SF: Mutable RefreshRateConfigs

Modify the list of supported refresh rates in RefreshRateConfigs
on hotplug. In order to support this the RefreshRateConfigs class
is refactored to not return references to its internal members,
but instead return copies. This won't be expensive because
the RefreshRate objects which are returned are small.

Bug: 159590486
Test: 1. boot w/o display
      2. connect a display which supports multiple refresh rates
      3. request a mode switch from an app
      4. verify that the switch works
Test: atest libsurfaceflinger_unittest
Test: toggle refresh rate overlay
      adb shell service call SurfaceFlinger 1034 i32 1/0
Change-Id: I1588bf004a0a0319a94931adbfb822836703849a
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 6a511a8..a0f91c2 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 */));
@@ -256,8 +256,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 35b382e..4677db9 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -38,6 +38,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;
@@ -153,9 +173,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());
 
@@ -468,9 +488,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 {
@@ -486,7 +517,7 @@
     return *mPrimaryRefreshRates.front();
 }
 
-const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
+RefreshRate RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
     std::lock_guard lock(mLock);
     return getMaxRefreshRateByPolicyLocked();
 }
@@ -505,12 +536,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();
 }
@@ -532,16 +563,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();
@@ -549,7 +587,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();
@@ -566,7 +604,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()) {
@@ -584,7 +622,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;
     }
@@ -599,7 +637,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();
@@ -635,14 +673,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());
         }
@@ -668,8 +706,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;
 
@@ -702,25 +741,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();
@@ -740,7 +760,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 6967f69..abffb0b 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());
@@ -2621,6 +2621,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) {
@@ -5406,16 +5409,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();
         }
@@ -6065,7 +6068,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);
@@ -6371,7 +6374,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);
     }
 }