PowerManager Service Analysis-updatePowerStateLocked Method

Posted by MnM333 on Sun, 10 Oct 2021 18:29:09 +0200

1.2. Detailed updatePowerStateLocked method

Next, as discussed above, at the end of the systemReady() method, the updatePowerStateLocked() method is called:

public void systemReady(IAppOpsService appOps) {synchronized (mLock) {
    mSystemReady = true;

UpdatePowerStateLocked()Method is the core method in the whole PMS, and is also the most important method in the whole PMS. It needs to be invoked to update and recalculate the change of the whole power state after executing the operation of application lock, release lock, user event, forced wake-up/sleep, etc. An int value mDirty is used as a flag bit in PMS to judge if the power state changes, when the power state changes.This method is called when there is a change, such as light-off screen, battery state change, dark screen, etc. In this method, other peer methods are called to update, the following are analyzed one by one, see its code first:

private void updatePowerStateLocked() {    
    if (!mSystemReady || mDirty == 0) {      
        }    try {    // Phase 0: Basic state updates.
    //Update battery information
    updateIsPoweredLocked(mDirty);   //Update screen hold wake-up identification value mStayOn
    updateStayOnLocked(mDirty);    //Brightness enhancement correlation
    final long now = SystemClock.uptimeMillis();  
    int dirtyPhase2 = 0; 
    for (;;) {
        int dirtyPhase1 = mDirty;
        dirtyPhase2 |= dirtyPhase1;
        mDirty = 0;        //Update the markup value for statistical wakelock mWakeLockSummary
        updateWakeLockSummaryLocked(dirtyPhase1);//Update statistical userActivity token values mUserActivitySummary and hibernation arrival time
        updateUserActivitySummaryLocked(now, dirtyPhase1);
        //Used to update screen wake-up status, state change returns true
        if (!updateWakefulnessLocked(dirtyPhase1)) {            
    // Phase 2: Update display power state.
    //Interact with Display and request Display status
    boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);    // Phase 3: Update dream state (depends on display ready signal).
    //Update Screen Saver
    updateDreamLocked(dirtyPhase2, displayBecameReady);    // Phase 4: Send notifications, if needed.
    //If wakefulness changes, do the final closing
    finishWakefulnessChangeIfNeededLocked();    // Phase 5: Update suspend blocker.
    // Because we might release the last suspend blocker here, we need to make 
    //surewe finished everything else first!
    //Update Suspend Lock
    } finally {

In the whole method, when the system is not ready or mDirty is not in place, no subsequent steps will be performed to return directly; the content of this method will be analyzed next, and because this method is very important, all the methods will be pasted here.


This method has two main functions:

1.USB plug-in brightness screen entry point;

2. Update the low power mode;

The method is as follows:

* Updates the value of mIsPowered.
* Sets DIRTY_IS_POWERED if a change occurred.
private void updateIsPoweredLocked(int dirty) {
if ((dirty & DIRTY_BATTERY_STATE) != 0) {
//Is it charged
final boolean wasPowered = mIsPowered;
final int oldPlugType = mPlugType;//Charging type
final boolean oldLevelLow = mBatteryLevelLow;
//Is it at low power/*----------------------------------------- BatteryService Interactive Begin-----------------------------*/
mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
mPlugType = mBatteryManagerInternal.getPlugType();
mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();
/*---------------------BatteryService Interactive End---------------------------------*///Charging State Change
if (wasPowered != mIsPowered || oldPlugType != mPlugType) {
    mDirty |= DIRTY_IS_POWERED;    //Whether to connect to wireless charging
    final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
            mIsPowered, mPlugType, mBatteryLevel);  
              final long now = SystemClock.uptimeMillis();    
     //Does plugging the charging cable wake up the screen
    if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, 
              oldPlugType, dockedOnWirelessCharger)) {        //Screen wake-up
              "android.server.power:POWER", Process.SYSTEM_UID,
               mContext.getOpPackageName(), Process.SYSTEM_UID);
    }    //Update user activity
            now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, 
            if (dockedOnWirelessCharger) {
}//Whether or not the last charge is different from the current charge || Whether or not the last charge is low or not the current charge is //low is different
if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {    //Last time at low power & not at low power
    if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) {        //Whether the user has turned off the low power mode when the battery is in the low power mode trigger value
        mAutoLowPowerModeSnoozing = false;
    }    //Update low power mode


This method is mainly used to determine if the system is charged in Settings while keeping the screen bright. The method is as follows:

private void updateStayOnLocked(int dirty) {    
if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) {    
    final boolean wasStayOn = mStayOn;    //Bright screen while charging &&DevicePolicyManager has no maximum shutdown time set
       if (mStayOnWhilePluggedInSetting != 0 && 
            !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {            //Keeping the screen bright depends on charging
            mStayOn = 
        } else {
            mStayOn = false;
        }        if (mStayOn != wasStayOn) {            //mDirty position if mStayOn value changes
            mDirty |= DIRTY_STAY_ON;

In this method, the bool value mStayOn is used as a flag, and mStayOnWhilePluggedInSetting is a value read from SettingsProvider to indicate whether the screen is set to stay on when charging. To make mStayOn true,The prerequisite is that mStayOnWhilePluggedInSetting is true, and DevicePolicyManager does not impose a maximum timeout constraint. If this condition is met, mStayOnis true when the device is charging. Otherwise, it is false.mStayOn is used as a judgment when entering Dream-related operations.


This part of the code triggered in PhoneWindowManager has not been studied specifically and is related to brightness enhancement.

private void updateScreenBrightnessBoostLocked(int dirty) {        
if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) {            
    if (mScreenBrightnessBoostInProgress) {                
        final long now = SystemClock.uptimeMillis();
                if (mLastScreenBrightnessBoostTime > mLastSleepTime) {                    
                final long boostTimeout = mLastScreenBrightnessBoostTime +
                            if (boostTimeout > now) {
                        Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
                        mHandler.sendMessageAtTime(msg, boostTimeout);                        return;
                mScreenBrightnessBoostInProgress = false;
                        PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);


In this method, all current WakeLock locks are counted and all wakelock lock states are filtered (the wakelock lock mechanism is analyzed later).And update the value of mWakeLockSummary to summarize the status of all active wake locks. mWakeLockSummary is an identification value used to record all WakeLock lock states when requesting Display. Most wake locks are ignored when the system is asleep, such as when the system is awakeWhen PowerManager.DOZE_WAKE_LOCK type wake-up locks are ignored, and when the system is in asleep or Doze state, PowerManager.SCREEN_BRIGHT type locks are ignored, etc. This method is as follows:

private void updateWakeLockSummaryLocked(int dirty) {    
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
    mWakeLockSummary = 0;    //Traversing wakelock in waklock collection
    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.PARTIAL_WAKE_LOCK:               
           if (!wakeLock.mDisabled) {                    // We only respect this if the wake lock is not disabled.
                    //If PARTIAL_WAKE_LOCK exists and the wakelock is available,
                    //Record by location, same as below
                    mWakeLockSummary |= WAKE_LOCK_CPU;
          case PowerManager.FULL_WAKE_LOCK:
                mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | 
         case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;               
          case PowerManager.SCREEN_DIM_WAKE_LOCK:
                mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;  
          case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                mWakeLockSummary |= 
          case PowerManager.DOZE_WAKE_LOCK:
                mWakeLockSummary |= WAKE_LOCK_DOZE; 
         case PowerManager.DRAW_WAKE_LOCK:
                mWakeLockSummary |= WAKE_LOCK_DRAW;
    }    // Cancel wake locks that make no sense based on the current state.
    //Here's to remove the meaningless WakeLock in a particular state
    if (mWakefulness != WAKEFULNESS_DOZING) {
     //Remove the wakeLock flag bit if it is not in the Dozing state
        mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
    if (mWakefulness == WAKEFULNESS_ASLEEP
            || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
            //If the current wakeLock lock is Asleep or Doze, the wakeLock lock associated with screen brightness should be removed
        mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | 
               if (mWakefulness == WAKEFULNESS_ASLEEP) {
               //When hibernating, the sensor no longer needs to monitor whether the terminal is close to the object to trigger the screen to go off
            mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
     // Infer implied wake locks where necessary based on the current state.
        //Based on the current state and the WakeLock held by the PMS, an implicit lock requirement is inferred
        //For example, when the PMS holds a bright screen lock WAKE_LOCK_SCREEN_BRIGHT, if the current terminal is awake
        //So obviously the CPU needs to be awake
    if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | 
            WAKE_LOCK_SCREEN_DIM)) != 0) {        //In the awake state, WAKE_LOCK_STAY_AWAKE is only used in the awake state
        if (mWakefulness == WAKEFULNESS_AWAKE) {
            mWakeLockSummary |= WAKE_LOCK_CPU | 
            WAKE_LOCK_STAY_AWAKE;            //In screen saver state (dream)
        } else if (mWakefulness == WAKEFULNESS_DREAMING) {
            mWakeLockSummary |= WAKE_LOCK_CPU;
    }    if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
        mWakeLockSummary |= WAKE_LOCK_CPU;

Combined with the comment information for each WakeLock level, the above code is fairly understandable.
The only reason Android defines an mWakeLockSummary variable is that:
PMS defines WakeLock as request information for different processes that have different requirements for CPU, screen, and keyboard.
For each resource, as long as one application meets the acquisition criteria, the PMS needs to allocate resources for the application to the terminal.
For example: assume that PMS has 20 WakeLock s, only one request is for a bright screen, and 19 only request a CPU wake-up, PMS still needs to keep the terminal bright.
Therefore, mWakeLockSummary provides a capability to integrate multiple WakeLock requests for centralized control by PMS.

1.2.5 updateUserActivitySummaryLocked

updateUserActivitySummaryLocked determines the status of the current screen based on the user's last activity.
This method is used to update the user activity time. When the device and the user interact, the next time they hibernate is calculated based on the current time and the duration of hibernation, the duration of Dim, and the state they are in, thus completing the operation of the user activity timeout. For example, the time from the bright screen to Dim, the time from Dim to the off screen, and the time from the bright screen to the screen saver are the key codes here.As follows (with deletions):

private void updateUserActivitySummaryLocked(long now, int dirty) {    // Update the status of the user activity timeout timer.
    long nextTimeout = 0;    //This method will not be executed if it is dormant
    if (mWakefulness == WAKEFULNESS_AWAKE
            || mWakefulness == WAKEFULNESS_DREAMING
            || mWakefulness == WAKEFULNESS_DOZING) {        
            //The time it takes for the device to fully enter hibernation, which is -1 to disable, default -1
        final int sleepTimeout = getSleepTimeoutLocked();     
         //User timeout, which is the amount of time spent inactive in hibernation or screensaver, except in exceptional cases
        final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);       
         //Dim duration, i.e. how long to sleep when the screen is bright and dark
        final int screenDimDuration =  
          getScreenDimDurationLocked(screenOffTimeout);        //User interaction through WindowManager
        final boolean userInactiveOverride = 
        mUserActivitySummary = 0;        //1. Bright Screen; 2. User Activity After Bright Screen
        if (mLastUserActivityTime >= mLastWakeTime) {            
        //Next Sleep Time = Last User Activity Time + Sleep Time - Dim Time
            nextTimeout = mLastUserActivityTime
                + screenOffTimeout - screenDimDuration;        //If the current time is less than the next screen timeout, indicating that the device is in the bright state at this time, set the user activity state to USER_ACTIVITY_SCREEN_BRIGHT, which represents the bright screen
            if (now < nextTimeout) {
                mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
            } else {   //If the current time is greater than the next activity time, there should be two situations at this time: already dormant and Dim
                nextTimeout = mLastUserActivityTime + screenOffTimeout;                //If the current time is less than the last active time + screen timeout, this value is about 3s, indicating that the device is in Dim state at this time, then set the user active state to USER_ACTIVITY_SCREEN_DIM representing Dim
                if (now < nextTimeout) {
                    mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
        ...........................................................        //Send a timer Handler and updatePowerStateLocked() again after the arrival time
        if (mUserActivitySummary != 0 && nextTimeout >= 0) {
            Message msg = 
                 mHandler.sendMessageAtTime(msg, nextTimeout);
         } else {
          mUserActivitySummary = 0;

When acquiring a user's activity timeout, it is not only determined by the amount of hibernation that the user has set in the settings, but also by the amount of wakelock locks marked with PowerManager.ON_AFTER_RELEASE that affect the user's timeout when released. Only one of the most common types of code listed above is the code logic from the user's highlight to the time of arrival.The device is set to sleep for 15 seconds, Dim for 3 seconds, and I press the power key to wake up the device at 9:20:01, so when this method is executed, there are:

mLastUserActivity=mLastWakeTime=9:20:01,now=9:20:01+0.02ms,screenOffTimeout=15s,screenDimDuration=3s,therefore nextTimeout For 9:20:01+15s-3s=9:20:13

So a timed message will be sent through the Handler, and after 13 seconds it will enter Dim...

nextTimeout = mLastUserActivity + screenOffTimeout =9:20:01+15s=9:20:16 > now

So judging that the current Dim state, while the nextTimeout changes, and sets the timer message again through Handler,..., after 3s, it goes back to the method for processing, this time, by judging that the nextTimeout is set to -1, so that the handler is no longer sent and hibernates through other methods in updatePowerStateLocked().
After calculating the nextTimeout, a delay message is sent through the Handler, and the entire power status is updated again after reaching the nextTimeout:

private final class PowerManagerHandler extends Handler {        
    public PowerManagerHandler(Looper looper) {            
    super(looper, null, true /*async*/);
        public void handleMessage(Message msg) {            
        switch (msg.what) {                                   			
 private void handleUserActivityTimeout() { 
      // runs on handler thread
    synchronized (mLock) {        
        if (DEBUG_SPEW) {
            Slog.d(TAG, "handleUserActivityTimeout");
        mDirty |= DIRTY_USER_ACTIVITY;

In addition, there is one point to note here that when calculating the extinction timeout, there are two values:

final int sleepTimeout = getSleepTimeoutLocked();
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);

These two methods are related to sleep time, and in PMS, two values are defined:

mSleepTimeoutSetting = Settings.Secure.getIntForUser(resolver,
mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,

Settings.Secure.SLEEP_TIMEOUT represents the time the device has fully entered the post-sleep screensaver after a period of inactivity. This value can be interpreted as the maximum or upper limit for waking up or screensaver and is greater than Settings.System.SCREEN_OFF_TIMEOUT.The default is -1, meaning this feature is disabled. Settings.System.SCREEN_OFF_TIMEOUT indicates the time a device enters sleep or screensaver after a period of inactivity, also known as the user activity timeout, but the screen does not have to turn off when it expires. This value can be set in Settings-Hibernate.

1.2.6.for(;); loop and updateWakefulness Locked ()

In the updatePowerStateLocked() method, an infinite loop is set, and both methods of the above analysis are executed in an infinite loop. Why design an infinite loop is related to the implementation within its loop? Next, analyze its contents one by one. The for loop code is as follows:

for (;;) {    int dirtyPhase1 = mDirty;
    dirtyPhase2 |= dirtyPhase1;
    mDirty = 0;    
    //Summarize wakelock
    //Summary useractivity
    updateUserActivitySummaryLocked(now, dirtyPhase1);    
    if (!updateWakefulnessLocked(dirtyPhase1)) {        

The summary wakelock and useractivity methods have been analyzed earlier, so there is a key method here: updateWakefulness Locked(), which is the key to exit the loop. If this method returns false,Then the loop ends, and if it returns true, the next cycle occurs, so what does the return value of this method mean? Let's continue to look at this method:

private boolean updateWakefulnessLocked(int dirty) {    
    boolean changed = false;    
        | DIRTY_DOCK_STATE)) != 0) {   //Keep the current screen awake &&The device is about to exit the wake-up state (Sleep or Screen Saver)
           if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
               Slog.d(TAG, "updateWakefulnessLocked: Bed time...");              
                final long time = SystemClock.uptimeMillis();        //Whether to enable the screen saver during hibernation
               if (shouldNapAtBedTimeLocked()) {                     //Enter the screen saver and return to true
                  changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
                  } else {                                           //Go to sleep, return to true
                     changed = goToSleepNoUpdateLocked(time,
                     PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, 
       }    return changed;

This method is used to update the wakefulness of the device, and it is also the decision point of the bright screen->screen saver/sleep. wakefulness is a value used to represent the current state of the device. There are four system-defined wakefulness values representing different states:

//Sleep state, when off screen
public static final int WAKEFULNESS_ASLEEP = 0;
//Screen light
public static final int WAKEFULNESS_AWAKE = 1;
//Screen saver
public static final int WAKEFULNESS_DREAMING = 2;
//When in DOZE mode
public static final int WAKEFULNESS_DOZING = 3;

If the current device is in a wake state and will exit the wake state, that is, into a sleep state or a dreaming state, if the device is switched on, into a screen saver state, or directly into a sleep state. In this case, wakefulness changes, so the return value is true,The wakelockSummary and userActivitySummary need to be recomputed through the next cycle. If they are not, then the if statement will not be entered, indicating that there is no need to change the wakefulness value and return false, then the loop will execute only once and exit. Therefore, the cycle will execute twice only after a period of inactivity reaches the user's screen saver or when he enters sleep after a time-out.In other cases, only one execution will exit, such as pressing the power key to extinguish the screen only once, because when the power key is extinguished, the wakefulness value has changed from wake-up state to SLEEP state, so the execution condition is not satisfied.

Now that you know the main functions of the updatefulnessLocked() method, let's look at the methods associated with hibernation and screen savers. First, look at the isItBedTimeYetLocked() method, which determines if the current device is going to go to sleep. The return value is the inverse of the isBeKeptAwakeLocke() method, which is mStayOn (whether the screen is always bright)., wakelockSummary, userActivitySummary, mProximityPositive, etc. Decide that if one of them is true, you will not be able to go to sleep, that is, to satisfy going to sleep, the relevant attribute values are false. isBeKeptAwakeLocke() is as follows:

private boolean isBeingKeptAwakeLocked() {
return mStayOn//Whether the screen stays on
    || mProximityPositive//true when approaching sensor near screen
    //In awake state
    || (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
    //Screen in bright or dim state
    || (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
            | USER_ACTIVITY_SCREEN_DIM)) != 0            
    || mScreenBrightnessBoostInProgress;//In Brightness Enhancement}

Next, take a look at the shoudNapAtBedTimeLocked() method, which is used to determine if a device enters screen saver mode:

private boolean shouldNapAtBedTimeLocked() {//Whether the screen saver turns on return mDreams ActivateOnSleepSetting
    || (mDreamsActivateOnDockSetting //Whether to turn on the screen saver when inserting the base
            && mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED);

In addition to the above methods, there are napNoUpdateLocked() and goToSleepNoUpdateLocked() methods, which control the device to enter the screen saver or hibernate, respectively, and will be analyzed in specific scenarios.

Combining the analysis of the three methods mentioned above, the three methods, updateWakeLockSummaryLocked(), updateUserActivitySummaryLocked(), updateWakefulnessLocked(), are put in for(;);Called in a loop because they together determine the state of the device. The first two methods summarize the state, and the second method determines whether to change the current device wake-up state based on the values summarized by the first two methods.The summary state is affected by mWakefulness and therefore recycles. At the same time, the for loop only executes twice when the screen goes out of time to sleep or the screen saver, and in other cases only once.

Topics: Android