Merge "SF: Mutable RefreshRateConfigs"
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 32110e9..9230e72 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -233,8 +233,8 @@
     mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
 }
 
-void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
-    mCurrentFps = refreshRate.getFps().getIntValue();
+void RefreshRateOverlay::changeRefreshRate(const Fps& fps) {
+    mCurrentFps = fps.getIntValue();
     auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
     mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
                       mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
@@ -258,8 +258,9 @@
 
 void RefreshRateOverlay::reset() {
     mBufferCache.clear();
-    mLowFps = mFlinger.mRefreshRateConfigs->getMinRefreshRate().getFps().getIntValue();
-    mHighFps = mFlinger.mRefreshRateConfigs->getMaxRefreshRate().getFps().getIntValue();
+    const auto range = mFlinger.mRefreshRateConfigs->getSupportedRefreshRateRange();
+    mLowFps = range.min.getIntValue();
+    mHighFps = range.max.getIntValue();
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index 4ca1337..c16cfa0 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -23,7 +23,7 @@
 #include <ui/Size.h>
 #include <utils/StrongPointer.h>
 
-#include "Scheduler/RefreshRateConfigs.h"
+#include "Fps.h"
 
 namespace android {
 
@@ -34,14 +34,12 @@
 class Layer;
 class SurfaceFlinger;
 
-using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
-
 class RefreshRateOverlay {
 public:
     RefreshRateOverlay(SurfaceFlinger&, bool showSpinner);
 
     void setViewport(ui::Size);
-    void changeRefreshRate(const RefreshRate&);
+    void changeRefreshRate(const Fps&);
     void onInvalidate();
     void reset();
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index c42c812..975754b 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -39,6 +39,26 @@
                               toString(layer.seamlessness).c_str(),
                               to_string(layer.desiredRefreshRate).c_str());
 }
+
+std::vector<Fps> constructKnownFrameRates(
+        const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
+    std::vector<Fps> knownFrameRates = {Fps(24.0f), Fps(30.0f), Fps(45.0f), Fps(60.0f), Fps(72.0f)};
+    knownFrameRates.reserve(knownFrameRates.size() + configs.size());
+
+    // Add all supported refresh rates to the set
+    for (const auto& config : configs) {
+        const auto refreshRate = Fps::fromPeriodNsecs(config->getVsyncPeriod());
+        knownFrameRates.emplace_back(refreshRate);
+    }
+
+    // Sort and remove duplicates
+    std::sort(knownFrameRates.begin(), knownFrameRates.end(), Fps::comparesLess);
+    knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(),
+                                      Fps::EqualsWithMargin()),
+                          knownFrameRates.end());
+    return knownFrameRates;
+}
+
 } // namespace
 
 using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
@@ -154,9 +174,9 @@
     float score;
 };
 
-const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
-        const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
-        GlobalSignals* outSignalsConsidered) const {
+RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector<LayerRequirement>& layers,
+                                                   const GlobalSignals& globalSignals,
+                                                   GlobalSignals* outSignalsConsidered) const {
     ATRACE_CALL();
     ALOGV("getBestRefreshRate %zu layers", layers.size());
 
@@ -469,9 +489,20 @@
     return bestRefreshRate;
 }
 
-const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
+std::optional<Fps> RefreshRateConfigs::onKernelTimerChanged(
+        std::optional<HwcConfigIndexType> desiredActiveConfigId, bool timerExpired) const {
     std::lock_guard lock(mLock);
-    return getMinRefreshRateByPolicyLocked();
+
+    const auto& current = desiredActiveConfigId ? *mRefreshRates.at(*desiredActiveConfigId)
+                                                : *mCurrentRefreshRate;
+    const auto& min = *mMinSupportedRefreshRate;
+
+    if (current != min) {
+        const auto& refreshRate = timerExpired ? min : current;
+        return refreshRate.getFps();
+    }
+
+    return {};
 }
 
 const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
@@ -487,7 +518,7 @@
     return *mPrimaryRefreshRates.front();
 }
 
-const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
+RefreshRate RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
     std::lock_guard lock(mLock);
     return getMaxRefreshRateByPolicyLocked();
 }
@@ -506,12 +537,12 @@
     return *mPrimaryRefreshRates.back();
 }
 
-const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
+RefreshRate RefreshRateConfigs::getCurrentRefreshRate() const {
     std::lock_guard lock(mLock);
     return *mCurrentRefreshRate;
 }
 
-const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicy() const {
+RefreshRate RefreshRateConfigs::getCurrentRefreshRateByPolicy() const {
     std::lock_guard lock(mLock);
     return getCurrentRefreshRateByPolicyLocked();
 }
@@ -533,16 +564,23 @@
         const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
         HwcConfigIndexType currentConfigId)
       : mKnownFrameRates(constructKnownFrameRates(configs)) {
+    updateDisplayConfigs(configs, currentConfigId);
+}
+
+void RefreshRateConfigs::updateDisplayConfigs(
+        const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
+        HwcConfigIndexType currentConfigId) {
+    std::lock_guard lock(mLock);
     LOG_ALWAYS_FATAL_IF(configs.empty());
     LOG_ALWAYS_FATAL_IF(currentConfigId.value() < 0);
     LOG_ALWAYS_FATAL_IF(currentConfigId.value() >= configs.size());
 
+    mRefreshRates.clear();
     for (auto configId = HwcConfigIndexType(0); configId.value() < configs.size(); configId++) {
         const auto& config = configs.at(static_cast<size_t>(configId.value()));
+        const auto fps = Fps::fromPeriodNsecs(config->getVsyncPeriod());
         mRefreshRates.emplace(configId,
-                              std::make_unique<RefreshRate>(configId, config,
-                                                            Fps::fromPeriodNsecs(
-                                                                    config->getVsyncPeriod()),
+                              std::make_unique<RefreshRate>(configId, config, fps,
                                                             RefreshRate::ConstructorTag(0)));
         if (configId == currentConfigId) {
             mCurrentRefreshRate = mRefreshRates.at(configId).get();
@@ -550,7 +588,7 @@
     }
 
     std::vector<const RefreshRate*> sortedConfigs;
-    getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs);
+    getSortedRefreshRateListLocked([](const RefreshRate&) { return true; }, &sortedConfigs);
     mDisplayManagerPolicy.defaultConfig = currentConfigId;
     mMinSupportedRefreshRate = sortedConfigs.front();
     mMaxSupportedRefreshRate = sortedConfigs.back();
@@ -570,7 +608,7 @@
     constructAvailableRefreshRates();
 }
 
-bool RefreshRateConfigs::isPolicyValid(const Policy& policy) {
+bool RefreshRateConfigs::isPolicyValidLocked(const Policy& policy) const {
     // defaultConfig must be a valid config, and within the given refresh rate range.
     auto iter = mRefreshRates.find(policy.defaultConfig);
     if (iter == mRefreshRates.end()) {
@@ -588,7 +626,7 @@
 
 status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
     std::lock_guard lock(mLock);
-    if (!isPolicyValid(policy)) {
+    if (!isPolicyValidLocked(policy)) {
         ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str());
         return BAD_VALUE;
     }
@@ -603,7 +641,7 @@
 
 status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& policy) {
     std::lock_guard lock(mLock);
-    if (policy && !isPolicyValid(*policy)) {
+    if (policy && !isPolicyValidLocked(*policy)) {
         return BAD_VALUE;
     }
     Policy previousPolicy = *getCurrentPolicyLocked();
@@ -639,14 +677,14 @@
     return false;
 }
 
-void RefreshRateConfigs::getSortedRefreshRateList(
+void RefreshRateConfigs::getSortedRefreshRateListLocked(
         const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
         std::vector<const RefreshRate*>* outRefreshRates) {
     outRefreshRates->clear();
     outRefreshRates->reserve(mRefreshRates.size());
     for (const auto& [type, refreshRate] : mRefreshRates) {
         if (shouldAddRefreshRate(*refreshRate)) {
-            ALOGV("getSortedRefreshRateList: config %d added to list policy",
+            ALOGV("getSortedRefreshRateListLocked: config %d added to list policy",
                   refreshRate->configId.value());
             outRefreshRates->push_back(refreshRate.get());
         }
@@ -672,8 +710,9 @@
     ALOGV("constructAvailableRefreshRates: %s ", policy->toString().c_str());
 
     auto filterRefreshRates = [&](Fps min, Fps max, const char* listName,
-                                  std::vector<const RefreshRate*>* outRefreshRates) {
-        getSortedRefreshRateList(
+                                  std::vector<const RefreshRate*>*
+                                          outRefreshRates) REQUIRES(mLock) {
+        getSortedRefreshRateListLocked(
                 [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
                     const auto& hwcConfig = refreshRate.hwcConfig;
 
@@ -706,25 +745,6 @@
                        &mAppRequestRefreshRates);
 }
 
-std::vector<Fps> RefreshRateConfigs::constructKnownFrameRates(
-        const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
-    std::vector<Fps> knownFrameRates = {Fps(24.0f), Fps(30.0f), Fps(45.0f), Fps(60.0f), Fps(72.0f)};
-    knownFrameRates.reserve(knownFrameRates.size() + configs.size());
-
-    // Add all supported refresh rates to the set
-    for (const auto& config : configs) {
-        const auto refreshRate = Fps::fromPeriodNsecs(config->getVsyncPeriod());
-        knownFrameRates.emplace_back(refreshRate);
-    }
-
-    // Sort and remove duplicates
-    std::sort(knownFrameRates.begin(), knownFrameRates.end(), Fps::comparesLess);
-    knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(),
-                                      Fps::EqualsWithMargin()),
-                          knownFrameRates.end());
-    return knownFrameRates;
-}
-
 Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const {
     if (frameRate.lessThanOrEqualWithMargin(*mKnownFrameRates.begin())) {
         return *mKnownFrameRates.begin();
@@ -744,7 +764,7 @@
 
 RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction() const {
     std::lock_guard lock(mLock);
-    const auto& deviceMin = getMinRefreshRate();
+    const auto& deviceMin = *mMinSupportedRefreshRate;
     const auto& minByPolicy = getMinRefreshRateByPolicyLocked();
     const auto& maxByPolicy = getMaxRefreshRateByPolicyLocked();
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index e4bbf7f..4b99145 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -68,8 +68,6 @@
                     std::shared_ptr<const HWC2::Display::Config> config, Fps fps, ConstructorTag)
               : configId(configId), hwcConfig(config), fps(std::move(fps)) {}
 
-        RefreshRate(const RefreshRate&) = delete;
-
         HwcConfigIndexType getConfigId() const { return configId; }
         nsecs_t getVsyncPeriod() const { return hwcConfig->getVsyncPeriod(); }
         int32_t getConfigGroup() const { return hwcConfig->getConfigGroup(); }
@@ -111,27 +109,26 @@
     using AllRefreshRatesMapType =
             std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;
 
+    struct FpsRange {
+        Fps min{0.0f};
+        Fps max{std::numeric_limits<float>::max()};
+
+        bool operator==(const FpsRange& other) const {
+            return min.equalsWithMargin(other.min) && max.equalsWithMargin(other.max);
+        }
+
+        bool operator!=(const FpsRange& other) const { return !(*this == other); }
+
+        std::string toString() const {
+            return base::StringPrintf("[%s %s]", to_string(min).c_str(), to_string(max).c_str());
+        }
+    };
+
     struct Policy {
     private:
         static constexpr int kAllowGroupSwitchingDefault = false;
 
     public:
-        struct Range {
-            Fps min{0.0f};
-            Fps max{std::numeric_limits<float>::max()};
-
-            bool operator==(const Range& other) const {
-                return min.equalsWithMargin(other.min) && max.equalsWithMargin(other.max);
-            }
-
-            bool operator!=(const Range& other) const { return !(*this == other); }
-
-            std::string toString() const {
-                return base::StringPrintf("[%s %s]", to_string(min).c_str(),
-                                          to_string(max).c_str());
-            }
-        };
-
         // The default config, used to ensure we only initiate display config switches within the
         // same config group as defaultConfigId's group.
         HwcConfigIndexType defaultConfig;
@@ -140,29 +137,29 @@
         // The primary refresh rate range represents display manager's general guidance on the
         // display configs we'll consider when switching refresh rates. Unless we get an explicit
         // signal from an app, we should stay within this range.
-        Range primaryRange;
+        FpsRange primaryRange;
         // The app request refresh rate range allows us to consider more display configs when
         // switching refresh rates. Although we should generally stay within the primary range,
         // specific considerations, such as layer frame rate settings specified via the
         // setFrameRate() api, may cause us to go outside the primary range. We never go outside the
         // app request range. The app request range will be greater than or equal to the primary
         // refresh rate range, never smaller.
-        Range appRequestRange;
+        FpsRange appRequestRange;
 
         Policy() = default;
 
-        Policy(HwcConfigIndexType defaultConfig, const Range& range)
+        Policy(HwcConfigIndexType defaultConfig, const FpsRange& range)
               : Policy(defaultConfig, kAllowGroupSwitchingDefault, range, range) {}
 
-        Policy(HwcConfigIndexType defaultConfig, bool allowGroupSwitching, const Range& range)
+        Policy(HwcConfigIndexType defaultConfig, bool allowGroupSwitching, const FpsRange& range)
               : Policy(defaultConfig, allowGroupSwitching, range, range) {}
 
-        Policy(HwcConfigIndexType defaultConfig, const Range& primaryRange,
-               const Range& appRequestRange)
+        Policy(HwcConfigIndexType defaultConfig, const FpsRange& primaryRange,
+               const FpsRange& appRequestRange)
               : Policy(defaultConfig, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {}
 
         Policy(HwcConfigIndexType defaultConfig, bool allowGroupSwitching,
-               const Range& primaryRange, const Range& appRequestRange)
+               const FpsRange& primaryRange, const FpsRange& appRequestRange)
               : defaultConfig(defaultConfig),
                 allowGroupSwitching(allowGroupSwitching),
                 primaryRange(primaryRange),
@@ -258,35 +255,35 @@
     //   globalSignals - global state of touch and idle
     //   outSignalsConsidered - An output param that tells the caller whether the refresh rate was
     //                          chosen based on touch boost and/or idle timer.
-    const RefreshRate& getBestRefreshRate(const std::vector<LayerRequirement>& layers,
-                                          const GlobalSignals& globalSignals,
-                                          GlobalSignals* outSignalsConsidered = nullptr) const
+    RefreshRate getBestRefreshRate(const std::vector<LayerRequirement>& layers,
+                                   const GlobalSignals& globalSignals,
+                                   GlobalSignals* outSignalsConsidered = nullptr) const
             EXCLUDES(mLock);
 
-    // Returns the lowest refresh rate supported by the device. This won't change at runtime.
-    const RefreshRate& getMinRefreshRate() const { return *mMinSupportedRefreshRate; }
+    FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) {
+        std::lock_guard lock(mLock);
+        return {mMinSupportedRefreshRate->getFps(), mMaxSupportedRefreshRate->getFps()};
+    }
 
-    // Returns the lowest refresh rate according to the current policy. May change at runtime. Only
-    // uses the primary range, not the app request range.
-    const RefreshRate& getMinRefreshRateByPolicy() const EXCLUDES(mLock);
-
-    // Returns the highest refresh rate supported by the device. This won't change at runtime.
-    const RefreshRate& getMaxRefreshRate() const { return *mMaxSupportedRefreshRate; }
+    std::optional<Fps> onKernelTimerChanged(std::optional<HwcConfigIndexType> desiredActiveConfigId,
+                                            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.
-    const RefreshRate& getMaxRefreshRateByPolicy() const EXCLUDES(mLock);
+    RefreshRate getMaxRefreshRateByPolicy() const EXCLUDES(mLock);
 
     // Returns the current refresh rate
-    const RefreshRate& getCurrentRefreshRate() const EXCLUDES(mLock);
+    RefreshRate getCurrentRefreshRate() const EXCLUDES(mLock);
 
     // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by
     // the policy.
-    const RefreshRate& getCurrentRefreshRateByPolicy() const;
+    RefreshRate getCurrentRefreshRateByPolicy() const;
 
-    // Returns the refresh rate that corresponds to a HwcConfigIndexType. This won't change at
+    // Returns the refresh rate that corresponds to a HwcConfigIndexType. This may change at
     // runtime.
-    const RefreshRate& getRefreshRateFromConfigId(HwcConfigIndexType configId) const {
+    // TODO(b/159590486) An invalid config id may be given here if the dipslay configs have changed.
+    RefreshRate getRefreshRateFromConfigId(HwcConfigIndexType configId) const EXCLUDES(mLock) {
+        std::lock_guard lock(mLock);
         return *mRefreshRates.at(configId);
     };
 
@@ -302,10 +299,17 @@
     RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
                        HwcConfigIndexType currentConfigId);
 
+    void updateDisplayConfigs(
+            const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
+            HwcConfigIndexType currentConfig) EXCLUDES(mLock);
+
     // Returns whether switching configs (refresh rate or resolution) is possible.
     // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the configs only
     // differ in resolution.
-    bool canSwitch() const { return mRefreshRates.size() > 1; }
+    bool canSwitch() const EXCLUDES(mLock) {
+        std::lock_guard lock(mLock);
+        return mRefreshRates.size() > 1;
+    }
 
     // Class to enumerate options around toggling the kernel timer on and off. We have an option
     // for no change to avoid extra calls to kernel.
@@ -334,12 +338,10 @@
     friend class RefreshRateConfigsTest;
 
     void constructAvailableRefreshRates() REQUIRES(mLock);
-    static std::vector<Fps> constructKnownFrameRates(
-            const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs);
 
-    void getSortedRefreshRateList(
+    void getSortedRefreshRateListLocked(
             const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
-            std::vector<const RefreshRate*>* outRefreshRates);
+            std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock);
 
     // Returns the refresh rate with the highest score in the collection specified from begin
     // to end. If there are more than one with the same highest refresh rate, the first one is
@@ -364,7 +366,7 @@
     const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock);
 
     const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
-    bool isPolicyValid(const Policy& policy);
+    bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
 
     // Return the display refresh rate divider to match the layer
     // frame rate, or 0 if the display refresh rate is not a multiple of the
@@ -376,9 +378,9 @@
     float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&,
                                     bool isSeamlessSwitch) const REQUIRES(mLock);
 
-    // The list of refresh rates, indexed by display config ID. This must not change after this
+    // The list of refresh rates, indexed by display config ID. This may change after this
     // object is initialized.
-    AllRefreshRatesMapType mRefreshRates;
+    AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock);
 
     // The list of refresh rates in the primary range of the current policy, ordered by vsyncPeriod
     // (the first element is the lowest refresh rate).
@@ -398,9 +400,9 @@
     std::optional<Policy> mOverridePolicy GUARDED_BY(mLock);
 
     // The min and max refresh rates supported by the device.
-    // This will not change at runtime.
-    const RefreshRate* mMinSupportedRefreshRate;
-    const RefreshRate* mMaxSupportedRefreshRate;
+    // This may change at runtime.
+    const RefreshRate* mMinSupportedRefreshRate GUARDED_BY(mLock);
+    const RefreshRate* mMaxSupportedRefreshRate GUARDED_BY(mLock);
 
     mutable std::mutex mLock;
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 18c899b..49e3903 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -612,7 +612,7 @@
         mFeatures.contentRequirements = summary;
 
         newConfigId = calculateRefreshRateConfigIndexType(&consideredSignals);
-        auto& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+        auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
         frameRateOverridesChanged =
                 updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps());
 
@@ -629,7 +629,7 @@
         }
     }
     if (frameRateChanged) {
-        auto& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+        auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
         mSchedulerCallback.changeRefreshRate(newRefreshRate,
                                              consideredSignals.idle ? ConfigEvent::None
                                                                     : ConfigEvent::Changed);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 59b3824..2e00ca8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -995,7 +995,7 @@
 
 void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
     ATRACE_CALL();
-    auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId);
+    auto refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId);
     ALOGV("setDesiredActiveConfig(%s)", refreshRate.getName().c_str());
 
     std::lock_guard<std::mutex> lock(mActiveConfigLock);
@@ -1030,7 +1030,7 @@
     }
 
     if (mRefreshRateOverlay) {
-        mRefreshRateOverlay->changeRefreshRate(refreshRate);
+        mRefreshRateOverlay->changeRefreshRate(refreshRate.getFps());
     }
 }
 
@@ -1076,14 +1076,14 @@
         return;
     }
 
-    auto& oldRefreshRate =
+    auto oldRefreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig());
 
     std::lock_guard<std::mutex> lock(mActiveConfigLock);
     mRefreshRateConfigs->setCurrentConfigId(mUpcomingActiveConfig.configId);
     display->setActiveConfig(mUpcomingActiveConfig.configId);
 
-    auto& refreshRate =
+    auto refreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId);
     mRefreshRateStats->setRefreshRate(refreshRate.getFps());
 
@@ -1126,7 +1126,7 @@
         return;
     }
 
-    auto& refreshRate =
+    auto refreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig->configId);
     ALOGV("performSetActiveConfig changing active config to %d(%s)",
           refreshRate.getConfigId().value(), refreshRate.getName().c_str());
@@ -2620,6 +2620,9 @@
             if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
                 const auto displayId = currentState.physical->id;
                 const auto configs = getHwComposer().getConfigs(displayId);
+                const auto currentConfig =
+                        HwcConfigIndexType(getHwComposer().getActiveConfigIndex(displayId));
+                mRefreshRateConfigs->updateDisplayConfigs(configs, currentConfig);
                 mVsyncConfiguration->reset();
                 updatePhaseConfiguration(mRefreshRateConfigs->getCurrentRefreshRate());
                 if (mRefreshRateOverlay) {
@@ -5411,16 +5414,16 @@
     // mRefreshRateConfigs->getCurrentRefreshRate()
     static_cast<void>(schedule([=] {
         const auto desiredActiveConfig = getDesiredActiveConfig();
-        const auto& current = desiredActiveConfig
-                ? mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig->configId)
-                : mRefreshRateConfigs->getCurrentRefreshRate();
-        const auto& min = mRefreshRateConfigs->getMinRefreshRate();
+        const std::optional<HwcConfigIndexType> desiredConfigId = desiredActiveConfig
+                ? std::make_optional(desiredActiveConfig->configId)
+                : std::nullopt;
 
-        if (current != min) {
-            const bool timerExpired = mKernelIdleTimerEnabled && expired;
-
+        const bool timerExpired = mKernelIdleTimerEnabled && expired;
+        const auto newRefreshRate =
+                mRefreshRateConfigs->onKernelTimerChanged(desiredConfigId, timerExpired);
+        if (newRefreshRate) {
             if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) {
-                mRefreshRateOverlay->changeRefreshRate(timerExpired ? min : current);
+                mRefreshRateOverlay->changeRefreshRate(*newRefreshRate);
             }
             mEventQueue->invalidate();
         }
@@ -6070,7 +6073,7 @@
     toggleKernelIdleTimer();
 
     auto configId = mScheduler->getPreferredConfigId();
-    auto& preferredRefreshRate = configId
+    auto preferredRefreshRate = configId
             ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
             // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind.
             : mRefreshRateConfigs->getRefreshRateFromConfigId(currentPolicy.defaultConfig);
@@ -6376,7 +6379,8 @@
                 mRefreshRateOverlay->setViewport(display->getSize());
             }
 
-            mRefreshRateOverlay->changeRefreshRate(mRefreshRateConfigs->getCurrentRefreshRate());
+            mRefreshRateOverlay->changeRefreshRate(
+                    mRefreshRateConfigs->getCurrentRefreshRate().getFps());
         }
     }));
 }
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 45f0ee6..0813968 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -56,6 +56,21 @@
         return refreshRateConfigs.mKnownFrameRates;
     }
 
+    RefreshRate getMinRefreshRateByPolicy(const RefreshRateConfigs& refreshRateConfigs) {
+        std::lock_guard lock(refreshRateConfigs.mLock);
+        return refreshRateConfigs.getMinRefreshRateByPolicyLocked();
+    }
+
+    RefreshRate getMinSupportedRefreshRate(const RefreshRateConfigs& refreshRateConfigs) {
+        std::lock_guard lock(refreshRateConfigs.mLock);
+        return *refreshRateConfigs.mMinSupportedRefreshRate;
+    }
+
+    RefreshRate getMaxSupportedRefreshRate(const RefreshRateConfigs& refreshRateConfigs) {
+        std::lock_guard lock(refreshRateConfigs.mLock);
+        return *refreshRateConfigs.mMaxSupportedRefreshRate;
+    }
+
     // Test config IDs
     static inline const HwcConfigIndexType HWC_CONFIG_ID_60 = HwcConfigIndexType(0);
     static inline const HwcConfigIndexType HWC_CONFIG_ID_90 = HwcConfigIndexType(1);
@@ -209,13 +224,13 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    const auto& minRate = refreshRateConfigs->getMinRefreshRate();
-    const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
+    const auto& minRate = getMinSupportedRefreshRate(*refreshRateConfigs);
+    const auto& performanceRate = getMaxSupportedRefreshRate(*refreshRateConfigs);
 
     ASSERT_EQ(mExpected60Config, minRate);
     ASSERT_EQ(mExpected90Config, performanceRate);
 
-    const auto& minRateByPolicy = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& minRateByPolicy = getMinRefreshRateByPolicy(*refreshRateConfigs);
     const auto& performanceRateByPolicy = refreshRateConfigs->getMaxRefreshRateByPolicy();
     ASSERT_EQ(minRateByPolicy, minRate);
     ASSERT_EQ(performanceRateByPolicy, performanceRate);
@@ -226,9 +241,9 @@
             std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    const auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
-    const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
-    const auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& minRate = getMinRefreshRateByPolicy(*refreshRateConfigs);
+    const auto& performanceRate = getMaxSupportedRefreshRate(*refreshRateConfigs);
+    const auto& minRate60 = getMinRefreshRateByPolicy(*refreshRateConfigs);
     const auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
 
     ASSERT_EQ(mExpected60Config, minRate);
@@ -239,7 +254,7 @@
               0);
     refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
 
-    const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& minRate90 = getMinRefreshRateByPolicy(*refreshRateConfigs);
     const auto& performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
 
     ASSERT_EQ(mExpected90DifferentGroupConfig, performanceRate);
@@ -252,9 +267,9 @@
             std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentResolutions,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    const auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
-    const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
-    const auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& minRate = getMinRefreshRateByPolicy(*refreshRateConfigs);
+    const auto& performanceRate = getMaxSupportedRefreshRate(*refreshRateConfigs);
+    const auto& minRate60 = getMinRefreshRateByPolicy(*refreshRateConfigs);
     const auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
 
     ASSERT_EQ(mExpected60Config, minRate);
@@ -265,7 +280,7 @@
               0);
     refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
 
-    const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& minRate90 = getMinRefreshRateByPolicy(*refreshRateConfigs);
     const auto& performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
 
     ASSERT_EQ(mExpected90DifferentResolutionConfig, performanceRate);
@@ -278,8 +293,8 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
-    auto& performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    auto minRate = getMinRefreshRateByPolicy(*refreshRateConfigs);
+    auto performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy();
 
     ASSERT_EQ(mExpected60Config, minRate);
     ASSERT_EQ(mExpected90Config, performanceRate);
@@ -287,8 +302,8 @@
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
               0);
 
-    auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
-    auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    auto minRate60 = getMinRefreshRateByPolicy(*refreshRateConfigs);
+    auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
     ASSERT_EQ(mExpected60Config, minRate60);
     ASSERT_EQ(mExpected60Config, performanceRate60);
 }
@@ -298,20 +313,20 @@
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
     {
-        auto& current = refreshRateConfigs->getCurrentRefreshRate();
+        auto current = refreshRateConfigs->getCurrentRefreshRate();
         EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_60);
     }
 
     refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
     {
-        auto& current = refreshRateConfigs->getCurrentRefreshRate();
+        auto current = refreshRateConfigs->getCurrentRefreshRate();
         EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
     }
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(90), Fps(90)}}),
               0);
     {
-        auto& current = refreshRateConfigs->getCurrentRefreshRate();
+        auto current = refreshRateConfigs->getCurrentRefreshRate();
         EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
     }
 }