diff options
5 files changed, 123 insertions, 6 deletions
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index f71e853a1170..ffd7212a7525 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -715,6 +715,14 @@ public abstract class DisplayManagerInternal { boolean startOffload(); void stopOffload(); + + /** + * Called when {@link DisplayOffloadSession} tries to block screen turning on. + * + * @param unblocker a {@link Runnable} executed upon all work required before screen turning + * on is done. + */ + void onBlockingScreenOn(Runnable unblocker); } /** A session token that associates a internal display with a {@link DisplayOffloader}. */ @@ -734,6 +742,15 @@ public abstract class DisplayManagerInternal { */ void updateBrightness(float brightness); + /** + * Called while display is turning to state ON to leave a small period for displayoffload + * session to finish some work. + * + * @param unblocker a {@link Runnable} used by displayoffload session to notify + * {@link DisplayManager} that it can continue turning screen on. + */ + boolean blockScreenOn(Runnable unblocker); + /** Returns whether displayoffload supports the given display state. */ static boolean isSupportedOffloadState(int displayState) { return Display.isSuspendedState(displayState); diff --git a/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java b/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java index 1bd556bdcc4f..4e341a9c19b4 100644 --- a/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java +++ b/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java @@ -56,6 +56,15 @@ public class DisplayOffloadSessionImpl implements DisplayManagerInternal.Display } } + @Override + public boolean blockScreenOn(Runnable unblocker) { + if (mDisplayOffloader == null) { + return false; + } + mDisplayOffloader.onBlockingScreenOn(unblocker); + return true; + } + /** * Start the offload session. The method returns if the session is already active. * @return Whether the session was started successfully diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index 52c53f3d658e..6d09cc9d37ba 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -126,6 +126,8 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // To enable these logs, run: // 'adb shell setprop persist.log.tag.DisplayPowerController2 DEBUG && adb reboot' private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); + private static final String SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME = + "Screen on blocked by displayoffload"; // If true, uses the color fade on animation. // We might want to turn this off if we cannot get a guarantee that the screen @@ -155,6 +157,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private static final int MSG_SET_DWBC_COLOR_OVERRIDE = 15; private static final int MSG_SET_DWBC_LOGGING_ENABLED = 16; private static final int MSG_SET_BRIGHTNESS_FROM_OFFLOAD = 17; + private static final int MSG_OFFLOADING_SCREEN_ON_UNBLOCKED = 18; @@ -339,6 +342,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // we are waiting for a callback to release it and unblock the screen. private ScreenOnUnblocker mPendingScreenOnUnblocker; private ScreenOffUnblocker mPendingScreenOffUnblocker; + private Runnable mPendingScreenOnUnblockerByDisplayOffload; // True if we were in the process of turning off the screen. // This allows us to recover more gracefully from situations where we abort @@ -348,10 +352,15 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // The elapsed real time when the screen on was blocked. private long mScreenOnBlockStartRealTime; private long mScreenOffBlockStartRealTime; + private long mScreenOnBlockByDisplayOffloadStartRealTime; // Screen state we reported to policy. Must be one of REPORTED_TO_POLICY_* fields. private int mReportedScreenStateToPolicy = REPORTED_TO_POLICY_UNREPORTED; + // Used to deduplicate the displayoffload blocking screen on logic. One block per turning on. + // This value is reset when screen on is reported or the blocking is cancelled. + private boolean mScreenTurningOnWasBlockedByDisplayOffload; + // If the last recorded screen state was dozing or not. private boolean mDozing; @@ -472,7 +481,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal private boolean mBootCompleted; private final DisplayManagerFlags mFlags; - private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; + private DisplayOffloadSession mDisplayOffloadSession; /** * Creates the display power controller. @@ -772,6 +781,10 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal @Override public void setDisplayOffloadSession(DisplayOffloadSession session) { + if (session == mDisplayOffloadSession) { + return; + } + unblockScreenOnByDisplayOffload(); mDisplayOffloadSession = session; } @@ -1735,6 +1748,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal // reporting the display is ready because we only need to ensure the screen is in the // right power state even as it continues to converge on the desired brightness. final boolean ready = mPendingScreenOnUnblocker == null + && mPendingScreenOnUnblockerByDisplayOffload == null && (!mColorFadeEnabled || (!mColorFadeOnAnimator.isStarted() && !mColorFadeOffAnimator.isStarted())) && mPowerState.waitUntilClean(mCleanListener); @@ -1983,15 +1997,69 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } } + private void blockScreenOnByDisplayOffload(DisplayOffloadSession displayOffloadSession) { + if (mPendingScreenOnUnblockerByDisplayOffload != null || displayOffloadSession == null) { + return; + } + mScreenTurningOnWasBlockedByDisplayOffload = true; + + Trace.asyncTraceBegin( + Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME, 0); + mScreenOnBlockByDisplayOffloadStartRealTime = SystemClock.elapsedRealtime(); + + mPendingScreenOnUnblockerByDisplayOffload = + () -> onDisplayOffloadUnblockScreenOn(displayOffloadSession); + if (!displayOffloadSession.blockScreenOn(mPendingScreenOnUnblockerByDisplayOffload)) { + mPendingScreenOnUnblockerByDisplayOffload = null; + long delay = + SystemClock.elapsedRealtime() - mScreenOnBlockByDisplayOffloadStartRealTime; + Slog.w(mTag, "Tried blocking screen on for offloading but failed. So, end trace after " + + delay + " ms."); + Trace.asyncTraceEnd( + Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME, 0); + return; + } + Slog.i(mTag, "Blocking screen on for offloading."); + } + + private void onDisplayOffloadUnblockScreenOn(DisplayOffloadSession displayOffloadSession) { + Message msg = mHandler.obtainMessage(MSG_OFFLOADING_SCREEN_ON_UNBLOCKED, + displayOffloadSession); + mHandler.sendMessage(msg); + } + + private void unblockScreenOnByDisplayOffload() { + if (mPendingScreenOnUnblockerByDisplayOffload == null) { + return; + } + mPendingScreenOnUnblockerByDisplayOffload = null; + long delay = SystemClock.elapsedRealtime() - mScreenOnBlockByDisplayOffloadStartRealTime; + Slog.i(mTag, "Unblocked screen on for offloading after " + delay + " ms"); + Trace.asyncTraceEnd( + Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME, 0); + } + private boolean setScreenState(int state) { return setScreenState(state, false /*reportOnly*/); } private boolean setScreenState(int state, boolean reportOnly) { final boolean isOff = (state == Display.STATE_OFF); + final boolean isOn = (state == Display.STATE_ON); + final boolean changed = mPowerState.getScreenState() != state; - if (mPowerState.getScreenState() != state - || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) { + // If the screen is turning on, give displayoffload a chance to do something before the + // screen actually turns on. + // TODO(b/316941732): add tests for this displayoffload screen-on blocker. + if (isOn && changed && !mScreenTurningOnWasBlockedByDisplayOffload) { + blockScreenOnByDisplayOffload(mDisplayOffloadSession); + } else if (!isOn && mScreenTurningOnWasBlockedByDisplayOffload) { + // No longer turning screen on, so unblock previous screen on blocking immediately. + unblockScreenOnByDisplayOffload(); + mScreenTurningOnWasBlockedByDisplayOffload = false; + } + + if (changed || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) { // If we are trying to turn screen off, give policy a chance to do something before we // actually turn the screen off. if (isOff && !mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()) { @@ -2007,8 +2075,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } } - if (!reportOnly && mPowerState.getScreenState() != state - && readyToUpdateDisplayState()) { + if (!reportOnly && changed && readyToUpdateDisplayState() + && mPendingScreenOffUnblocker == null + && mPendingScreenOnUnblockerByDisplayOffload == null) { Trace.traceCounter(Trace.TRACE_TAG_POWER, "ScreenState", state); String propertyKey = "debug.tracing.screen_state"; @@ -2060,12 +2129,16 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal } // Return true if the screen isn't blocked. - return mPendingScreenOnUnblocker == null; + return mPendingScreenOnUnblocker == null + && mPendingScreenOnUnblockerByDisplayOffload == null; } private void setReportedScreenState(int state) { Trace.traceCounter(Trace.TRACE_TAG_POWER, "ReportedScreenStateToPolicy", state); mReportedScreenStateToPolicy = state; + if (state == REPORTED_TO_POLICY_SCREEN_ON) { + mScreenTurningOnWasBlockedByDisplayOffload = false; + } } private void loadAmbientLightSensor() { @@ -2813,6 +2886,12 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal updatePowerState(); } break; + case MSG_OFFLOADING_SCREEN_ON_UNBLOCKED: + if (mDisplayOffloadSession == msg.obj) { + unblockScreenOnByDisplayOffload(); + updatePowerState(); + } + break; case MSG_CONFIGURE_BRIGHTNESS: BrightnessConfiguration brightnessConfiguration = (BrightnessConfiguration) msg.obj; diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayOffloadSessionImplTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayOffloadSessionImplTest.java index dea838d3763d..fbb14c3db9f9 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayOffloadSessionImplTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayOffloadSessionImplTest.java @@ -19,6 +19,7 @@ package com.android.server.display; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -88,4 +89,12 @@ public class DisplayOffloadSessionImplTest { verify(mDisplayPowerController).setBrightnessFromOffload(brightness); } + + @Test + public void testBlockScreenOn() { + Runnable unblocker = () -> {}; + mSession.blockScreenOn(unblocker); + + verify(mDisplayOffloader).onBlockingScreenOn(eq(unblocker)); + } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java index f36854b1ea78..0c845de8846e 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -1235,6 +1235,9 @@ public class LocalDisplayAdapterTest { @Override public void stopOffload() {} + + @Override + public void onBlockingScreenOn(Runnable unblocker) {} }); mDisplayOffloadSession = new DisplayOffloadSessionImpl(mDisplayOffloader, |