PhoneWindowManager responds to the power key
First, press the power key and then call frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.. Interceptkeybeforequeuing method of Java:
// TODO(b/117479243): handle it in InputPolicy /** {@inheritDoc} */ @Override public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { ...... // Handle special keys. switch (keyCode) { ...... case KeyEvent.KEYCODE_POWER: { EventLogTags.writeInterceptPower( KeyEvent.actionToString(event.getAction()), mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter); // Any activity on the power button stops the accessibility shortcut cancelPendingAccessibilityShortcutAction(); result &= ~ACTION_PASS_TO_USER; isWakeKey = false; // wake-up will be handled separately if (down) { interceptPowerKeyDown(event, interactive); } else { interceptPowerKeyUp(event, interactive, canceled); } break; } ...... } ...... }
The interceptPowerKeyUp method of PhoneWindowManager was called:
private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) { final boolean handled = canceled || mPowerKeyHandled; mScreenshotChordPowerKeyTriggered = false; cancelPendingScreenshotChordAction(); cancelPendingPowerKeyAction(); if (!handled) { ...... // No other actions. Handle it immediately. powerPress(eventTime, interactive, mPowerKeyPressCounter); } // Done. Reset our state. finishPowerKeyPress(); }
The powerPress method of PhoneWindowManager was called:
private void powerPress(long eventTime, boolean interactive, int count) { ...... if (count == 2) { powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior); } else if (count == 3) { powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior); } else if (interactive && !mBeganFromNonInteractive) { switch (mShortPressOnPowerBehavior) { ...... case SHORT_PRESS_POWER_GO_TO_SLEEP: goToSleepFromPowerButton(eventTime, 0); break; ...... } } }
The goToSleepFromPowerButton method of PhoneWindowManager was called:
/** * Sends the device to sleep as a result of a power button press. * * @return True if the was device was sent to sleep, false if sleep was suppressed. */ private boolean goToSleepFromPowerButton(long eventTime, int flags) { // Before we actually go to sleep, we check the last wakeup reason. // If the device very recently woke up from a gesture (like user lifting their device) // then ignore the sleep instruction. This is because users have developed // a tendency to hit the power button immediately when they pick up their device, and we // don't want to put the device back to sleep in those cases. final PowerManager.WakeData lastWakeUp = mPowerManagerInternal.getLastWakeup(); if (lastWakeUp != null && lastWakeUp.wakeReason == PowerManager.WAKE_REASON_GESTURE) { final int gestureDelayMillis = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.POWER_BUTTON_SUPPRESSION_DELAY_AFTER_GESTURE_WAKE, POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS); final long now = SystemClock.uptimeMillis(); if (mPowerButtonSuppressionDelayMillis > 0 && (now < lastWakeUp.wakeTime + mPowerButtonSuppressionDelayMillis)) { Slog.i(TAG, "Sleep from power button suppressed. Time since gesture: " + (now - lastWakeUp.wakeTime) + "ms"); return false; } } goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, flags); return true; }
The goToSleep method of PhoneWindowManager was called:
private void goToSleep(long eventTime, int reason, int flags) { mRequestedOrGoingToSleep = true; mPowerManager.goToSleep(eventTime, reason, flags); }
PowerMangerService processing screen off
Called frameworks / base / services / core / Java / COM / Android / server / power / powermanagerservice goToSleep method of BinderService static inner class of Java:
@Override // Binder call public void goToSleep(long eventTime, int reason, int flags) { if (eventTime > mClock.uptimeMillis()) { throw new IllegalArgumentException("event time must not be in the future"); } mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); final int uid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { goToSleepInternal(eventTime, reason, flags, uid); } finally { Binder.restoreCallingIdentity(ident); } }
Gotoseleepinternal method of PowerManagerService called:
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) { synchronized (mLock) { if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) { updatePowerStateLocked(); } } }
The gotoselepnoupdatelocked method of PowerManagerService was called:
/** * Puts the system in doze. * * This method is called goToSleep for historical reasons but actually attempts to DOZE, * and only tucks itself in to SLEEP if requested with the flag * {@link PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE}. */ @SuppressWarnings("deprecation") private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) { if (DEBUG_SPEW) { Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason + ", flags=" + flags + ", uid=" + uid); } if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP || getWakefulnessLocked() == WAKEFULNESS_DOZING || !mSystemReady || !mBootCompleted) { return false; } Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep"); try { reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX, Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN)); Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason) + " (uid " + uid + ")..."); mLastSleepTime = eventTime; mLastSleepReason = reason; mSandmanSummoned = true; mDozeStartInProgress = true; setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime); // Report the number of wake locks that will be cleared by going to sleep. int numWakeLocksCleared = 0; final int numWakeLocks = mWakeLocks.size(); for (int i = 0; i < numWakeLocks; i++) { final WakeLock wakeLock = mWakeLocks.get(i); switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) { case PowerManager.FULL_WAKE_LOCK: case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: case PowerManager.SCREEN_DIM_WAKE_LOCK: numWakeLocksCleared += 1; break; } } EventLogTags.writePowerSleepRequested(numWakeLocksCleared); // Skip dozing if requested. if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) { reallyGoToSleepNoUpdateLocked(eventTime, uid); } } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); } return true; }
The setwakefullness locked method of PowerManagerService is called, and wakefullness is passed in_ DOZING:
@VisibleForTesting void setWakefulnessLocked(int wakefulness, int reason, long eventTime) { if (getWakefulnessLocked() != wakefulness) { // Under lock, invalidate before set ensures caches won't return stale values. mInjector.invalidateIsInteractiveCaches(); mWakefulnessRaw = wakefulness; mWakefulnessChanging = true; mDirty |= DIRTY_WAKEFULNESS; // This is only valid while we are in wakefulness dozing. Set to false otherwise. mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING); if (mNotifier != null) { mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime); } mAttentionDetector.onWakefulnessChangeStarted(wakefulness); } }
Called frameworks / base / services / core / Java / COM / Android / server / power / notifier Onwakefullneschangestarted method of Java:
/** * Notifies that the device is changing wakefulness. * This function may be called even if the previous change hasn't finished in * which case it will assume that the state did not fully converge before the * next transition began and will recover accordingly. */ public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) { final boolean interactive = PowerManagerInternal.isInteractive(wakefulness); if (DEBUG) { Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness + ", reason=" + reason + ", interactive=" + interactive); } // Tell the activity manager about changes in wakefulness, not just interactivity. // It needs more granularity than other components. mHandler.post(new Runnable() { @Override public void run() { mActivityManagerInternal.onWakefulnessChanged(wakefulness); } }); // Handle any early interactive state changes. // Finish pending incomplete ones from a previous cycle. if (mInteractive != interactive) { // Finish up late behaviors if needed. if (mInteractiveChanging) { handleLateInteractiveChange(); } // Start input as soon as we start waking up or going to sleep. mInputManagerInternal.setInteractive(interactive); mInputMethodManagerInternal.setInteractive(interactive); // Notify battery stats. try { mBatteryStats.noteInteractive(interactive); } catch (RemoteException ex) { } FrameworkStatsLog.write(FrameworkStatsLog.INTERACTIVE_STATE_CHANGED, interactive ? FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON : FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF); // Handle early behaviors. mInteractive = interactive; mInteractiveChangeReason = reason; mInteractiveChangeStartTime = eventTime; mInteractiveChanging = true; handleEarlyInteractiveChange(); } }
This method first notifies AMS that the status changes to wakefullness_ DOZING, then notifies InputManager as an inactive state, and finally calls the handleEarlyInteractiveChange method of Notifier:
/** * Handle early interactive state changes such as getting applications or the lock * screen running and ready for the user to see (such as when turning on the screen). */ private void handleEarlyInteractiveChange() { synchronized (mLock) { if (mInteractive) { // Waking up... mHandler.post(new Runnable() { @Override public void run() { final int why = translateOnReason(mInteractiveChangeReason); mPolicy.startedWakingUp(why); } }); // Send interactive broadcast. mPendingInteractiveState = INTERACTIVE_STATE_AWAKE; mPendingWakeUpBroadcast = true; updatePendingBroadcastLocked(); } else { // Going to sleep... // Tell the policy that we started going to sleep. final int why = translateOffReason(mInteractiveChangeReason); mHandler.post(new Runnable() { @Override public void run() { mPolicy.startedGoingToSleep(why); } }); } } }
PhoneWindowManager executes startedGoingToSleep
Called frameworks / base / services / core / Java / COM / Android / server / policy / phonewindowmanager The startedGoingToSleep method of Java:
// Called on the PowerManager's Notifier thread. @Override public void startedGoingToSleep(int why) { if (DEBUG_WAKEUP) { Slog.i(TAG, "Started going to sleep... (why=" + WindowManagerPolicyConstants.offReasonToString(why) + ")"); } mGoingToSleep = true; mRequestedOrGoingToSleep = true; if (mKeyguardDelegate != null) { mKeyguardDelegate.onStartedGoingToSleep(why); } }
Notify the onStartedGoingToSleep of keyguard
Frameworks / base / services / core / Java / COM / Android / server / policy / keyguard / keyguardservicedelegate. Com was called Onstartedgoingtoseep method of Java:
public void onStartedGoingToSleep(int why) { if (mKeyguardService != null) { mKeyguardService.onStartedGoingToSleep(why); } mKeyguardState.offReason = why; mKeyguardState.interactiveState = INTERACTIVE_STATE_GOING_TO_SLEEP; }
Called frameworks / base / services / core / Java / COM / Android / server / policy / keyguard / keyguardservicewrapper Onstartedgoingtoseep method of Java:
@Override public void onStartedGoingToSleep(int reason) { try { mService.onStartedGoingToSleep(reason); } catch (RemoteException e) { Slog.w(TAG , "Remote Exception", e); } }
Frameworks / base / packages / systemui / SRC / COM / Android / systemui / keyguard / keyguardservice in the systemui process is called through the binder Onstartedgoingtoseep method of member variable mBinder of Java:
@Override // Binder interface public void onStartedGoingToSleep(int reason) { checkPermission(); mKeyguardViewMediator.onStartedGoingToSleep(reason); mKeyguardLifecyclesDispatcher.dispatch( KeyguardLifecyclesDispatcher.STARTED_GOING_TO_SLEEP); }
PowerManagerService updates the power status
Go back to gotoseleepinternal method of PowerManagerService, and then call updateposstatelocked method of PowerManagerService:
/** * Updates the global power state based on dirty bits recorded in mDirty. * * This is the main function that performs power state transitions. * We centralize them here so that we can recompute the power state completely * each time something important changes, and ensure that we do it the same * way each time. The point is to gather all of the transition logic here. */ private void updatePowerStateLocked() { if (!mSystemReady || mDirty == 0) { return; } if (!Thread.holdsLock(mLock)) { Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked"); } Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState"); try { // Phase 0: Basic state updates. updateIsPoweredLocked(mDirty); updateStayOnLocked(mDirty); updateScreenBrightnessBoostLocked(mDirty); // Phase 1: Update wakefulness. // Loop because the wake lock and user activity computations are influenced // by changes in wakefulness. final long now = mClock.uptimeMillis(); int dirtyPhase2 = 0; for (;;) { int dirtyPhase1 = mDirty; dirtyPhase2 |= dirtyPhase1; mDirty = 0; updateWakeLockSummaryLocked(dirtyPhase1); updateUserActivitySummaryLocked(now, dirtyPhase1); updateAttentiveStateLocked(now, dirtyPhase1); if (!updateWakefulnessLocked(dirtyPhase1)) { break; } } // Phase 2: Lock profiles that became inactive/not kept awake. updateProfilesLocked(now); // Phase 3: Update display power state. final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2); // Phase 4: Update dream state (depends on display ready signal). updateDreamLocked(dirtyPhase2, displayBecameReady); // Phase 5: Send notifications, if needed. finishWakefulnessChangeIfNeededLocked(); // Phase 6: Update suspend blocker. // Because we might release the last suspend blocker here, we need to make sure // we finished everything else first! updateSuspendBlockerLocked(); } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); } }
In Phase 3, the updateDisplayPowerStateLocked method of PowerManagerService is invoked:
/** * Updates the display power state asynchronously. * When the update is finished, mDisplayReady will be set to true. The display * controller posts a message to tell us when the actual display power state * has been updated so we come back here to double-check and finish up. * * This function recalculates the display power state each time. * * @return True if the display became ready. */ private boolean updateDisplayPowerStateLocked(int dirty) { final boolean oldDisplayReady = mDisplayReady; if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED | DIRTY_QUIESCENT)) != 0) { if ((dirty & DIRTY_QUIESCENT) != 0) { sQuiescent = false; } mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked(); // Determine appropriate screen brightness and auto-brightness adjustments. final boolean autoBrightness; final float screenBrightnessOverride; if (!mBootCompleted) { // Keep the brightness steady during boot. This requires the // bootloader brightness and the default brightness to be identical. autoBrightness = false; screenBrightnessOverride = mScreenBrightnessSettingDefault; } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) { autoBrightness = false; screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager; } else { autoBrightness = (mScreenBrightnessModeSetting == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT; } // Update display power request. mDisplayPowerRequest.screenBrightnessOverride = screenBrightnessOverride; mDisplayPowerRequest.useAutoBrightness = autoBrightness; mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked(); mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness(); updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest); if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) { mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager; if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0 && !mDrawWakeLockOverrideFromSidekick) { if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) { mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE; } if (mDisplayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) { mDisplayPowerRequest.dozeScreenState = Display.STATE_ON; } } mDisplayPowerRequest.dozeScreenBrightness = mDozeScreenBrightnessOverrideFromDreamManagerFloat; } else { mDisplayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN; mDisplayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; } mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest, mRequestWaitForNegativeProximity); mRequestWaitForNegativeProximity = false; if (DEBUG_SPEW) { Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady + ", policy=" + mDisplayPowerRequest.policy + ", mWakefulness=" + getWakefulnessLocked() + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary) + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary) + ", mBootCompleted=" + mBootCompleted + ", screenBrightnessOverride=" + screenBrightnessOverride + ", useAutoBrightness=" + autoBrightness + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress + ", mIsVrModeEnabled= " + mIsVrModeEnabled + ", sQuiescent=" + sQuiescent); } } return mDisplayReady && !oldDisplayReady; }
DisplayManagerService updates the power status
Through mdisplaymanagerinternal requestPowerState called frameworks / base / services / core / Java / COM / Android / server / display / displaymanagerservice The requestPowerState method of the internal class LocalService of Java:
@Override public boolean requestPowerState(DisplayPowerRequest request, boolean waitForNegativeProximity) { synchronized (mSyncRoot) { return mDisplayPowerController.requestPowerState(request, waitForNegativeProximity); } }
DisplayPowerController updates the power status
Called frameworks / base / services / core / Java / COM / Android / server / display / displaypowercontroller requestPowerState method of Java:
@Override public boolean requestPowerState(DisplayPowerRequest request, boolean waitForNegativeProximity) { synchronized (mSyncRoot) { return mDisplayPowerController.requestPowerState(request, waitForNegativeProximity); } }
The sendupdateposstatelocked method of DisplayPowerController was called:
private void sendUpdatePowerStateLocked() { if (!mPendingUpdatePowerStateLocked) { mPendingUpdatePowerStateLocked = true; Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE); mHandler.sendMessage(msg); } }
This message is processed in the handleMessage method of the internal class DisplayControllerHandler of displaypower controller:
@Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_UPDATE_POWER_STATE: updatePowerState(); break; ...... } }
The updateperstate method of DisplayPowerController was called:
private void updatePowerState() { ...... animateScreenStateChange(state, performScreenOffTransition); ...... }
The animateScreenStateChange method of DisplayPowerController was called:
private void animateScreenStateChange(int target, boolean performScreenOffTransition) { ...... if (target == Display.STATE_ON) { ...... } else if (target == Display.STATE_VR) { ...... } else if (target == Display.STATE_DOZE) { ...... } else if (target == Display.STATE_DOZE_SUSPEND) { ...... } else if (target == Display.STATE_ON_SUSPEND) { ...... } else { // Want screen off. mPendingScreenOff = true; if (!mColorFadeEnabled) { mPowerState.setColorFadeLevel(0.0f); } if (mPowerState.getColorFadeLevel() == 0.0f) { // Turn the screen off. // A black surface is already hiding the contents of the screen. setScreenState(Display.STATE_OFF); mPendingScreenOff = false; mPowerState.dismissColorFadeResources(); } else if (performScreenOffTransition && mPowerState.prepareColorFade(mContext, mColorFadeFadesConfig ? ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN) && mPowerState.getScreenState() != Display.STATE_OFF) { // Perform the screen off animation. mColorFadeOffAnimator.start(); } else { // Skip the screen off animation and add a black surface to hide the // contents of the screen. mColorFadeOffAnimator.end(); } } }
The first time you come in here, you will call mcolorfadeoffanimator Start starts the ColorFade animation. When you come in again, the ColorFade animation runs out. The condition is mppowerstate Getcolorfadelevel() = = 0.0F if it is satisfied, the setscreen method of DisplayPowerController will be called:
private boolean setScreenState(int state) { return setScreenState(state, false /*reportOnly*/); } private boolean setScreenState(int state, boolean reportOnly) { final boolean isOff = (state == Display.STATE_OFF); if (mPowerState.getScreenState() != state) { // 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) { setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_OFF); blockScreenOff(); mWindowManagerPolicy.screenTurningOff(mPendingScreenOffUnblocker); unblockScreenOff(); } else if (mPendingScreenOffUnblocker != null) { // Abort doing the state change until screen off is unblocked. return false; } } if (!reportOnly) { 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)); mPowerState.setScreenState(state); // Tell battery stats about the transition. try { mBatteryStats.noteScreenState(state); } catch (RemoteException ex) { // same process } } } // Tell the window manager policy when the screen is turned off or on unless it's due // to the proximity sensor. We temporarily block turning the screen on until the // window manager is ready by leaving a black surface covering the screen. // This surface is essentially the final state of the color fade animation and // it is only removed once the window manager tells us that the activity has // finished drawing underneath. if (isOff && mReportedScreenStateToPolicy != REPORTED_TO_POLICY_SCREEN_OFF && !mScreenOffBecauseOfProximity) { setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF); unblockScreenOn(); mWindowManagerPolicy.screenTurnedOff(); } else if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_OFF) { // We told policy already that screen was turning off, but now we changed our minds. // Complete the full state transition on -> turningOff -> off. unblockScreenOff(); mWindowManagerPolicy.screenTurnedOff(); setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF); } ...... // Return true if the screen isn't blocked. return mPendingScreenOnUnblocker == null; }
PhoneWindowManager executes screenTurningOff
This method first calls frameworks / base / services / core / Java / COM / Android / server / policy / phonewindowmanager screenTurningOff method of Java:
@Override public void screenTurningOff(ScreenOffListener screenOffListener) { mWindowManagerFuncs.screenTurningOff(screenOffListener); synchronized (mLock) { if (mKeyguardDelegate != null) { mKeyguardDelegate.onScreenTurningOff(); } } }
Screen capture before screen out
This method first calls frameworks / base / services / core / Java / COM / Android / server / WM / windowmanagerservice screenTurningOff method of Java:
@Override public void screenTurningOff(ScreenOffListener listener) { mTaskSnapshotController.screenTurningOff(listener); }
Called frameworks / base / services / core / Java / COM / Android / server / WM / tasksnapshotcontroller screenTurningOff method of Java:
/** * Called when screen is being turned off. */ void screenTurningOff(ScreenOffListener listener) { if (shouldDisableSnapshots()) { listener.onScreenOff(); return; } // We can't take a snapshot when screen is off, so take a snapshot now! mHandler.post(() -> { try { synchronized (mService.mGlobalLock) { mTmpTasks.clear(); mService.mRoot.forAllTasks(task -> { if (task.isVisible()) { mTmpTasks.add(task); } }); // Allow taking snapshot of home when turning screen off to reduce the delay of // waking from secure lock to home. final boolean allowSnapshotHome = mService.mPolicy.isKeyguardSecure(mService.mCurrentUserId); snapshotTasks(mTmpTasks, allowSnapshotHome); } } finally { listener.onScreenOff(); } }); }
Cut the screen here and call listener Onscreen off stops blocking the screen.
Notify onscreen Turningoff of keyguard
Return to the screenTurningOff method of PhoneWindowManager, and then call frameworks / base / services / core / Java / COM / Android / server / policy / keyguard / keyguardservicedelegate Onscreen Turningoff method of Java:
public void onScreenTurningOff() { if (mKeyguardService != null) { if (DEBUG) Log.v(TAG, "onScreenTurningOff()"); mKeyguardService.onScreenTurningOff(); } mKeyguardState.screenState = SCREEN_STATE_TURNING_OFF; }
Called frameworks / base / services / core / Java / COM / Android / server / policy / keyguard / keyguardservicewrapper Onscreen Turningoff method of Java:
@Override public void onScreenTurningOff() { try { mService.onScreenTurningOff(); } catch (RemoteException e) { Slog.w(TAG , "Remote Exception", e); } }
Frameworks / base / packages / systemui / SRC / COM / Android / systemui / keyguard / keyguardservice in the systemui process is called through the binder Onscreen Turningoff method of member variable mBinder of Java:
@Override // Binder interface public void onScreenTurningOff() { checkPermission(); mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNING_OFF); }
PhoneWindowManager executes screenTurnedOff
The setscreen state method of DisplayPowerController will also call frameworks / base / services / core / Java / COM / Android / server / policy / phonewindowmanager screenTurnedOff method of Java:
// Called on the DisplayManager's DisplayPowerController thread. @Override public void screenTurnedOff() { if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off..."); updateScreenOffSleepToken(true); mDefaultDisplayPolicy.screenTurnedOff(); synchronized (mLock) { if (mKeyguardDelegate != null) { mKeyguardDelegate.onScreenTurnedOff(); } } mDefaultDisplayRotation.updateOrientationListener(); reportScreenStateToVrManager(false); }
Here, the screen out SleepToken is obtained through updatescreen offsleeptoken (true), and the resume Activity will be pause. See SleepToken mechanism.
Notify onscreen turnedoff of keyguard
Frameworks / base / services / core / Java / COM / Android / server / policy / keyguard / keyguardservicedelegate. Com was called Onscreen turnedoff method of Java:
public void onScreenTurnedOff() { if (mKeyguardService != null) { if (DEBUG) Log.v(TAG, "onScreenTurnedOff()"); mKeyguardService.onScreenTurnedOff(); } mKeyguardState.screenState = SCREEN_STATE_OFF; }
Called frameworks / base / services / core / Java / COM / Android / server / policy / keyguard / keyguardservicewrapper Onscreen turnedoff method of Java:
@Override public void onScreenTurnedOff() { try { mService.onScreenTurnedOff(); } catch (RemoteException e) { Slog.w(TAG , "Remote Exception", e); } }
Frameworks / base / packages / systemui / SRC / COM / Android / systemui / keyguard / keyguardservice in the systemui process is called through the binder Onscreen turnedoff method of member variable mBinder of Java:
@Override // Binder interface public void onScreenTurnedOff() { checkPermission(); mKeyguardViewMediator.onScreenTurnedOff(); mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNED_OFF); }
PhoneWindowManager executes finishedGoingToSleep
Go back to the updateposstatelocked method of PowerManagerService, and call the finishwakefullnesschangeifneededlocked method of PowerManagerService in Phase 5:
private void finishWakefulnessChangeIfNeededLocked() { if (mWakefulnessChanging && mDisplayReady) { if (getWakefulnessLocked() == WAKEFULNESS_DOZING && (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) { return; // wait until dream has enabled dozing } else { // Doze wakelock acquired (doze started) or device is no longer dozing. mDozeStartInProgress = false; } if (getWakefulnessLocked() == WAKEFULNESS_DOZING || getWakefulnessLocked() == WAKEFULNESS_ASLEEP) { logSleepTimeoutRecapturedLocked(); } if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) { Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0); final int latencyMs = (int) (mClock.uptimeMillis() - mLastWakeTime); if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) { Slog.w(TAG, "Screen on took " + latencyMs + " ms"); } } mWakefulnessChanging = false; mNotifier.onWakefulnessChangeFinished(); } }
Called frameworks / base / services / core / Java / COM / Android / server / power / notifier Onwakefullnesschangefinished method of Java:
/** * Notifies that the device has finished changing wakefulness. */ public void onWakefulnessChangeFinished() { if (DEBUG) { Slog.d(TAG, "onWakefulnessChangeFinished"); } if (mInteractiveChanging) { mInteractiveChanging = false; handleLateInteractiveChange(); } }
The handleLateInteractiveChange method of Notifier was called:
/** * Handle late interactive state changes once they are finished so that the system can * finish pending transitions (such as turning the screen off) before causing * applications to change state visibly. */ private void handleLateInteractiveChange() { synchronized (mLock) { final int interactiveChangeLatency = (int) (SystemClock.uptimeMillis() - mInteractiveChangeStartTime); if (mInteractive) { // Finished waking up... ...... } else { // Finished going to sleep... // This is a good time to make transitions that we don't want the user to see, // such as bringing the key guard to focus. There's no guarantee for this // however because the user could turn the device on again at any time. // Some things may need to be protected by other mechanisms that defer screen on. // Cancel pending user activity. if (mUserActivityPending) { mUserActivityPending = false; mHandler.removeMessages(MSG_USER_ACTIVITY); } // Tell the policy we finished going to sleep. final int why = translateOffReason(mInteractiveChangeReason); mHandler.post(new Runnable() { @Override public void run() { LogMaker log = new LogMaker(MetricsEvent.SCREEN); log.setType(MetricsEvent.TYPE_CLOSE); log.setSubtype(why); log.setLatency(interactiveChangeLatency); log.addTaggedData( MetricsEvent.FIELD_SCREEN_SLEEP_REASON, mInteractiveChangeReason); MetricsLogger.action(log); EventLogTags.writePowerScreenState(0, why, 0, 0, interactiveChangeLatency); mPolicy.finishedGoingToSleep(why); } }); // Send non-interactive broadcast. mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP; mPendingGoToSleepBroadcast = true; updatePendingBroadcastLocked(); } } }
Through mhandler The post method calls the frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager. after thread switching. The finishedGoingToSleep method of Java:
// Called on the PowerManager's Notifier thread. @Override public void finishedGoingToSleep(int why) { EventLogTags.writeScreenToggled(0); if (DEBUG_WAKEUP) { Slog.i(TAG, "Finished going to sleep... (why=" + WindowManagerPolicyConstants.offReasonToString(why) + ")"); } MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000); mGoingToSleep = false; mRequestedOrGoingToSleep = false; mDefaultDisplayPolicy.setAwake(false); // We must get this work done here because the power manager will drop // the wake lock and let the system suspend once this function returns. synchronized (mLock) { updateWakeGestureListenerLp(); updateLockScreenTimeout(); } mDefaultDisplayRotation.updateOrientationListener(); if (mKeyguardDelegate != null) { mKeyguardDelegate.onFinishedGoingToSleep(why, mCameraGestureTriggeredDuringGoingToSleep); } if (mDisplayFoldController != null) { mDisplayFoldController.finishedGoingToSleep(); } mCameraGestureTriggeredDuringGoingToSleep = false; }
First, the event log: screen is printed_ toggled: 0
Notify the onfinished goingtosleep of keyguard
And then called frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.. Onfinished goingtosleep method of Java:
public void onFinishedGoingToSleep(int why, boolean cameraGestureTriggered) { if (mKeyguardService != null) { mKeyguardService.onFinishedGoingToSleep(why, cameraGestureTriggered); } mKeyguardState.interactiveState = INTERACTIVE_STATE_SLEEP; }
Called frameworks / base / services / core / Java / COM / Android / server / policy / keyguard / keyguardservicewrapper Onfinished goingtosleep method of Java:
@Override public void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) { try { mService.onFinishedGoingToSleep(reason, cameraGestureTriggered); } catch (RemoteException e) { Slog.w(TAG , "Remote Exception", e); } }
Frameworks / base / packages / systemui / SRC / COM / Android / systemui / keyguard / keyguardservice in the systemui process is called through the binder Onfinished goingtosleep method of member variable mBinder of Java:
@Override // Binder interface public void onFinishedGoingToSleep(int reason, boolean cameraGestureTriggered) { checkPermission(); mKeyguardViewMediator.onFinishedGoingToSleep(reason, cameraGestureTriggered); mKeyguardLifecyclesDispatcher.dispatch( KeyguardLifecyclesDispatcher.FINISHED_GOING_TO_SLEEP); }
summary
1 can and Bright screen process Learn by comparison.
2. Phonewindowmanager will call startedGoingToSleep, screenTurningOff, screenTurnedOff and finishedGoingToSleep methods in turn
3 when the screen is off, the acquisition of SleepToken and the appearance of Keyguard will cause all activities to be stop ped.
4. Screen capture will be taken before screen out, and then in screen out animation, this screen capture will cover the front of the screen and block all windows until the screen is completely black.