SF: Flow DisplayModeRequest through mode set FSM

The motivation is to:
    - Avoid redundant state that can cause data races if stale.
    - Consolidate control flow for resolution and refresh rate changes.
    - Clarify the desired/pending/active states of the per-display FSM.

The notable changes are:

Consume the desired DisplayModeRequestOpt via either SF::dropModeRequest
or DisplayDevice::initiateModeChange.

Pull the details of SF::finalizeDisplayModeChange into DisplayDevice::
finalizeModeChange, which now returns whether there was NoModeChange,
a ResolutionChange, or a RefreshRateChange. Consume the pending request.

Now that DisplayDevice does not retain the desired DisplayModeRequest,
applyActiveMode as soon as finalizeDisplayModeChange ends, rather than
at a later point in the commit, when initiateDisplayModeChanges checks
whether the active and desired modes are the same.

Now that applyActiveMode happens in finalizeDisplayModeChange, remove
the special case when there is a displayToUpdateImmediately.

Bug: 305813445
Bug: 255635711
Bug: 241285876
Test: ALOGV of mode setting for inner/outer displays
Test: InitiateModeChangeTest, DisplayModeSwitchingTest
Change-Id: I688b0c922747a80e881965a1dc243d11ba2c7438
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index ac390cb..3090477 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -19,6 +19,7 @@
 #include <memory>
 #include <string>
 #include <unordered_map>
+#include <variant>
 
 #include <android-base/thread_annotations.h>
 #include <android/native_window.h>
@@ -194,12 +195,11 @@
     using DisplayModeRequestOpt = ftl::Optional<display::DisplayModeRequest>;
 
     DisplayModeRequestOpt getDesiredMode() const EXCLUDES(mDesiredModeLock);
-    void clearDesiredMode() EXCLUDES(mDesiredModeLock);
+    DisplayModeRequestOpt takeDesiredMode() EXCLUDES(mDesiredModeLock);
 
-    DisplayModeRequestOpt getPendingMode() const REQUIRES(kMainThreadContext) {
-        return mPendingModeOpt;
+    bool isModeSetPending() const REQUIRES(kMainThreadContext) {
+        return mPendingModeOpt.has_value();
     }
-    bool isModeSetPending() const REQUIRES(kMainThreadContext) { return mIsModeSetPending; }
 
     scheduler::FrameRateMode getActiveMode() const REQUIRES(kMainThreadContext) {
         return mRefreshRateSelector->getActiveMode();
@@ -211,8 +211,25 @@
                             hal::VsyncPeriodChangeTimeline& outTimeline)
             REQUIRES(kMainThreadContext);
 
-    void finalizeModeChange(DisplayModeId, Fps vsyncRate, Fps renderFps)
-            REQUIRES(kMainThreadContext);
+    struct NoModeChange {
+        const char* reason;
+    };
+
+    struct ResolutionChange {
+        display::DisplayModeRequest activeMode;
+    };
+
+    struct RefreshRateChange {
+        display::DisplayModeRequest activeMode;
+    };
+
+    using ModeChange = std::variant<NoModeChange, ResolutionChange, RefreshRateChange>;
+
+    // Clears the pending DisplayModeRequest, and returns the ModeChange that occurred. If it was a
+    // RefreshRateChange, the pending mode becomes the active mode. If it was a ResolutionChange,
+    // the caller is responsible for resizing the framebuffer to match the active resolution by
+    // recreating the DisplayDevice.
+    ModeChange finalizeModeChange() REQUIRES(kMainThreadContext);
 
     scheduler::RefreshRateSelector& refreshRateSelector() const { return *mRefreshRateSelector; }
 
@@ -249,6 +266,8 @@
     void dump(utils::Dumper&) const;
 
 private:
+    friend class TestableSurfaceFlinger;
+
     template <size_t N>
     inline std::string concatId(const char (&str)[N]) const {
         return std::string(ftl::Concat(str, ' ', getId().value).str());
@@ -299,12 +318,15 @@
     // This parameter is only used for hdr/sdr ratio overlay
     float mHdrSdrRatio = 1.0f;
 
+    // A DisplayModeRequest flows through three states: desired, pending, and active. Requests
+    // within a frame are merged into a single desired request. Unless cleared, the request is
+    // relayed to HWC on the next frame, and becomes pending. The mode becomes active once HWC
+    // signals the present fence to confirm the mode set.
     mutable std::mutex mDesiredModeLock;
     DisplayModeRequestOpt mDesiredModeOpt GUARDED_BY(mDesiredModeLock);
     TracedOrdinal<bool> mHasDesiredModeTrace GUARDED_BY(mDesiredModeLock);
 
     DisplayModeRequestOpt mPendingModeOpt GUARDED_BY(kMainThreadContext);
-    bool mIsModeSetPending GUARDED_BY(kMainThreadContext) = false;
 };
 
 struct DisplayDeviceState {