SF: Requery display modes if the active mode is not supported
Some TV devices send two hotplug events immediately one after another
during startup. Because we query the active display mode
and the supported modes in two separete calls to HWC it's possible
to get an active mode, which is not in the list of supported modes.
If this happens we requery the display modes up to 3 times. If the
problem still persists we throw a fatal error.
Bug: 175678215
Bug: 159590486
Test: check that device boots
Test: plug HDMI out and it
Change-Id: I94dbadac4eb75ed659ede6299df0c3459ed6c74e
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 056dd9f..b39231e 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());