You can use the Power button, USB flash drive, or call…… to light up the screen , although the way is different, but as long as the launch of bright screen, its process is the same. The wakeUp() method is provided in PowerManager for other components or applications to light up the screen, so we’ll start with this method.

/ * * *@paramTime Screen time *@paramReason The screen is on *@param*/
public void wakeUp(long time, @WakeReason int reason, String details) {
    try {
        mService.wakeUp(time, reason, details, mContext.getOpPackageName());
    } catch (RemoteException e) {
        throwe.rethrowFromSystemServer(); }}Copy the code

After calling wakeUp() in PowerManager, the PMS#wakeUp() method is directly called. After checking permissions, wakeUpInternal() is called to enter the PMS internal process:

// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private void wakeUpInternal(long eventTime, @WakeReason int reason, String details, int uid,
        String opPackageName, int opUid) {
    synchronized (mLock) {
        // Perform the screen lighting process
        if (wakeUpNoUpdateLocked(eventTime, reason, details, uid, opPackageName, opUid)) {
            // Update all statusupdatePowerStateLocked(); }}}Copy the code

In this method:

  • First, callwakeUpNoUpdateLocked()Methods;
  • Then, based on the call return value, determine whether to update the global state;

1. WakeUpNoUpdateLocked () validates and illuminates status updates

This method is the main method to light up the screen. If the screen is lit successfully, this method returns true and updates the global status. If the screen is not lit up, this method returns false, indicating that the screen failed to light up:

// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private boolean wakeUpNoUpdateLocked(long eventTime, @WakeReason int reason, String details,
        int reasonUid, String opPackageName, int opUid) {
    // The screen is on before the last time when the screen is off, the screen is on, the system is not started, or suspend is mandatory
    if(eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE || ! mBootCompleted || ! mSystemReady || mForceSuspendActive) {return false;
    }
 
    try {
        mLastWakeTime = eventTime;  // Update the last screen light time
        mLastWakeReason = reason;   // Update the cause of the screen light
        // Update mWakefulness
        setWakefulnessLocked(WAKEFULNESS_AWAKE, reason, eventTime);
        // Notify other components to light up
        mNotifier.onWakeUp(reason, details, reasonUid, opPackageName, opUid);
        // Update user activity time
        userActivityNoUpdateLocked(
                eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return true;
}
Copy the code

First, verify the screen lighting time and status. If any of the following three conditions are met, the screen will not be lit successfully and false is returned. After the verification is complete, the screen lighting process begins:

  • The time when the screen is on is shorter than the time when the screen is off last time.
  • The wakeup state is already on;
  • System startup is not complete or suspend is forced.

Next, mLastWakeTime and mLastWakeReason are updated to indicate when and why the screen was last lit. The setWakefulnessLocked() method is then called to set the value representing the PMS wakefulness state, mWakefulness. Finally, execute userActivityNoUpdateLocked update user activity time () method.

1.1. SetWakefulnessLocked () updates the wake state

// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
    if(getWakefulnessLocked() ! = wakefulness) {/ / update the mWakefulness
        mWakefulnessRaw = wakefulness;
        mWakefulnessChanging = true;
        mDirty |= DIRTY_WAKEFULNESS;
        mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING);
        // mNotifier starts the mWakefuless transition
        if(mNotifier ! =null) {
            mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
        }
        // Notifies the mAttentionDetector of system status changesmAttentionDetector.onWakefulnessChangeStarted(wakefulness); }}Copy the code

The value of mWakefulnessRaw is set to WAKEFULNESS_AWAKE, indicating that the screen state is Awake. Then through Notifier# onWakefulnessChangeStarted () method to screen state began to change the cut off but not completed work (e.g., kill bright screen broadcast).

1.2. Notifier# onWakefulnessChangeStarted ()

// frameworks/base/services/core/java/com/android/server/power/Notifier.java

    public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
        // Whether the state is interactive
        final booleaninteractive = PowerManagerInternal.isInteractive(wakefulness); .if(mInteractive ! = interactive) {// Finish up late behaviors if needed.
            if(mInteractiveChanging) { handleLateInteractiveChange(); }...// Update the interaction status
            mInteractive = interactive;
            mInteractiveChangeReason = reason;
            mInteractiveChangeStartTime = eventTime;
            // The interaction state begins to change
            mInteractiveChanging = true;
            // Perform the state change early taskhandleEarlyInteractiveChange(); }}Copy the code

The mInteractive value is first updated to indicate whether the system is interactive, and the interaction status is set to the Input module. When the PMS is Awake or Dreaming, the PMS is considered to be interactive. Then call handleEarlyInteractiveChange () method, its early task after the change of state.

1.3. HandleEarlyInteractiveChange interact () early task after the change of state

// frameworks/base/services/core/java/com/android/server/power/Notifier.java

    private void handleEarlyInteractiveChange(a) {
        synchronized (mLock) {
            if (mInteractive) {  // Interactive state
                // run on the system_server main thread
                mHandler.post(new Runnable() {
                    @Override
                    public void run(a) {
                        final int why = translateOnReason(mInteractiveChangeReason);
                        // Notify PhoneWindowManager to start lighting upmPolicy.startedWakingUp(why); }});// Indicates which interaction state is changing
                mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
                // Indicates that a bright broadcast will be sent
                mPendingWakeUpBroadcast = true;
                // Send a broadcast that lights up
                updatePendingBroadcastLocked();
            } else {
                // Going to sleep.... }}}Copy the code

MInteractive is true when the screen is on, so call PhoneWindowManager#startedWakingUp(), which tells components to lock the screen. This call is made on the system_server main thread. Then through updatePendingBroadcastLocked () method to send bright screen broadcast.

1.4. UpdatePendingBroadcastLocked () sends bright screen broadcast

This method is responsible for sending the on-off screen broadcast:

// frameworks/base/services/core/java/com/android/server/power/Notifier.java

    private void updatePendingBroadcastLocked(a) {
        if(! mBroadcastInProgress && mPendingInteractiveState ! = INTERACTIVE_STATE_UNKNOWN && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast || mPendingInteractiveState ! = mBroadcastedInteractiveState)) { mBroadcastInProgress =true;                         // Indicates that a broadcast is being sent
            mSuspendBlocker.acquire();                           // Apply SuspendBlocker to prevent CPU hibernation
            Message msg = mHandler.obtainMessage(MSG_BROADCAST); // In system_server, the process of sending a broadcast screen is displayed
            msg.setAsynchronous(true); mHandler.sendMessage(msg); }}Copy the code

Conditions are judged to confirm whether the conditions for sending a broadcast are met. The meanings of these conditions are as follows:

  • MBroadcastInProgress: Indicates whether broadcasts are being sent.
  • MPendingInteractiveState: INTERACTIVE_STATE_UNKNOWN: the default value, INTERACTIVE_STATE_AWAKE: on-screen broadcast, INTERACTIVE_STATE_ASLEEP: off-screen broadcast.
  • MBroadcastedInteractiveState: according to current state of the radio value;
  • MPendingWakeUpBroadcast: a bright screen broadcast is to be sent.
  • Broadcast mPendingGoToSleepBroadcast: what will send out the screen.

After entering this method, you first apply for a SuspendBlocker lock to avoid a broadcast transmission failure when the CPU goes to sleep. A broadcast is then sent by calling sendNextBroadcaset() in the Handler:

// frameworks/base/services/core/java/com/android/server/power/Notifier.java

    private void sendNextBroadcast(a) {
        final int powerState;
        synchronized (mLock) {
            // First execution
            if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
                ......
            } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
                // If the current broadcast status is INTERACTIVE_STATE_AWAKE, an off-screen broadcast may be sent
                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                        || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
                    mPendingGoToSleepBroadcast = false;
                    mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
                } else {
                    // End the broadcast transmission
                    finishPendingBroadcastLocked();
                    return; }}else {// If the current broadcast status is INTERACTIVE_STATE_ASLEEP, the screen is lit
                if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                        || mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
                    mPendingWakeUpBroadcast = false;
                    / / update mBroadcastedInteractiveState values
                    mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
                } else {
                    // End The broadcast is sent
                    finishPendingBroadcastLocked();
                    return;
                }
            }

            powerState = mBroadcastedInteractiveState;
        }

        if (powerState == INTERACTIVE_STATE_AWAKE) {
            // Send a broadcast that lights up
            sendWakeUpBroadcast();
        } else {
            // Send an off-screen broadcastsendGoToSleepBroadcast(); }}Copy the code

Finally, using the sendWakeUpBroadcast() method, send a bright-screen broadcast:

// frameworks/base/services/core/java/com/android/server/power/Notifier.java

private void sendWakeUpBroadcast(a) {
    // Send intent.action_screen_on broadcast
    if (mActivityManagerInternal.isSystemReady()) {
        mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
                mWakeUpBroadcastDone, mHandler, 0.null.null); }... }Copy the code

MWakeUpBroadcastDone specifies a mWakeUpBroadcastDone, which will receive the broadcast as the last broadcast receiver after the broadcast is sent. Continues to perform in the mWakeUpBroadcastDone sendNextBroadcast () method, in the execution, according to the condition is executed inishPendingBroadcastLocked () method:

private void finishPendingBroadcastLocked(a) {
    // Reset mBroadcastInProgress, which indicates that no broadcasts are currently being sent
    mBroadcastInProgress = false;  
    // Release SuspendBlocker lock
    mSuspendBlocker.release();  
}
Copy the code

In this way, the transmission of the bright screen broadcast is completed.

1.5. UserActivityNoUpdateLocked update user interaction time ()

Back to wakeUpNoUpdateLocked () method, setWakefulnessLocked () after the execution, execution userActivityNoUpdateLocked () method, this method is used to update the system interact with the user last time, Depending on this time, you can decide when to automatically sleep. For details, see the automatic screen off process.

WakeUpNoUpdateLocked () completes and returns true, and the updatePowerStateLocked() method is executed.

2. UpdatePowerStateLocked () Updates the PMS global status

This method in the first article has been analyzed, here of one of the key operations only see the bright screen, perform updateDisplayPowerStateLocked () method.

2.1. UpdateDisplayPowerStateLocked () to the DMS by request

All of the request data in the PMS is encapsulated in a DisplayPowerRequest object that makes a request to the DMS. When a request is received in the DMS, the Display state and brightness are updated in the DisplayPowerController and the request result is returned to the PMS. The request processing logic in DisplayPowerController is as follows:

public boolean requestPowerState(DisplayPowerRequest request,
        boolean waitForNegativeProximity) {
 
    synchronized (mLock) {
        boolean changed = false;
         // Whether to wait for the PSensor to report the away event
        if(waitForNegativeProximity && ! mPendingWaitForNegativeProximityLocked) { mPendingWaitForNegativeProximityLocked =true;
            changed = true;
        }
 
        // Determine if it is a new request
        if (mPendingRequestLocked == null) {
            mPendingRequestLocked = new DisplayPowerRequest(request);
            changed = true;
        } else if(! mPendingRequestLocked.equals(request)) { mPendingRequestLocked.copyFrom(request); changed =true;
        }
 
        if (changed) {
            mDisplayReadyLocked = false;
        }
 
        // Start processing requests
        if(changed && ! mPendingRequestChangedLocked) { mPendingRequestChangedLocked =true;
            sendUpdatePowerStateLocked();
        }
        // returns to the PMS to indicate whether the request has been processed
        returnmDisplayReadyLocked; }}Copy the code

In this method, it checks whether the DisplayPowerRequest object in the request is the same as the DisplayRequest object in the last request. If it is different, it starts processing the new request and returns mDisplayReadyLocked to the PMS. This value indicates whether the request is completed in the DMS.

When the request is processed, mDisplayReadyLocked is set to true, and the PMS#onStateChanged() method is called back to notify the PMS that the update is complete. After this step, the system brightness and display status are all set, and the screen is already on. For a detailed analysis of brightness and display status, see the DMS process in the Android R DisplayManagerService module (3).

2.2. FinishWakefulnessChangeIfNeededLocked () when awakened state changes to complete tasks

Back to updatePowerStateLocked () method, when the DMS processing request is completed, and return to request the results, perform finishWakefulnessChangeIfNeededLocked () method, carries on the screen state change after the completion of the operation:

    private void finishWakefulnessChangeIfNeededLocked(a) {
        // System state wakefulness is processed through Notifier
        if (mWakefulnessChanging && mDisplayReady) {
            if (getWakefulnessLocked() == WAKEFULNESS_DOZING
                    && (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
                return; 
            } else {
                mDozeStartInProgress = false;
            }
            // The wake state change is complete
            mWakefulnessChanging = false; mNotifier.onWakefulnessChangeFinished(); }}Copy the code

Here will perform Notifier# onWakefulnessChangeFinished () method, notify the Notifier awakened state changes, after the completion of interactive state related tasks.

2.3. Notifier# onWakefulnessChangeFinished ()

// frameworks/base/services/core/java/com/android/server/power/Notifier.java

    public void onWakefulnessChangeFinished(a) {
        // Set mInteractiveChanging to false to indicate that the interaction state is also changed
        if (mInteractiveChanging) {
            mInteractiveChanging = false;
            // Process the task after completing the interaction state changehandleLateInteractiveChange(); }}Copy the code

Here will now reset mInteractiveChanging value to false, said interactive status change has been completed, the next execution handleLateInteractiveChange () method.

2.4. HandleLateInteractiveChange () interact state changes after the completion of the task

HandleLateInteractiveChange () method and handleEarlyInteractiveChange () method should be relatively, a processing interaction state changes after the early work, a late after the change of interaction condition:

// frameworks/base/services/core/java/com/android/server/power/Notifier.java

    private void handleLateInteractiveChange(a) {
        synchronized (mLock) {
            if (mInteractive) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run(a) {
                        // Notify PhoneWindowManager that the screen is litmPolicy.finishedWakingUp(why); }}); }else {
                // Process in non-interactive state. }}}Copy the code

In the system_server main thread, notify PhoneWindowManager that the screen has been lit.

3. Summary

The key steps are as follows:

  1. Update PMS wake up status;
  2. Update interaction status;
  3. The system_server main thread calls PhoneWindowManager#startedWakingUp() to notify WMS that the screen starts to light up.
  4. System_server main thread sends a screen light broadcast;
  5. Request Display status and brightness from DMS;
  6. After the DMS returns the request status, the system_server main thread calls PhoneWindowManager#finishedWakingUp() to notify the WMS module that the screen has been turned on.

The sequence diagram of the whole process is as follows: