From e2b48d25a0a5fa9f412d4536d7ddfd320b9b0f14 Mon Sep 17 00:00:00 2001 From: Robert Horvath Date: Tue, 2 Feb 2021 11:46:22 +0100 Subject: On quiescent boot, report screenTurningOff, skip screenTurningOn Fixes an issue where ActivityStacks were resumed while the screen was off and PowerManager wakefulness was asleep after a quiescent boot. To keep ActivityStacks paused, PhoneWindowManager acquires a "sleep token". In #screenTurningOff, this token is acquired, and in #screenTurningOn it is released. Before, PhoneWindowManager#systemBooted always called #screenTurningOn. In a quiescent boot, this led to the sleep token being released and ActivityStacks being resumed, even though the screen did not actually turn on. With this change, DisplayPowerController calls #screenTurningOff during a quiescent boot, acquiring the sleep token, and #systemBooted skips calling #screenTurningOn, preventing the sleep token from being released again. To finish up boot, #enableScreen is called (last part of #finishScreenTurningOn), which stops the boot animation process, signals SurfaceFlinger and ActivityManager that boot has completed. Bug: 171827143 Test: atest QuiescentBootTests#testQuiescentBoot_activitiesNotResumedAfterBoot Test: adb reboot quiescent adb shell dumpsys power: Verify wakefulness asleep adb shell dumpsys activity activities: Verify stack is sleeping (isSleeping=true), state is STOPPED (state=STOPPED) Change-Id: Ieb0b805c33b3da4261856b724f32412c2660f4c9 --- .../server/display/DisplayPowerController.java | 17 +++++--- .../android/server/policy/PhoneWindowManager.java | 45 ++++++++++++++++------ 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index cb8541eb5e94..5cd0534c8e93 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -140,6 +140,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private static final int RAMP_STATE_SKIP_INITIAL = 1; private static final int RAMP_STATE_SKIP_AUTOBRIGHT = 2; + private static final int REPORTED_TO_POLICY_UNREPORTED = -1; private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0; private static final int REPORTED_TO_POLICY_SCREEN_TURNING_ON = 1; private static final int REPORTED_TO_POLICY_SCREEN_ON = 2; @@ -311,8 +312,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private long mScreenOnBlockStartRealTime; private long mScreenOffBlockStartRealTime; - // Screen state we reported to policy. Must be one of REPORTED_TO_POLICY_SCREEN_* fields. - private int mReportedScreenStateToPolicy; + // Screen state we reported to policy. Must be one of REPORTED_TO_POLICY_* fields. + private int mReportedScreenStateToPolicy = REPORTED_TO_POLICY_UNREPORTED; // If the last recorded screen state was dozing or not. private boolean mDozing; @@ -1440,12 +1441,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private boolean setScreenState(int state, boolean reportOnly) { final boolean isOff = (state == Display.STATE_OFF); - if (mPowerState.getScreenState() != state) { + if (mPowerState.getScreenState() != state + || 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 && !mScreenOffBecauseOfProximity) { - if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON) { + if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON + || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) { setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_OFF); blockScreenOff(); mWindowManagerPolicy.screenTurningOff(mDisplayId, mPendingScreenOffUnblocker); @@ -1456,7 +1459,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } - if (!reportOnly) { + if (!reportOnly && mPowerState.getScreenState() != state) { Trace.traceCounter(Trace.TRACE_TAG_POWER, "ScreenState", state); // TODO(b/153319140) remove when we can get this from the above trace invocation SystemProperties.set("debug.tracing.screen_state", String.valueOf(state)); @@ -1486,7 +1489,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mWindowManagerPolicy.screenTurnedOff(mDisplayId); setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF); } - if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) { + if (!isOff + && (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF + || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED)) { setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_ON); if (mPowerState.getColorFadeLevel() == 0.0f) { blockScreenOn(); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index c7789eecc68f..45e6cdce768b 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -405,6 +405,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean mEnableCarDockHomeCapture = true; boolean mBootMessageNeedsHiding; + volatile boolean mBootAnimationDismissable; private KeyguardServiceDelegate mKeyguardDelegate; private boolean mKeyguardBound; final Runnable mWindowManagerDrawCallback = new Runnable() { @@ -4305,6 +4306,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { 0 /* cookie */); updateScreenOffSleepToken(false); mDefaultDisplayPolicy.screenTurnedOn(screenOnListener); + mBootAnimationDismissable = false; synchronized (mLock) { if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) { @@ -4379,6 +4381,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn", 0 /* cookie */); + enableScreen(listener, true /* report */); + } + + private void enableScreen(ScreenOnListener listener, boolean report) { final boolean enableScreen; final boolean awake = mDefaultDisplayPolicy.isAwake(); synchronized (mLock) { @@ -4396,17 +4402,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - if (listener != null) { - listener.onScreenOn(); - } + if (report) { + if (listener != null) { + listener.onScreenOn(); + } - for (int i = mScreenOnListeners.size() - 1; i >= 0; i--) { - final ScreenOnListener screenOnListener = mScreenOnListeners.valueAt(i); - if (screenOnListener != null) { - screenOnListener.onScreenOn(); + for (int i = mScreenOnListeners.size() - 1; i >= 0; i--) { + final ScreenOnListener screenOnListener = mScreenOnListeners.valueAt(i); + if (screenOnListener != null) { + screenOnListener.onScreenOn(); + } } + mScreenOnListeners.clear(); } - mScreenOnListeners.clear(); if (enableScreen) { try { @@ -4614,13 +4622,28 @@ public class PhoneWindowManager implements WindowManagerPolicy { } startedWakingUp(PowerManager.WAKE_REASON_UNKNOWN); finishedWakingUp(PowerManager.WAKE_REASON_UNKNOWN); - screenTurningOn(DEFAULT_DISPLAY, mDefaultDisplayPolicy.getScreenOnListener()); - screenTurnedOn(DEFAULT_DISPLAY); + + int defaultDisplayState = mDisplayManager.getDisplay(DEFAULT_DISPLAY).getState(); + boolean defaultDisplayOn = defaultDisplayState == Display.STATE_ON; + boolean defaultScreenTurningOn = mDefaultDisplayPolicy.getScreenOnListener() != null; + if (defaultDisplayOn || defaultScreenTurningOn) { + // Now that system is booted, wait for keyguard and windows to be drawn before + // updating the orientation listener, stopping the boot animation and enabling screen. + screenTurningOn(DEFAULT_DISPLAY, mDefaultDisplayPolicy.getScreenOnListener()); + screenTurnedOn(DEFAULT_DISPLAY); + } else { + // We're not turning the screen on, so don't wait for keyguard to be drawn + // to dismiss the boot animation and finish booting + mBootAnimationDismissable = true; + enableScreen(null, false /* report */); + } } @Override public boolean canDismissBootAnimation() { - return mDefaultDisplayPolicy.isKeyguardDrawComplete(); + // Allow to dismiss the boot animation if the keyguard has finished drawing, + // or mBootAnimationDismissable has been set + return mDefaultDisplayPolicy.isKeyguardDrawComplete() || mBootAnimationDismissable; } ProgressDialog mBootMsgDialog = null; -- cgit v1.2.3-59-g8ed1b