SF: Refactor setter for DM and override policy

Move DisplayDevice::setRefreshRatePolicy to RefreshRateConfigs, and
merge the repetitive set{DisplayManager,Override}Policy helpers.

Improve type correctness of the parameters and return value.

Bug: 241285191
Test: libsurfaceflinger_unittest
Change-Id: Iee87316e5702282b828bc3f28cd7d30041030ed5
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a57af09..c63d57f 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -216,7 +216,6 @@
               to_string(getId()).c_str());
         return BAD_VALUE;
     }
-    mNumModeSwitchesInPolicy++;
     mUpcomingActiveMode = info;
     ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.mode->getFps().getIntValue());
     return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), info.mode->getHwcId(),
@@ -498,27 +497,6 @@
     mDesiredActiveModeChanged = false;
 }
 
-status_t DisplayDevice::setRefreshRatePolicy(
-        const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
-    const auto oldPolicy = mRefreshRateConfigs->getCurrentPolicy();
-    const status_t setPolicyResult = overridePolicy
-            ? mRefreshRateConfigs->setOverridePolicy(policy)
-            : mRefreshRateConfigs->setDisplayManagerPolicy(*policy);
-
-    if (setPolicyResult == OK) {
-        const int numModeChanges = mNumModeSwitchesInPolicy.exchange(0);
-
-        ALOGI("Display %s policy changed\n"
-              "Previous: {%s}\n"
-              "Current:  {%s}\n"
-              "%d mode changes were performed under the previous policy",
-              to_string(getId()).c_str(), oldPolicy.toString().c_str(),
-              policy ? policy->toString().c_str() : "null", numModeChanges);
-    }
-
-    return setPolicyResult;
-}
-
 std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
 
 }  // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e155ca1..06a812b 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -236,10 +236,6 @@
 
     nsecs_t getVsyncPeriodFromHWC() const;
 
-    status_t setRefreshRatePolicy(
-            const std::optional<scheduler::RefreshRateConfigs::Policy>& policy,
-            bool overridePolicy);
-
     // release HWC resources (if any) for removable displays
     void disconnect();
 
@@ -287,8 +283,6 @@
     TracedOrdinal<bool> mDesiredActiveModeChanged
             GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
     ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext);
-
-    std::atomic_int mNumModeSwitchesInPolicy = 0;
 };
 
 struct DisplayDeviceState {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index fb50588..c10b817 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -28,6 +28,7 @@
 #include <android-base/stringprintf.h>
 #include <ftl/enum.h>
 #include <ftl/fake_guard.h>
+#include <ftl/match.h>
 #include <utils/Trace.h>
 
 #include "../SurfaceFlingerProperties.h"
@@ -117,6 +118,20 @@
     return false;
 }
 
+std::string toString(const RefreshRateConfigs::PolicyVariant& policy) {
+    using namespace std::string_literals;
+
+    return ftl::match(
+            policy,
+            [](const RefreshRateConfigs::DisplayManagerPolicy& policy) {
+                return "DisplayManagerPolicy"s + policy.toString();
+            },
+            [](const RefreshRateConfigs::OverridePolicy& policy) {
+                return "OverridePolicy"s + policy.toString();
+            },
+            [](RefreshRateConfigs::NoOverridePolicy) { return "NoOverridePolicy"s; });
+}
+
 } // namespace
 
 struct RefreshRateConfigs::RefreshRateScoreComparator {
@@ -874,35 +889,60 @@
             policy.appRequestRange.max >= policy.primaryRange.max;
 }
 
-status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
-    std::lock_guard lock(mLock);
-    if (!isPolicyValidLocked(policy)) {
-        ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str());
-        return BAD_VALUE;
-    }
-    mGetRankedRefreshRatesCache.reset();
-    Policy previousPolicy = *getCurrentPolicyLocked();
-    mDisplayManagerPolicy = policy;
-    if (*getCurrentPolicyLocked() == previousPolicy) {
-        return CURRENT_POLICY_UNCHANGED;
-    }
-    constructAvailableRefreshRates();
-    return NO_ERROR;
-}
+auto RefreshRateConfigs::setPolicy(const PolicyVariant& policy) -> SetPolicyResult {
+    Policy oldPolicy;
+    {
+        std::lock_guard lock(mLock);
+        oldPolicy = *getCurrentPolicyLocked();
 
-status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& policy) {
-    std::lock_guard lock(mLock);
-    if (policy && !isPolicyValidLocked(*policy)) {
-        return BAD_VALUE;
+        const bool valid = ftl::match(
+                policy,
+                [this](const auto& policy) {
+                    ftl::FakeGuard guard(mLock);
+                    if (!isPolicyValidLocked(policy)) {
+                        ALOGE("Invalid policy: %s", policy.toString().c_str());
+                        return false;
+                    }
+
+                    using T = std::decay_t<decltype(policy)>;
+
+                    if constexpr (std::is_same_v<T, DisplayManagerPolicy>) {
+                        mDisplayManagerPolicy = policy;
+                    } else {
+                        static_assert(std::is_same_v<T, OverridePolicy>);
+                        mOverridePolicy = policy;
+                    }
+                    return true;
+                },
+                [this](NoOverridePolicy) {
+                    ftl::FakeGuard guard(mLock);
+                    mOverridePolicy.reset();
+                    return true;
+                });
+
+        if (!valid) {
+            return SetPolicyResult::Invalid;
+        }
+
+        mGetRankedRefreshRatesCache.reset();
+
+        if (*getCurrentPolicyLocked() == oldPolicy) {
+            return SetPolicyResult::Unchanged;
+        }
+        constructAvailableRefreshRates();
     }
-    mGetRankedRefreshRatesCache.reset();
-    Policy previousPolicy = *getCurrentPolicyLocked();
-    mOverridePolicy = policy;
-    if (*getCurrentPolicyLocked() == previousPolicy) {
-        return CURRENT_POLICY_UNCHANGED;
-    }
-    constructAvailableRefreshRates();
-    return NO_ERROR;
+
+    const auto displayId = getActiveMode().getPhysicalDisplayId();
+    const unsigned numModeChanges = std::exchange(mNumModeSwitchesInPolicy, 0u);
+
+    ALOGI("Display %s policy changed\n"
+          "Previous: %s\n"
+          "Current:  %s\n"
+          "%u mode changes were performed under the previous policy",
+          to_string(displayId).c_str(), oldPolicy.toString().c_str(), toString(policy).c_str(),
+          numModeChanges);
+
+    return SetPolicyResult::Changed;
 }
 
 const RefreshRateConfigs::Policy* RefreshRateConfigs::getCurrentPolicyLocked() const {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 8b89104..2c2e34a 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -21,6 +21,7 @@
 #include <optional>
 #include <type_traits>
 #include <utility>
+#include <variant>
 
 #include <gui/DisplayEventReceiver.h>
 
@@ -67,8 +68,7 @@
     static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION =
             std::chrono::nanoseconds(800us).count();
 
-    struct Policy {
-    private:
+    class Policy {
         static constexpr int kAllowGroupSwitchingDefault = false;
 
     public:
@@ -118,23 +118,28 @@
         std::string toString() const;
     };
 
-    // Return code set*Policy() to indicate the current policy is unchanged.
-    static constexpr int CURRENT_POLICY_UNCHANGED = 1;
+    enum class SetPolicyResult { Invalid, Unchanged, Changed };
 
     // We maintain the display manager policy and the override policy separately. The override
     // policy is used by CTS tests to get a consistent device state for testing. While the override
     // policy is set, it takes precedence over the display manager policy. Once the override policy
     // is cleared, we revert to using the display manager policy.
+    struct DisplayManagerPolicy : Policy {
+        using Policy::Policy;
+    };
 
-    // Sets the display manager policy to choose refresh rates. The return value will be:
-    //   - A negative value if the policy is invalid or another error occurred.
-    //   - NO_ERROR if the policy was successfully updated, and the current policy is different from
-    //     what it was before the call.
-    //   - CURRENT_POLICY_UNCHANGED if the policy was successfully updated, but the current policy
-    //     is the same as it was before the call.
-    status_t setDisplayManagerPolicy(const Policy& policy) EXCLUDES(mLock);
-    // Sets the override policy. See setDisplayManagerPolicy() for the meaning of the return value.
-    status_t setOverridePolicy(const std::optional<Policy>& policy) EXCLUDES(mLock);
+    struct OverridePolicy : Policy {
+        using Policy::Policy;
+    };
+
+    struct NoOverridePolicy {};
+
+    using PolicyVariant = std::variant<DisplayManagerPolicy, OverridePolicy, NoOverridePolicy>;
+
+    SetPolicyResult setPolicy(const PolicyVariant&) EXCLUDES(mLock) REQUIRES(kMainThreadContext);
+
+    void onModeChangeInitiated() REQUIRES(kMainThreadContext) { mNumModeSwitchesInPolicy++; }
+
     // Gets the current policy, which will be the override policy if active, and the display manager
     // policy otherwise.
     Policy getCurrentPolicy() const EXCLUDES(mLock);
@@ -418,6 +423,8 @@
     Policy mDisplayManagerPolicy GUARDED_BY(mLock);
     std::optional<Policy> mOverridePolicy GUARDED_BY(mLock);
 
+    unsigned mNumModeSwitchesInPolicy GUARDED_BY(kMainThreadContext) = 0;
+
     mutable std::mutex mLock;
 
     // A sorted list of known frame rates that a Heuristic layer will choose
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ddd0f4c..1e39f62 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1105,7 +1105,7 @@
     }
 
     const char* const whence = __func__;
-    auto future = mScheduler->schedule([=]() -> status_t {
+    auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(kMainThreadContext) -> status_t {
         const auto displayOpt =
                 FTL_FAKE_GUARD(mStateLock,
                                ftl::find_if(mPhysicalDisplays,
@@ -1130,13 +1130,16 @@
         }
 
         const Fps fps = *fpsOpt;
+
         // Keep the old switching type.
         const bool allowGroupSwitching =
                 display->refreshRateConfigs().getCurrentPolicy().allowGroupSwitching;
-        const scheduler::RefreshRateConfigs::Policy policy{modeId, allowGroupSwitching, {fps, fps}};
-        constexpr bool kOverridePolicy = false;
 
-        return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy);
+        const scheduler::RefreshRateConfigs::DisplayManagerPolicy policy{modeId,
+                                                                         allowGroupSwitching,
+                                                                         {fps, fps}};
+
+        return setDesiredDisplayModeSpecsInternal(display, policy);
     });
 
     return future.get();
@@ -1273,6 +1276,8 @@
             ALOGW("initiateModeChange failed: %d", status);
             continue;
         }
+
+        display->refreshRateConfigs().onModeChangeInitiated();
         mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
 
         if (outTimeline.refreshRequired) {
@@ -5866,7 +5871,7 @@
             case 1036: {
                 if (data.readInt32() > 0) { // turn on
                     return mScheduler
-                            ->schedule([this] {
+                            ->schedule([this]() FTL_FAKE_GUARD(kMainThreadContext) {
                                 const auto display =
                                         FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
 
@@ -5876,24 +5881,21 @@
                                 // defaultMode. The defaultMode doesn't matter for the override
                                 // policy though, since we set allowGroupSwitching to true, so it's
                                 // not a problem.
-                                scheduler::RefreshRateConfigs::Policy overridePolicy;
+                                scheduler::RefreshRateConfigs::OverridePolicy overridePolicy;
                                 overridePolicy.defaultMode = display->refreshRateConfigs()
                                                                      .getDisplayManagerPolicy()
                                                                      .defaultMode;
                                 overridePolicy.allowGroupSwitching = true;
-                                constexpr bool kOverridePolicy = true;
-                                return setDesiredDisplayModeSpecsInternal(display, overridePolicy,
-                                                                          kOverridePolicy);
+                                return setDesiredDisplayModeSpecsInternal(display, overridePolicy);
                             })
                             .get();
                 } else { // turn off
                     return mScheduler
-                            ->schedule([this] {
+                            ->schedule([this]() FTL_FAKE_GUARD(kMainThreadContext) {
                                 const auto display =
                                         FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
-                                constexpr bool kOverridePolicy = true;
-                                return setDesiredDisplayModeSpecsInternal(display, {},
-                                                                          kOverridePolicy);
+                                return setDesiredDisplayModeSpecsInternal(
+                                        display, scheduler::RefreshRateConfigs::NoOverridePolicy{});
                             })
                             .get();
                 }
@@ -6732,7 +6734,7 @@
 
 status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal(
         const sp<DisplayDevice>& display,
-        const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
+        const scheduler::RefreshRateConfigs::PolicyVariant& policy) {
     Mutex::Autolock lock(mStateLock);
 
     if (mDebugDisplayModeSetByBackdoor) {
@@ -6740,23 +6742,24 @@
         return NO_ERROR;
     }
 
-    const status_t setPolicyResult = display->setRefreshRatePolicy(policy, overridePolicy);
-    if (setPolicyResult < 0) {
-        return BAD_VALUE;
-    }
-    if (setPolicyResult == scheduler::RefreshRateConfigs::CURRENT_POLICY_UNCHANGED) {
-        return NO_ERROR;
+    auto& configs = display->refreshRateConfigs();
+    using SetPolicyResult = scheduler::RefreshRateConfigs::SetPolicyResult;
+
+    switch (configs.setPolicy(policy)) {
+        case SetPolicyResult::Invalid:
+            return BAD_VALUE;
+        case SetPolicyResult::Unchanged:
+            return NO_ERROR;
+        case SetPolicyResult::Changed:
+            break;
     }
 
-    const scheduler::RefreshRateConfigs::Policy currentPolicy =
-            display->refreshRateConfigs().getCurrentPolicy();
-
+    const scheduler::RefreshRateConfigs::Policy currentPolicy = configs.getCurrentPolicy();
     ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str());
 
     // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
     // be depending in this callback.
-    const auto activeModePtr = display->refreshRateConfigs().getActiveModePtr();
-    if (isDisplayActiveLocked(display)) {
+    if (const auto activeModePtr = configs.getActiveModePtr(); isDisplayActiveLocked(display)) {
         mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeModePtr);
         toggleKernelIdleTimer();
     } else {
@@ -6776,7 +6779,7 @@
     ALOGV("Switching to Scheduler preferred mode %d (%s)", preferredModeId.value(),
           to_string(preferredMode->getFps()).c_str());
 
-    if (!display->refreshRateConfigs().isModeAllowed(preferredModeId)) {
+    if (!configs.isModeAllowed(preferredModeId)) {
         ALOGE("%s: Preferred mode %d is disallowed", __func__, preferredModeId.value());
         return INVALID_OPERATION;
     }
@@ -6795,7 +6798,7 @@
         return BAD_VALUE;
     }
 
-    auto future = mScheduler->schedule([=]() -> status_t {
+    auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(kMainThreadContext) -> status_t {
         const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken));
         if (!display) {
             ALOGE("Attempt to set desired display modes for invalid display token %p",
@@ -6805,16 +6808,15 @@
             ALOGW("Attempt to set desired display modes for virtual display");
             return INVALID_OPERATION;
         } else {
-            using Policy = scheduler::RefreshRateConfigs::Policy;
+            using Policy = scheduler::RefreshRateConfigs::DisplayManagerPolicy;
             const Policy policy{DisplayModeId(defaultMode),
                                 allowGroupSwitching,
                                 {Fps::fromValue(primaryRefreshRateMin),
                                  Fps::fromValue(primaryRefreshRateMax)},
                                 {Fps::fromValue(appRequestRefreshRateMin),
                                  Fps::fromValue(appRequestRefreshRateMax)}};
-            constexpr bool kOverridePolicy = false;
 
-            return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy);
+            return setDesiredDisplayModeSpecsInternal(display, policy);
         }
     });
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 378c9f0..adde907 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -680,11 +680,9 @@
                                                           DisplayModeId defaultModeId) const
             REQUIRES(mStateLock);
 
-    // Sets the desired display mode specs.
-    status_t setDesiredDisplayModeSpecsInternal(
-            const sp<DisplayDevice>& display,
-            const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
-            EXCLUDES(mStateLock);
+    status_t setDesiredDisplayModeSpecsInternal(const sp<DisplayDevice>&,
+                                                const scheduler::RefreshRateConfigs::PolicyVariant&)
+            EXCLUDES(mStateLock) REQUIRES(kMainThreadContext);
 
     void commitTransactions() EXCLUDES(mStateLock) REQUIRES(kMainThreadContext);
     void commitTransactionsLocked(uint32_t transactionFlags)
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 66bac44..a949440 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -362,11 +362,24 @@
                                                              mFdp.ConsumeFloatingPoint<float>()),
                                                      globalSignals);
 
-    refreshRateConfigs.setDisplayManagerPolicy(
-            {modeId,
-             {Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
-              Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())}});
-    FTL_FAKE_GUARD(kMainThreadContext, refreshRateConfigs.setActiveModeId(modeId));
+    {
+        ftl::FakeGuard guard(kMainThreadContext);
+
+        refreshRateConfigs.setPolicy(
+                RefreshRateConfigs::
+                        DisplayManagerPolicy{modeId,
+                                             {Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+                                              Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())}});
+        refreshRateConfigs.setPolicy(
+                RefreshRateConfigs::OverridePolicy{modeId,
+                                                   {Fps::fromValue(
+                                                            mFdp.ConsumeFloatingPoint<float>()),
+                                                    Fps::fromValue(
+                                                            mFdp.ConsumeFloatingPoint<float>())}});
+        refreshRateConfigs.setPolicy(RefreshRateConfigs::NoOverridePolicy{});
+
+        refreshRateConfigs.setActiveModeId(modeId);
+    }
 
     RefreshRateConfigs::isFractionalPairOrMultiple(Fps::fromValue(
                                                            mFdp.ConsumeFloatingPoint<float>()),
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index a706c4b..00f1b08 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -34,6 +34,7 @@
 
 namespace hal = android::hardware::graphics::composer::hal;
 
+using SetPolicyResult = RefreshRateConfigs::SetPolicyResult;
 using LayerVoteType = RefreshRateConfigs::LayerVoteType;
 using LayerRequirement = RefreshRateConfigs::LayerRequirement;
 
@@ -93,6 +94,15 @@
                                       GlobalSignals signals = {}) const {
         return getRankedRefreshRatesAndSignals(layers, signals).first.front().displayModePtr;
     }
+
+    SetPolicyResult setPolicy(const PolicyVariant& policy) {
+        ftl::FakeGuard guard(kMainThreadContext);
+        return RefreshRateConfigs::setPolicy(policy);
+    }
+
+    SetPolicyResult setDisplayManagerPolicy(const DisplayManagerPolicy& policy) {
+        return setPolicy(policy);
+    }
 };
 
 class RefreshRateConfigsTest : public testing::Test {
@@ -178,9 +188,33 @@
 }
 
 TEST_F(RefreshRateConfigsTest, invalidPolicy) {
-    RefreshRateConfigs configs(kModes_60, kModeId60);
-    EXPECT_LT(configs.setDisplayManagerPolicy({DisplayModeId(10), {60_Hz, 60_Hz}}), 0);
-    EXPECT_LT(configs.setDisplayManagerPolicy({kModeId60, {20_Hz, 40_Hz}}), 0);
+    TestableRefreshRateConfigs configs(kModes_60, kModeId60);
+
+    EXPECT_EQ(SetPolicyResult::Invalid,
+              configs.setDisplayManagerPolicy({DisplayModeId(10), {60_Hz, 60_Hz}}));
+    EXPECT_EQ(SetPolicyResult::Invalid,
+              configs.setDisplayManagerPolicy({kModeId60, {20_Hz, 40_Hz}}));
+}
+
+TEST_F(RefreshRateConfigsTest, unchangedPolicy) {
+    TestableRefreshRateConfigs configs(kModes_60_90, kModeId60);
+
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}));
+
+    EXPECT_EQ(SetPolicyResult::Unchanged,
+              configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}));
+
+    // Override to the same policy.
+    EXPECT_EQ(SetPolicyResult::Unchanged,
+              configs.setPolicy(RefreshRateConfigs::OverridePolicy{kModeId90, {60_Hz, 90_Hz}}));
+
+    // Clear override to restore DisplayManagerPolicy.
+    EXPECT_EQ(SetPolicyResult::Unchanged,
+              configs.setPolicy(RefreshRateConfigs::NoOverridePolicy{}));
+
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId90, {30_Hz, 90_Hz}}));
 }
 
 TEST_F(RefreshRateConfigsTest, twoModes_storesFullRefreshRateMap) {
@@ -211,7 +245,8 @@
     EXPECT_EQ(kMode60, minRate60);
     EXPECT_EQ(kMode60, performanceRate60);
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}));
     configs.setActiveModeId(kModeId90);
 
     const auto minRate90 = configs.getMinRefreshRateByPolicy();
@@ -234,7 +269,8 @@
     EXPECT_EQ(kMode60, minRate60);
     EXPECT_EQ(kMode60, performanceRate60);
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}));
     configs.setActiveModeId(kModeId90);
 
     const auto minRate90 = configs.getMinRefreshRateByPolicy();
@@ -254,7 +290,8 @@
     EXPECT_EQ(kMode60, minRate);
     EXPECT_EQ(kMode90, performanceRate);
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}));
 
     const auto minRate60 = configs.getMinRefreshRateByPolicy();
     const auto performanceRate60 = configs.getMaxRefreshRateByPolicy();
@@ -276,7 +313,8 @@
         EXPECT_EQ(mode.getId(), kModeId90);
     }
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}));
     {
         const auto& mode = configs.getActiveMode();
         EXPECT_EQ(mode.getId(), kModeId90);
@@ -291,15 +329,17 @@
         // range.
         EXPECT_EQ(kMode90, configs.getBestRefreshRate());
 
-        EXPECT_EQ(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), NO_ERROR);
+        EXPECT_EQ(SetPolicyResult::Changed,
+                  configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}));
         EXPECT_EQ(kMode60, configs.getBestRefreshRate());
     }
     {
         // We select max even when this will cause a non-seamless switch.
         TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
         constexpr bool kAllowGroupSwitching = true;
-        EXPECT_EQ(configs.setDisplayManagerPolicy({kModeId90, kAllowGroupSwitching, {0_Hz, 90_Hz}}),
-                  NO_ERROR);
+        EXPECT_EQ(SetPolicyResult::Changed,
+                  configs.setDisplayManagerPolicy(
+                          {kModeId90, kAllowGroupSwitching, {0_Hz, 90_Hz}}));
         EXPECT_EQ(kMode90_G1, configs.getBestRefreshRate());
     }
 }
@@ -340,7 +380,8 @@
     EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
 
     lr.name = "";
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}));
 
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
@@ -364,7 +405,8 @@
     lr.desiredRefreshRate = 24_Hz;
     EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}));
 
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
@@ -388,7 +430,8 @@
     lr.desiredRefreshRate = 24_Hz;
     EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 120_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 120_Hz}}));
     lr.vote = LayerVoteType::Min;
     EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers));
 
@@ -1039,7 +1082,8 @@
                                                                    RefreshRateRanking{kMode60},
                                                                    RefreshRateRanking{kMode90}};
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}));
 
     const std::vector<RefreshRateRanking>& refreshRates =
             configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt,
@@ -1062,7 +1106,8 @@
                                                                    RefreshRateRanking{kMode60},
                                                                    RefreshRateRanking{kMode30}};
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 90_Hz}, {30_Hz, 90_Hz}}));
 
     const std::vector<RefreshRateRanking>& refreshRates =
             configs.getRefreshRatesByPolicy(/*anchorGroupOpt*/ std::nullopt,
@@ -1300,9 +1345,10 @@
 
 TEST_F(RefreshRateConfigsTest,
        getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresTouchFlag) {
-    RefreshRateConfigs configs(kModes_60_90, kModeId90);
+    TestableRefreshRateConfigs configs(kModes_60_90, kModeId90);
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}));
 
     std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
@@ -1323,7 +1369,8 @@
        getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresIdleFlag) {
     TestableRefreshRateConfigs configs(kModes_60_90, kModeId60);
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 90_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 90_Hz}}));
 
     std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& lr = layers[0];
@@ -1472,7 +1519,8 @@
        getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitFocusedLayers) {
     TestableRefreshRateConfigs configs(kModes_60_90, kModeId90);
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}));
 
     const auto [mode, signals] = configs.getRankedRefreshRatesAndSignals({}, {});
     EXPECT_EQ(mode.front().displayModePtr, kMode90);
@@ -1546,10 +1594,10 @@
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayer) {
     TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
 
-    RefreshRateConfigs::Policy policy;
+    RefreshRateConfigs::DisplayManagerPolicy policy;
     policy.defaultMode = configs.getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
-    EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+    EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
 
     std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& layer = layers[0];
@@ -1564,10 +1612,10 @@
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamless) {
     TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
 
-    RefreshRateConfigs::Policy policy;
+    RefreshRateConfigs::DisplayManagerPolicy policy;
     policy.defaultMode = configs.getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
-    EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+    EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
 
     // Verify that we won't change the group if seamless switch is required.
     std::vector<LayerRequirement> layers = {{.weight = 1.f}};
@@ -1583,10 +1631,10 @@
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) {
     TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
 
-    RefreshRateConfigs::Policy policy;
+    RefreshRateConfigs::DisplayManagerPolicy policy;
     policy.defaultMode = configs.getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
-    EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+    EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
 
     configs.setActiveModeId(kModeId90);
 
@@ -1604,10 +1652,10 @@
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerDefaultSeamlessness) {
     TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
 
-    RefreshRateConfigs::Policy policy;
+    RefreshRateConfigs::DisplayManagerPolicy policy;
     policy.defaultMode = configs.getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
-    EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+    EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
 
     configs.setActiveModeId(kModeId90);
 
@@ -1628,10 +1676,10 @@
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) {
     TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
 
-    RefreshRateConfigs::Policy policy;
+    RefreshRateConfigs::DisplayManagerPolicy policy;
     policy.defaultMode = configs.getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
-    EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+    EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
 
     configs.setActiveModeId(kModeId90);
 
@@ -1657,10 +1705,10 @@
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeamed) {
     TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
 
-    RefreshRateConfigs::Policy policy;
+    RefreshRateConfigs::DisplayManagerPolicy policy;
     policy.defaultMode = configs.getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
-    EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+    EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
 
     configs.setActiveModeId(kModeId90);
 
@@ -1690,10 +1738,10 @@
 TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSeamed) {
     TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId60);
 
-    RefreshRateConfigs::Policy policy;
+    RefreshRateConfigs::DisplayManagerPolicy policy;
     policy.defaultMode = configs.getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
-    EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+    EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
 
     configs.setActiveModeId(kModeId90);
 
@@ -1721,10 +1769,10 @@
     TestableRefreshRateConfigs configs(kModes_30_60, kModeId60);
 
     // Allow group switching.
-    RefreshRateConfigs::Policy policy;
+    RefreshRateConfigs::DisplayManagerPolicy policy;
     policy.defaultMode = configs.getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
-    EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+    EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
 
     std::vector<LayerRequirement> layers = {{.weight = 1.f}};
     auto& layer = layers[0];
@@ -1744,10 +1792,10 @@
     TestableRefreshRateConfigs configs(kModes_25_30_50_60, kModeId60);
 
     // Allow group switching.
-    RefreshRateConfigs::Policy policy;
+    RefreshRateConfigs::DisplayManagerPolicy policy;
     policy.defaultMode = configs.getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
-    EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+    EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
 
     std::vector<LayerRequirement> layers = {{.name = "60Hz ExplicitDefault",
                                              .vote = LayerVoteType::ExplicitDefault,
@@ -1776,10 +1824,10 @@
     TestableRefreshRateConfigs configs(kModes_60_90_G1, kModeId90);
 
     // Allow group switching.
-    RefreshRateConfigs::Policy policy;
+    RefreshRateConfigs::DisplayManagerPolicy policy;
     policy.defaultMode = configs.getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
-    EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0);
+    EXPECT_EQ(SetPolicyResult::Changed, configs.setPolicy(policy));
 
     std::vector<LayerRequirement> layers = {
             {.name = "Min", .vote = LayerVoteType::Min, .weight = 1.f, .focused = true}};
@@ -1807,7 +1855,8 @@
         return configs.getBestRefreshRate(layers, {.touch = args.touch})->getId();
     };
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 60_Hz}, {30_Hz, 90_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 60_Hz}, {30_Hz, 90_Hz}}));
 
     EXPECT_EQ(kModeId60, configs.getBestRefreshRate()->getId());
     EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz));
@@ -1831,7 +1880,8 @@
     EXPECT_EQ(kModeId60,
               getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.touch = true}));
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 60_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}, {60_Hz, 60_Hz}}));
 
     EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz));
     EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Min, 90_Hz));
@@ -1860,7 +1910,8 @@
         return refreshRate.front().displayModePtr->getId();
     };
 
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0);
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}));
 
     // Idle should be lower priority than touch boost.
     {
@@ -2156,43 +2207,50 @@
 TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) {
     using KernelIdleTimerAction = RefreshRateConfigs::KernelIdleTimerAction;
 
-    RefreshRateConfigs configs(kModes_60_90, kModeId90);
+    TestableRefreshRateConfigs configs(kModes_60_90, kModeId90);
 
-    // SetPolicy(60, 90), current 90Hz => TurnOn.
+    // setPolicy(60, 90), current 90Hz => TurnOn.
     EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction());
 
-    // SetPolicy(60, 90), current 60Hz => TurnOn.
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}}), 0);
+    // setPolicy(60, 90), current 60Hz => TurnOn.
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}}));
     EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction());
 
-    // SetPolicy(60, 60), current 60Hz => TurnOff
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0);
+    // setPolicy(60, 60), current 60Hz => TurnOff
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}));
     EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction());
 
-    // SetPolicy(90, 90), current 90Hz => TurnOff.
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0);
+    // setPolicy(90, 90), current 90Hz => TurnOff.
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}));
     EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction());
 }
 
 TEST_F(RefreshRateConfigsTest, testKernelIdleTimerActionFor120Hz) {
     using KernelIdleTimerAction = RefreshRateConfigs::KernelIdleTimerAction;
 
-    RefreshRateConfigs configs(kModes_60_120, kModeId120);
+    TestableRefreshRateConfigs configs(kModes_60_120, kModeId120);
 
-    // SetPolicy(0, 60), current 60Hz => TurnOn.
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 60_Hz}}), 0);
+    // setPolicy(0, 60), current 60Hz => TurnOn.
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 60_Hz}}));
     EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction());
 
-    // SetPolicy(60, 60), current 60Hz => TurnOff.
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0);
+    // setPolicy(60, 60), current 60Hz => TurnOff.
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}));
     EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction());
 
-    // SetPolicy(60, 120), current 60Hz => TurnOn.
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 120_Hz}}), 0);
+    // setPolicy(60, 120), current 60Hz => TurnOn.
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 120_Hz}}));
     EXPECT_EQ(KernelIdleTimerAction::TurnOn, configs.getIdleTimerAction());
 
-    // SetPolicy(120, 120), current 120Hz => TurnOff.
-    EXPECT_GE(configs.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}}), 0);
+    // setPolicy(120, 120), current 120Hz => TurnOff.
+    EXPECT_EQ(SetPolicyResult::Changed,
+              configs.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}}));
     EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction());
 }