Use power mode of all independent displays to control power optimisations.
In the following cases, if there is any performance-optimised/independent active display (powered on) then power optimisations are disabled. If there is no performance-optimised/independent active display then power optimisations are enabled, even if there are power-optimised displays that are powered on.
* Physical or virtual display power mode change
* Physical or virtual display added or removed
Power optimisations include:
* Lowering thread priority
Bug: 342681202
Bug: 241285876
Flag: android.companion.virtualdevice.flags.correct_virtual_display_power_state
Test: manually tested with flag on/off using Android Auto Projected
Change-Id: I96068c8779dbfe2b51b4d9acd522b6cb3995681f
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 099aa7a..217581c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4075,6 +4075,10 @@
incRefreshableDisplays();
}
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ applyOptimizationPolicy(__func__);
+ }
+
mDisplays.try_emplace(displayToken, std::move(display));
// For an external display, loadDisplayModes already attempted to select the same mode
@@ -4131,6 +4135,10 @@
// not be accessible.
}));
}
+
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ applyOptimizationPolicy(__func__);
+ }
}
void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
@@ -5679,7 +5687,7 @@
}
const auto displayId = display->getPhysicalId();
- ALOGD("Setting power mode %d on display %s", mode, to_string(displayId).c_str());
+ ALOGD("Setting power mode %d on physical display %s", mode, to_string(displayId).c_str());
const auto currentMode = display->getPowerMode();
if (currentMode == mode) {
@@ -5722,11 +5730,11 @@
}
if (displayId == mActiveDisplayId) {
- // TODO: b/281692563 - Merge the syscalls. For now, keep uclamp in a separate syscall
- // and set it before SCHED_FIFO due to b/190237315.
- constexpr const char* kWhence = "setPowerMode(ON)";
- setSchedAttr(true, kWhence);
- setSchedFifo(true, kWhence);
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ applyOptimizationPolicy("setPhysicalDisplayPowerMode(ON)");
+ } else {
+ disablePowerOptimizations("setPhysicalDisplayPowerMode(ON)");
+ }
}
getHwComposer().setPowerMode(displayId, mode);
@@ -5753,9 +5761,11 @@
if (const auto display = getActivatableDisplay()) {
onActiveDisplayChangedLocked(activeDisplay.get(), *display);
} else {
- constexpr const char* kWhence = "setPowerMode(OFF)";
- setSchedFifo(false, kWhence);
- setSchedAttr(false, kWhence);
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ applyOptimizationPolicy("setPhysicalDisplayPowerMode(OFF)");
+ } else {
+ enablePowerOptimizations("setPhysicalDisplayPowerMode(OFF)");
+ }
if (currentModeNotDozeSuspend) {
if (!FlagManager::getInstance().multithreaded_present()) {
@@ -5816,7 +5826,67 @@
mScheduler->setDisplayPowerMode(displayId, mode);
- ALOGD("Finished setting power mode %d on display %s", mode, to_string(displayId).c_str());
+ ALOGD("Finished setting power mode %d on physical display %s", mode,
+ to_string(displayId).c_str());
+}
+
+void SurfaceFlinger::setVirtualDisplayPowerMode(const sp<DisplayDevice>& display,
+ hal::PowerMode mode) {
+ if (!display->isVirtual()) {
+ ALOGE("%s: Invalid operation on physical display", __func__);
+ return;
+ }
+
+ const auto displayId = display->getVirtualId();
+ ALOGD("Setting power mode %d on virtual display %s %s", mode, to_string(displayId).c_str(),
+ display->getDisplayName().c_str());
+
+ display->setPowerMode(static_cast<hal::PowerMode>(mode));
+
+ applyOptimizationPolicy(__func__);
+
+ ALOGD("Finished setting power mode %d on virtual display %s", mode,
+ to_string(displayId).c_str());
+}
+
+bool SurfaceFlinger::shouldOptimizeForPerformance() {
+ for (const auto& [_, display] : mDisplays) {
+ // Displays that are optimized for power are always powered on and should not influence
+ // whether there is an active display for the purpose of power optimization, etc. If these
+ // displays are being shown somewhere, a different (physical or virtual) display that is
+ // optimized for performance will be powered on in addition. Displays optimized for
+ // performance will change power mode, so if they are off then they are not active.
+ if (display->isPoweredOn() &&
+ display->getOptimizationPolicy() ==
+ gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void SurfaceFlinger::enablePowerOptimizations(const char* whence) {
+ ALOGD("%s: Enabling power optimizations", whence);
+
+ setSchedAttr(false, whence);
+ setSchedFifo(false, whence);
+}
+
+void SurfaceFlinger::disablePowerOptimizations(const char* whence) {
+ ALOGD("%s: Disabling power optimizations", whence);
+
+ // TODO: b/281692563 - Merge the syscalls. For now, keep uclamp in a separate syscall
+ // and set it before SCHED_FIFO due to b/190237315.
+ setSchedAttr(true, whence);
+ setSchedFifo(true, whence);
+}
+
+void SurfaceFlinger::applyOptimizationPolicy(const char* whence) {
+ if (shouldOptimizeForPerformance()) {
+ disablePowerOptimizations(whence);
+ } else {
+ enablePowerOptimizations(whence);
+ }
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
@@ -5838,9 +5908,8 @@
ALOGE("Failed to set power mode %d for display token %p", mode, displayToken.get());
} else if (display->isVirtual()) {
if (FlagManager::getInstance().correct_virtual_display_power_state()) {
- ALOGD("Setting power mode %d on virtual display %s", mode,
- display->getDisplayName().c_str());
- display->setPowerMode(static_cast<hal::PowerMode>(mode));
+ ftl::FakeGuard guard(mStateLock);
+ setVirtualDisplayPowerMode(display, static_cast<hal::PowerMode>(mode));
} else {
ALOGW("Attempt to set power mode %d for virtual display", mode);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 39e237b..8a0489f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -735,6 +735,22 @@
// Called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
REQUIRES(mStateLock, kMainThreadContext);
+ void setVirtualDisplayPowerMode(const sp<DisplayDevice>& display, hal::PowerMode mode)
+ REQUIRES(mStateLock, kMainThreadContext);
+
+ // Returns whether to optimize globally for performance instead of power.
+ bool shouldOptimizeForPerformance() REQUIRES(mStateLock);
+
+ // Turns on power optimizations, for example when there are no displays to be optimized for
+ // performance.
+ static void enablePowerOptimizations(const char* whence);
+
+ // Turns off power optimizations.
+ static void disablePowerOptimizations(const char* whence);
+
+ // Enables or disables power optimizations depending on whether there are displays that should
+ // be optimized for performance.
+ void applyOptimizationPolicy(const char* whence) REQUIRES(mStateLock);
// Returns the preferred mode for PhysicalDisplayId if the Scheduler has selected one for that
// display. Falls back to the display's defaultModeId otherwise.