Merge "SF: Requery display modes if the active mode is not supported" into sc-dev
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index cf6bc68..f532e50 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -91,6 +91,12 @@
         int32_t dpiX = -1;
         int32_t dpiY = -1;
         int32_t configGroup = -1;
+
+        friend std::ostream& operator<<(std::ostream& os, const HWCDisplayMode& mode) {
+            return os << "id=" << mode.hwcId << " res=" << mode.width << "x" << mode.height
+                      << " vsyncPeriod=" << mode.vsyncPeriod << " dpi=" << mode.dpiX << "x"
+                      << mode.dpiY << " group=" << mode.configGroup;
+        }
     };
 
     virtual ~HWComposer();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 424c511..ad91183 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -104,6 +104,7 @@
 #include "DisplayHardware/DisplayIdentification.h"
 #include "DisplayHardware/FramebufferSurface.h"
 #include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/Hal.h"
 #include "DisplayHardware/VirtualDisplaySurface.h"
 #include "DisplayRenderArea.h"
 #include "EffectLayer.h"
@@ -131,6 +132,7 @@
 #include "TimeStats/TimeStats.h"
 #include "android-base/parseint.h"
 #include "android-base/stringprintf.h"
+#include "android-base/strings.h"
 
 #define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock)
 
@@ -2306,8 +2308,28 @@
     // here the transaction has been committed
 }
 
-DisplayModes SurfaceFlinger::loadSupportedDisplayModes(PhysicalDisplayId displayId) const {
-    const auto hwcModes = getHwComposer().getModes(displayId);
+void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes,
+                                      DisplayModePtr& outActiveMode) const {
+    std::vector<HWComposer::HWCDisplayMode> hwcModes;
+    std::optional<hal::HWDisplayId> activeModeHwcId;
+    bool activeModeIsSupported;
+    int attempt = 0;
+    constexpr int kMaxAttempts = 3;
+    do {
+        hwcModes = getHwComposer().getModes(displayId);
+        activeModeHwcId = getHwComposer().getActiveMode(displayId);
+        LOG_ALWAYS_FATAL_IF(!activeModeHwcId, "HWC returned no active mode");
+
+        activeModeIsSupported =
+                std::any_of(hwcModes.begin(), hwcModes.end(),
+                            [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) {
+                                return mode.hwcId == *activeModeHwcId;
+                            });
+    } while (!activeModeIsSupported && ++attempt < kMaxAttempts);
+    LOG_ALWAYS_FATAL_IF(!activeModeIsSupported,
+                        "After %d attempts HWC still returns an active mode which is not"
+                        " supported. Active mode ID = %" PRIu64 " . Supported modes = %s",
+                        kMaxAttempts, *activeModeHwcId, base::Join(hwcModes, ", ").c_str());
 
     DisplayModes oldModes;
 
@@ -2345,10 +2367,15 @@
 
     if (modesAreSame) {
         // The supported modes have not changed, keep the old IDs.
-        return oldModes;
+        outModes = oldModes;
+    } else {
+        outModes = newModes;
     }
 
-    return newModes;
+    outActiveMode = *std::find_if(outModes.begin(), outModes.end(),
+                                  [activeModeHwcId](const DisplayModePtr& mode) {
+                                      return mode->getHwcId() == *activeModeHwcId;
+                                  });
 }
 
 void SurfaceFlinger::processDisplayHotplugEventsLocked() {
@@ -2364,15 +2391,9 @@
         const auto it = mPhysicalDisplayTokens.find(displayId);
 
         if (event.connection == hal::Connection::CONNECTED) {
-            auto supportedModes = loadSupportedDisplayModes(displayId);
-            const auto activeModeHwcId = getHwComposer().getActiveMode(displayId);
-            LOG_ALWAYS_FATAL_IF(!activeModeHwcId, "HWC returned no active mode");
-
-            const auto activeMode = *std::find_if(supportedModes.begin(), supportedModes.end(),
-                                                  [activeModeHwcId](const DisplayModePtr& mode) {
-                                                      return mode->getHwcId() == *activeModeHwcId;
-                                                  });
-            // TODO(b/175678215) Handle the case when activeMode is not in supportedModes
+            DisplayModes supportedModes;
+            DisplayModePtr activeMode;
+            loadDisplayModes(displayId, supportedModes, activeMode);
 
             if (it == mPhysicalDisplayTokens.end()) {
                 ALOGV("Creating display %s", to_string(displayId).c_str());
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8fe8bb1..6434ca2 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -942,7 +942,8 @@
     /*
      * Display management
      */
-    DisplayModes loadSupportedDisplayModes(PhysicalDisplayId) const REQUIRES(mStateLock);
+    void loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes,
+                          DisplayModePtr& outActiveMode) const REQUIRES(mStateLock);
     sp<DisplayDevice> setupNewDisplayDeviceInternal(
             const wp<IBinder>& displayToken,
             std::shared_ptr<compositionengine::Display> compositionDisplay,