Refactor game-related frame rate override to LayerHistory

Previously game-related frame rate overrides are maintained in Scheduler
only, which does not provide votes to the actual display refresh rate.
This causes an issue that these overrides will only be viable when they
are the divisors of the display refresh rate at the moment.

This change moves the game intervention and newly-added game default
frame rate overrides to LayerHistory, where overrides will be considered
in layer frame rate votes. Scheduler will get this information and
select the display frame rate accordingly

Bug: 286084594
Test: SurfaceFlinger unit test
      atest LayerHistoryTest
      atest FrameRateOverrideMappingsTest
      atest CtsGraphicsTestCases --test-filter "SetFrameRateTest*"
      atest CtsFrameRateOverrideTestCases
Change-Id: I9957af8e53fbdd44b8d70028572e6db8e779a1fe
diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
index cb9bfe9..82af61a 100644
--- a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
+++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "FrameRateOverrideMappings.h"
+#include <common/FlagManager.h>
 
 namespace android::scheduler {
 using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
@@ -30,7 +31,7 @@
         }
     }
 
-    {
+    if (!FlagManager::getInstance().game_default_frame_rate()) {
         const auto iter = mFrameRateOverridesFromGameManager.find(uid);
         if (iter != mFrameRateOverridesFromGameManager.end()) {
             return iter->second;
@@ -61,10 +62,13 @@
     for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) {
         overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
     }
-    for (const auto& [uid, frameRate] : mFrameRateOverridesFromGameManager) {
-        if (std::find_if(overrides.begin(), overrides.end(),
-                         [uid = uid](auto i) { return i.uid == uid; }) == overrides.end()) {
-            overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
+
+    if (!FlagManager::getInstance().game_default_frame_rate()) {
+        for (const auto& [uid, frameRate] : mFrameRateOverridesFromGameManager) {
+            if (std::find_if(overrides.begin(), overrides.end(),
+                             [uid = uid](auto i) { return i.uid == uid; }) == overrides.end()) {
+                overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
+            }
         }
     }
 
@@ -93,7 +97,9 @@
     if (!hasOverrides) return;
 
     dump(dumper, "setFrameRate"sv, mFrameRateOverridesByContent);
-    dump(dumper, "GameManager"sv, mFrameRateOverridesFromGameManager);
+    if (!FlagManager::getInstance().game_default_frame_rate()) {
+        dump(dumper, "GameManager"sv, mFrameRateOverridesFromGameManager);
+    }
     dump(dumper, "Backdoor"sv, mFrameRateOverridesFromBackdoor);
 }
 
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 9c00302..5ce883c 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -266,6 +266,7 @@
         if (isLayerActive(*info, threshold)) {
             // Set layer vote if set
             const auto frameRate = info->getSetFrameRateVote();
+
             const auto voteType = [&]() {
                 switch (frameRate.vote.type) {
                     case Layer::FrameRateCompatibility::Default:
@@ -283,12 +284,40 @@
                 }
             }();
 
-            if (frameRate.isValid()) {
-                const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote;
-                info->setLayerVote({type, frameRate.vote.rate, frameRate.vote.seamlessness,
-                                    frameRate.category});
+            if (FlagManager::getInstance().game_default_frame_rate()) {
+                // Determine the layer frame rate considering the following priorities:
+                // 1. Game mode intervention frame rate override
+                // 2. setFrameRate vote
+                // 3. Game default frame rate override
+
+                const auto& [gameModeFrameRateOverride, gameDefaultFrameRateOverride] =
+                        getGameFrameRateOverrideLocked(info->getOwnerUid());
+
+                const auto gameFrameRateOverrideVoteType =
+                        info->isVisible() ? LayerVoteType::ExplicitDefault : LayerVoteType::NoVote;
+
+                const auto setFrameRateVoteType =
+                        info->isVisible() ? voteType : LayerVoteType::NoVote;
+
+                if (gameModeFrameRateOverride.isValid()) {
+                    info->setLayerVote({gameFrameRateOverrideVoteType, gameModeFrameRateOverride});
+                } else if (frameRate.isValid()) {
+                    info->setLayerVote({setFrameRateVoteType, frameRate.vote.rate,
+                                        frameRate.vote.seamlessness, frameRate.category});
+                } else if (gameDefaultFrameRateOverride.isValid()) {
+                    info->setLayerVote(
+                            {gameFrameRateOverrideVoteType, gameDefaultFrameRateOverride});
+                } else {
+                    info->resetLayerVote();
+                }
             } else {
-                info->resetLayerVote();
+                if (frameRate.isValid()) {
+                    const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote;
+                    info->setLayerVote({type, frameRate.vote.rate, frameRate.vote.seamlessness,
+                                        frameRate.category});
+                } else {
+                    info->resetLayerVote();
+                }
             }
 
             it++;
@@ -347,4 +376,56 @@
     return isSmallDirty;
 }
 
+void LayerHistory::updateGameModeFrameRateOverride(FrameRateOverride frameRateOverride) {
+    const uid_t uid = frameRateOverride.uid;
+    std::lock_guard lock(mLock);
+    if (frameRateOverride.frameRateHz != 0.f) {
+        mGameFrameRateOverride[uid].first = Fps::fromValue(frameRateOverride.frameRateHz);
+    } else {
+        if (mGameFrameRateOverride[uid].second.getValue() == 0.f) {
+            mGameFrameRateOverride.erase(uid);
+        } else {
+            mGameFrameRateOverride[uid].first = Fps();
+        }
+    }
+}
+
+void LayerHistory::updateGameDefaultFrameRateOverride(FrameRateOverride frameRateOverride) {
+    const uid_t uid = frameRateOverride.uid;
+    std::lock_guard lock(mLock);
+    if (frameRateOverride.frameRateHz != 0.f) {
+        mGameFrameRateOverride[uid].second = Fps::fromValue(frameRateOverride.frameRateHz);
+    } else {
+        if (mGameFrameRateOverride[uid].first.getValue() == 0.f) {
+            mGameFrameRateOverride.erase(uid);
+        } else {
+            mGameFrameRateOverride[uid].second = Fps();
+        }
+    }
+}
+
+std::pair<Fps, Fps> LayerHistory::getGameFrameRateOverride(uid_t uid) const {
+    if (!FlagManager::getInstance().game_default_frame_rate()) {
+        return std::pair<Fps, Fps>();
+    }
+
+    std::lock_guard lock(mLock);
+
+    return getGameFrameRateOverrideLocked(uid);
+}
+
+std::pair<Fps, Fps> LayerHistory::getGameFrameRateOverrideLocked(uid_t uid) const {
+    if (!FlagManager::getInstance().game_default_frame_rate()) {
+        return std::pair<Fps, Fps>();
+    }
+
+    const auto it = mGameFrameRateOverride.find(uid);
+
+    if (it == mGameFrameRateOverride.end()) {
+        return std::pair<Fps, Fps>(Fps(), Fps());
+    }
+
+    return it->second;
+}
+
 } // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 5a9445b..930d06c 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -43,6 +43,7 @@
 
 class LayerHistory {
 public:
+    using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
     using LayerVoteType = RefreshRateSelector::LayerVoteType;
     static constexpr std::chrono::nanoseconds kMaxPeriodForHistory = 1s;
 
@@ -89,6 +90,15 @@
 
     bool isSmallDirtyArea(uint32_t dirtyArea, float threshold) const;
 
+    // Updates the frame rate override set by game mode intervention
+    void updateGameModeFrameRateOverride(FrameRateOverride frameRateOverride) EXCLUDES(mLock);
+
+    // Updates the frame rate override set by game default frame rate
+    void updateGameDefaultFrameRateOverride(FrameRateOverride frameRateOverride) EXCLUDES(mLock);
+
+    std::pair<Fps, Fps> getGameFrameRateOverride(uid_t uid) const EXCLUDES(mLock);
+    std::pair<Fps, Fps> getGameFrameRateOverrideLocked(uid_t uid) const REQUIRES(mLock);
+
 private:
     friend class LayerHistoryTest;
     friend class LayerHistoryIntegrationTest;
@@ -137,6 +147,13 @@
 
     // Whether a mode change is in progress or not
     std::atomic<bool> mModeChangePending = false;
+
+    // A list to look up the game frame rate overrides
+    // Each entry includes:
+    // 1. the uid of the app
+    // 2. a pair of game mode intervention frame frame and game default frame rate override
+    // set to 0.0 if there is no such override
+    std::map<uid_t, std::pair<Fps, Fps>> mGameFrameRateOverride GUARDED_BY(mLock);
 };
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 50bb83d..326e444 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -175,7 +175,8 @@
                             bool pendingModeChange, const LayerProps& props);
 
     // Sets an explicit layer vote. This usually comes directly from the application via
-    // ANativeWindow_setFrameRate API
+    // ANativeWindow_setFrameRate API. This is also used by Game Default Frame Rate and
+    // Game Mode Intervention Frame Rate.
     void setLayerVote(LayerVote vote) { mLayerVote = vote; }
 
     // Sets the default layer vote. This will be the layer vote after calling to resetLayerVote().
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index aa8d54d..6a85788 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -1226,12 +1226,27 @@
     mLayerHistory.setDisplayArea(displayArea);
 }
 
-void Scheduler::setGameModeRefreshRateForUid(FrameRateOverride frameRateOverride) {
+void Scheduler::setGameModeFrameRateForUid(FrameRateOverride frameRateOverride) {
     if (frameRateOverride.frameRateHz > 0.f && frameRateOverride.frameRateHz < 1.f) {
         return;
     }
 
-    mFrameRateOverrideMappings.setGameModeRefreshRateForUid(frameRateOverride);
+    if (FlagManager::getInstance().game_default_frame_rate()) {
+        // update the frame rate override mapping in LayerHistory
+        mLayerHistory.updateGameModeFrameRateOverride(frameRateOverride);
+    } else {
+        mFrameRateOverrideMappings.setGameModeRefreshRateForUid(frameRateOverride);
+    }
+}
+
+void Scheduler::setGameDefaultFrameRateForUid(FrameRateOverride frameRateOverride) {
+    if (!FlagManager::getInstance().game_default_frame_rate() ||
+        (frameRateOverride.frameRateHz > 0.f && frameRateOverride.frameRateHz < 1.f)) {
+        return;
+    }
+
+    // update the frame rate override mapping in LayerHistory
+    mLayerHistory.updateGameDefaultFrameRateOverride(frameRateOverride);
 }
 
 void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 454ef83..ce585c6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -293,7 +293,17 @@
     // FrameRateOverride.refreshRateHz == 0 means no preference.
     void setPreferredRefreshRateForUid(FrameRateOverride);
 
-    void setGameModeRefreshRateForUid(FrameRateOverride);
+    // Stores the frame rate override that a game should run at set by game interventions.
+    // FrameRateOverride.refreshRateHz == 0 means no preference.
+    void setGameModeFrameRateForUid(FrameRateOverride) EXCLUDES(mDisplayLock);
+
+    // Stores the frame rate override that a game should run rat set by default game frame rate.
+    // FrameRateOverride.refreshRateHz == 0 means no preference, game default game frame rate is not
+    // enabled.
+    //
+    // "ro.surface_flinger.game_default_frame_rate_override" sets the frame rate value,
+    // "persist.graphics.game_default_frame_rate.enabled" controls whether this feature is enabled.
+    void setGameDefaultFrameRateForUid(FrameRateOverride) EXCLUDES(mDisplayLock);
 
     void updateSmallAreaDetection(std::vector<std::pair<int32_t, float>>& uidThresholdMappings);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c4de02f..8f26d16 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -8440,17 +8440,25 @@
     return genericLayerMetadataKeyMap;
 }
 
-status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) {
+status_t SurfaceFlinger::setGameModeFrameRateOverride(uid_t uid, float frameRate) {
     PhysicalDisplayId displayId = [&]() {
         Mutex::Autolock lock(mStateLock);
         return getDefaultDisplayDeviceLocked()->getPhysicalId();
     }();
 
-    mScheduler->setGameModeRefreshRateForUid(FrameRateOverride{static_cast<uid_t>(uid), frameRate});
+    mScheduler->setGameModeFrameRateForUid(FrameRateOverride{static_cast<uid_t>(uid), frameRate});
     mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::setGameDefaultFrameRateOverride(uid_t uid, float frameRate) {
+    if (FlagManager::getInstance().game_default_frame_rate()) {
+        mScheduler->setGameDefaultFrameRateForUid(
+                FrameRateOverride{static_cast<uid_t>(uid), frameRate});
+    }
+    return NO_ERROR;
+}
+
 status_t SurfaceFlinger::updateSmallAreaDetection(
         std::vector<std::pair<int32_t, float>>& appIdThresholdMappings) {
     mScheduler->updateSmallAreaDetection(appIdThresholdMappings);
@@ -9800,13 +9808,25 @@
     return binder::Status::ok();
 }
 
-binder::Status SurfaceComposerAIDL::setOverrideFrameRate(int32_t uid, float frameRate) {
+binder::Status SurfaceComposerAIDL::setGameModeFrameRateOverride(int32_t uid, float frameRate) {
     status_t status;
     const int c_uid = IPCThreadState::self()->getCallingUid();
     if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) {
-        status = mFlinger->setOverrideFrameRate(uid, frameRate);
+        status = mFlinger->setGameModeFrameRateOverride(uid, frameRate);
     } else {
-        ALOGE("setOverrideFrameRate() permission denied for uid: %d", c_uid);
+        ALOGE("setGameModeFrameRateOverride() permission denied for uid: %d", c_uid);
+        status = PERMISSION_DENIED;
+    }
+    return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setGameDefaultFrameRateOverride(int32_t uid, float frameRate) {
+    status_t status;
+    const int c_uid = IPCThreadState::self()->getCallingUid();
+    if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) {
+        status = mFlinger->setGameDefaultFrameRateOverride(uid, frameRate);
+    } else {
+        ALOGE("setGameDefaultFrameRateOverride() permission denied for uid: %d", c_uid);
         status = PERMISSION_DENIED;
     }
     return binderStatusFromStatusT(status);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6909055..c16489e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -607,7 +607,9 @@
     status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
                                   const gui::FrameTimelineInfo& frameTimelineInfo);
 
-    status_t setOverrideFrameRate(uid_t uid, float frameRate);
+    status_t setGameModeFrameRateOverride(uid_t uid, float frameRate);
+
+    status_t setGameDefaultFrameRateOverride(uid_t uid, float frameRate);
 
     status_t updateSmallAreaDetection(std::vector<std::pair<int32_t, float>>& uidThresholdMappings);
 
@@ -1571,7 +1573,8 @@
     binder::Status getDisplayDecorationSupport(
             const sp<IBinder>& displayToken,
             std::optional<gui::DisplayDecorationSupport>* outSupport) override;
-    binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override;
+    binder::Status setGameModeFrameRateOverride(int32_t uid, float frameRate) override;
+    binder::Status setGameDefaultFrameRateOverride(int32_t uid, float frameRate) override;
     binder::Status enableRefreshRateOverlay(bool active) override;
     binder::Status setDebugFlash(int delay) override;
     binder::Status scheduleComposite() override;
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index adb4974..35f5e64 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -126,6 +126,7 @@
     DUMP_READ_ONLY_FLAG(enable_fro_dependent_features);
     DUMP_READ_ONLY_FLAG(display_protected);
     DUMP_READ_ONLY_FLAG(fp16_client_target);
+    DUMP_READ_ONLY_FLAG(game_default_frame_rate);
 
 #undef DUMP_READ_ONLY_FLAG
 #undef DUMP_SERVER_FLAG
@@ -201,6 +202,7 @@
 FLAG_MANAGER_READ_ONLY_FLAG(enable_fro_dependent_features, "")
 FLAG_MANAGER_READ_ONLY_FLAG(display_protected, "")
 FLAG_MANAGER_READ_ONLY_FLAG(fp16_client_target, "debug.sf.fp16_client_target")
+FLAG_MANAGER_READ_ONLY_FLAG(game_default_frame_rate, "")
 
 /// Trunk stable server flags ///
 FLAG_MANAGER_SERVER_FLAG(late_boot_misc2, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index cdab461..3a509f6 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -65,6 +65,7 @@
     bool enable_fro_dependent_features() const;
     bool display_protected() const;
     bool fp16_client_target() const;
+    bool game_default_frame_rate() const;
 
 protected:
     // overridden for unit tests
diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig
index fabd738..ea8dcbb 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -122,3 +122,11 @@
   bug: "236745178"
   is_fixed_read_only: true
 }
+
+flag {
+  name: "game_default_frame_rate"
+  namespace: "game"
+  description: "This flag guards the new behavior with the addition of Game Default Frame Rate feature."
+  bug: "286084594"
+  is_fixed_read_only: true
+}
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 5888a55..5449aeb 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -55,7 +55,6 @@
         "ReleaseBufferCallback_test.cpp",
         "ScreenCapture_test.cpp",
         "SetFrameRate_test.cpp",
-        "SetFrameRateOverride_test.cpp",
         "SetGeometry_test.cpp",
         "Stress_test.cpp",
         "TextureFiltering_test.cpp",
diff --git a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp
deleted file mode 100644
index e43ef95..0000000
--- a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/gui/ISurfaceComposer.h>
-#include <gtest/gtest.h>
-#include <gui/DisplayEventReceiver.h>
-#include <gui/SurfaceComposerClient.h>
-#include <sys/epoll.h>
-#include <algorithm>
-
-namespace android {
-namespace {
-using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
-using gui::ISurfaceComposer;
-
-class SetFrameRateOverrideTest : public ::testing::Test {
-protected:
-    void SetUp() override {
-        const ISurfaceComposer::VsyncSource vsyncSource =
-                ISurfaceComposer::VsyncSource::eVsyncSourceApp;
-        const EventRegistrationFlags eventRegistration = {
-                ISurfaceComposer::EventRegistration::frameRateOverride};
-
-        mDisplayEventReceiver =
-                std::make_unique<DisplayEventReceiver>(vsyncSource, eventRegistration);
-        EXPECT_EQ(NO_ERROR, mDisplayEventReceiver->initCheck());
-
-        mEpollFd = epoll_create1(EPOLL_CLOEXEC);
-        EXPECT_GT(mEpollFd, 1);
-
-        epoll_event event;
-        event.events = EPOLLIN;
-        EXPECT_EQ(0, epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mDisplayEventReceiver->getFd(), &event));
-    }
-
-    void TearDown() override { close(mEpollFd); }
-
-    void setFrameRateAndListenEvents(uid_t uid, float frameRate) {
-        status_t ret = SurfaceComposerClient::setOverrideFrameRate(uid, frameRate);
-        ASSERT_EQ(NO_ERROR, ret);
-
-        DisplayEventReceiver::Event event;
-        bool isOverrideFlushReceived = false;
-        mFrameRateOverrides.clear();
-
-        epoll_event epollEvent;
-        while (epoll_wait(mEpollFd, &epollEvent, 1, 1000) > 0) {
-            while (mDisplayEventReceiver->getEvents(&event, 1) > 0) {
-                if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE) {
-                    mFrameRateOverrides.emplace_back(event.frameRateOverride);
-                }
-                if (event.header.type ==
-                    DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH) {
-                    isOverrideFlushReceived = true;
-                }
-            }
-
-            if (isOverrideFlushReceived) break;
-        }
-    }
-
-    std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver;
-    std::vector<FrameRateOverride> mFrameRateOverrides;
-
-    int mEpollFd;
-};
-
-TEST_F(SetFrameRateOverrideTest, SetFrameRateOverrideCall) {
-    uid_t uid = getuid();
-    float frameRate = 30.0f;
-    setFrameRateAndListenEvents(uid, frameRate);
-    // check if the frame rate override we set exists
-    ASSERT_TRUE(std::find_if(mFrameRateOverrides.begin(), mFrameRateOverrides.end(),
-                             [uid = uid, frameRate = frameRate](auto i) {
-                                 return uid == i.uid && frameRate == i.frameRateHz;
-                             }) != mFrameRateOverrides.end());
-
-    // test removing frame rate override
-    frameRate = 0.0f;
-    setFrameRateAndListenEvents(uid, frameRate);
-    ASSERT_TRUE(std::find_if(mFrameRateOverrides.begin(), mFrameRateOverrides.end(),
-                             [uid = uid, frameRate = frameRate](auto i) {
-                                 return uid == i.uid && frameRate == i.frameRateHz;
-                             }) == mFrameRateOverrides.end());
-}
-} // namespace
-} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
index a581c7a..7c1d4b4 100644
--- a/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
@@ -17,6 +17,8 @@
 #undef LOG_TAG
 #define LOG_TAG "FrameRateOverrideMappingsTest"
 
+#include <com_android_graphics_surfaceflinger_flags.h>
+#include <common/test/FlagUtils.h>
 #include <gtest/gtest.h>
 #include <unordered_map>
 
@@ -34,6 +36,8 @@
 };
 
 namespace {
+using namespace com::android::graphics::surfaceflinger;
+
 TEST_F(FrameRateOverrideMappingsTest, testUpdateFrameRateOverridesByContent) {
     mFrameRateOverrideByContent.clear();
     mFrameRateOverrideByContent.emplace(0, 30.0_Hz);
@@ -59,6 +63,8 @@
 }
 
 TEST_F(FrameRateOverrideMappingsTest, testSetGameModeRefreshRateForUid) {
+    SET_FLAG_FOR_TEST(flags::game_default_frame_rate, false);
+
     mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f});
     mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f});
 
@@ -95,6 +101,7 @@
 }
 
 TEST_F(FrameRateOverrideMappingsTest, testGetFrameRateOverrideForUidMixed) {
+    SET_FLAG_FOR_TEST(flags::game_default_frame_rate, false);
     mFrameRateOverrideByContent.clear();
     mFrameRateOverrideByContent.emplace(0, 30.0_Hz);
     mFrameRateOverrideByContent.emplace(1, 60.0_Hz);
@@ -111,7 +118,6 @@
     ASSERT_EQ(allFrameRateOverrides,
               mFrameRateOverrideMappings.getAllFrameRateOverrides(
                       /*supportsFrameRateOverrideByContent*/ true));
-
     mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f});
     mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f});
     mFrameRateOverrideMappings.setGameModeRefreshRateForUid({4, 120.0f});
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index b88ef56..0ae3ca3 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -118,6 +118,9 @@
     auto createLayer(std::string name) {
         return sp<MockLayer>::make(mFlinger.flinger(), std::move(name));
     }
+    auto createLayer(std::string name, uint32_t uid) {
+        return sp<MockLayer>::make(mFlinger.flinger(), std::move(name), std::move(uid));
+    }
 
     void recordFramesAndExpect(const sp<MockLayer>& layer, nsecs_t& time, Fps frameRate,
                                Fps desiredRefreshRate, int numFrames) {
@@ -247,6 +250,105 @@
     }
 }
 
+TEST_F(LayerHistoryTest, gameFrameRateOverrideMapping) {
+    SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true);
+
+    history().updateGameDefaultFrameRateOverride(FrameRateOverride({0, 60.0f}));
+
+    auto overridePair = history().getGameFrameRateOverride(0);
+    EXPECT_EQ(0_Hz, overridePair.first);
+    EXPECT_EQ(60_Hz, overridePair.second);
+
+    history().updateGameModeFrameRateOverride(FrameRateOverride({0, 40.0f}));
+    history().updateGameModeFrameRateOverride(FrameRateOverride({1, 120.0f}));
+
+    overridePair = history().getGameFrameRateOverride(0);
+    EXPECT_EQ(40_Hz, overridePair.first);
+    EXPECT_EQ(60_Hz, overridePair.second);
+
+    overridePair = history().getGameFrameRateOverride(1);
+    EXPECT_EQ(120_Hz, overridePair.first);
+    EXPECT_EQ(0_Hz, overridePair.second);
+
+    history().updateGameDefaultFrameRateOverride(FrameRateOverride({0, 0.0f}));
+    history().updateGameModeFrameRateOverride(FrameRateOverride({1, 0.0f}));
+
+    overridePair = history().getGameFrameRateOverride(0);
+    EXPECT_EQ(40_Hz, overridePair.first);
+    EXPECT_EQ(0_Hz, overridePair.second);
+
+    overridePair = history().getGameFrameRateOverride(1);
+    EXPECT_EQ(0_Hz, overridePair.first);
+    EXPECT_EQ(0_Hz, overridePair.second);
+}
+
+TEST_F(LayerHistoryTest, oneLayerGameFrameRateOverride) {
+    SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true);
+
+    const uid_t uid = 0;
+    const Fps gameDefaultFrameRate = Fps::fromValue(30.0f);
+    const Fps gameModeFrameRate = Fps::fromValue(60.0f);
+    const auto layer = createLayer("GameFrameRateLayer", uid);
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+    EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    // update game default frame rate override
+    history().updateGameDefaultFrameRateOverride(
+            FrameRateOverride({uid, gameDefaultFrameRate.getValue()}));
+
+    nsecs_t time = systemTime();
+    LayerHistory::Summary summary;
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer->getSequence(), layer->getLayerProps(), time, time,
+                         LayerHistory::LayerUpdateType::Buffer);
+        time += gameDefaultFrameRate.getPeriodNsecs();
+
+        summary = summarizeLayerHistory(time);
+    }
+
+    ASSERT_EQ(1, summary.size());
+    ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
+    ASSERT_EQ(30.0_Hz, summary[0].desiredRefreshRate);
+
+    // test against setFrameRate vote
+    const Fps setFrameRate = Fps::fromValue(120.0f);
+    EXPECT_CALL(*layer, getFrameRateForLayerTree())
+            .WillRepeatedly(
+                    Return(Layer::FrameRate(setFrameRate, Layer::FrameRateCompatibility::Default)));
+
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer->getSequence(), layer->getLayerProps(), time, time,
+                         LayerHistory::LayerUpdateType::Buffer);
+        time += setFrameRate.getPeriodNsecs();
+
+        summary = summarizeLayerHistory(time);
+    }
+
+    ASSERT_EQ(1, summary.size());
+    ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
+    ASSERT_EQ(120.0_Hz, summary[0].desiredRefreshRate);
+
+    // update game mode frame rate override
+    history().updateGameModeFrameRateOverride(
+            FrameRateOverride({uid, gameModeFrameRate.getValue()}));
+
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer->getSequence(), layer->getLayerProps(), time, time,
+                         LayerHistory::LayerUpdateType::Buffer);
+        time += gameModeFrameRate.getPeriodNsecs();
+
+        summary = summarizeLayerHistory(time);
+    }
+
+    ASSERT_EQ(1, summary.size());
+    ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
+    ASSERT_EQ(60.0_Hz, summary[0].desiredRefreshRate);
+}
+
 TEST_F(LayerHistoryTest, oneInvisibleLayer) {
     const auto layer = createLayer();
     EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 3dfb649..4204aa0 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <gmock/gmock.h>
+#include <optional>
 
 namespace android::mock {
 
@@ -27,6 +28,13 @@
         EXPECT_CALL(*this, getDefaultFrameRateCompatibility())
                 .WillOnce(testing::Return(scheduler::FrameRateCompatibility::Default));
     }
+
+    MockLayer(SurfaceFlinger* flinger, std::string name, std::optional<uint32_t> uid)
+          : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {}, uid)) {
+        EXPECT_CALL(*this, getDefaultFrameRateCompatibility())
+                .WillOnce(testing::Return(scheduler::FrameRateCompatibility::Default));
+    }
+
     explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {}
 
     MOCK_CONST_METHOD0(getType, const char*());