Preface
Analysis of the screen brightening process of PowerManagerServiceThe process of lighting the screen is analyzed and a general process suitable for lighting the screen or extinguishing the screen is summarized. However, there are some unique things in the screen decompression process, such as the obscure thing dream, which is started in the screen decompression process.
The screen is divided into manual screen and automatic screen. Manual screen extinguishing generally refers to the Power key screen extinguishing. Automatic screen extinguishing is what people often call the screen extinguishing caused by screen timeout. This article uses the Power key to remove the screen as an example to analyze the manual removal of the screen, and automatically remove the screen and leave it to the next article for analysis.
This articleAnalysis of the screen brightening process of PowerManagerServiceAs a basis, do not do too much analysis of the repetitive content. I hope readers must lay a solid foundation first before reading this article.
1. Screen decompression process
The Power key will be called when the screen is deactivated.PowerManagerService#goToSleep()
// @Override // Binder call public void goToSleep(long eventTime, int reason, int flags) { // ... try { sleepDisplayGroup(Display.DEFAULT_DISPLAY_GROUP, eventTime, reason, flags, uid); } } private void sleepDisplayGroup(int groupId, long eventTime, int reason, int flags, int uid) { synchronized (mLock) { // 1. Update wakefulness if (sleepDisplayGroupNoUpdateLocked(groupId, eventTime, reason, flags, uid)) { // 2. Update power status updatePowerStateLocked(); } } }
A very familiar process, update wakefulness first, and then update the power status.
However, the wakefulness process of Power keys to shut down screen is a little bit like this, as follows
private boolean sleepDisplayGroupNoUpdateLocked(int groupId, long eventTime, int reason, int flags, int uid) { // ... try { // ... // Summoning the sleeping spirit is actually to save a state (groupId, true); // Update wakefulness to WAKEFULNESS_DOZING setWakefulnessLocked(groupId, WAKEFULNESS_DOZING, eventTime, uid, reason, /* opUid= */ 0, /* opPackageName= */ null, /* details= */ null); // If flags have PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, update wakefulness to WAKEFULNESS_ASLEEP if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) { reallySleepDisplayGroupNoUpdateLocked(groupId, eventTime, uid); } } return true; }
By default, wakefulness is updated to WAKEFULNESS_DOZING, however, wakefulness is updated to WAKEFULNESS_ASLEEP if the parameter flags has PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE.
wakefulness indicates what state the device is in. In fact, it has four values, as follows
public abstract class PowerManagerInternal { /** * Wakefulness: The device is asleep. It can only be awoken by a call to wakeUp(). * The screen should be off or in the process of being turned off by the display controller. * The device typically passes through the dozing state first. */ public static final int WAKEFULNESS_ASLEEP = 0; /** * Wakefulness: The device is fully awake. It can be put to sleep by a call to goToSleep(). * When the user activity timeout expires, the device may start dreaming or go to sleep. */ public static final int WAKEFULNESS_AWAKE = 1; /** * Wakefulness: The device is dreaming. It can be awoken by a call to wakeUp(), * which ends the dream. The device goes to sleep when goToSleep() is called, when * the dream ends or when unplugged. * User activity may brighten the screen but does not end the dream. */ public static final int WAKEFULNESS_DREAMING = 2; /** * Wakefulness: The device is dozing. It is almost asleep but is allowing a special * low-power "doze" dream to run which keeps the display on but lets the application * processor be suspended. It can be awoken by a call to wakeUp() which ends the dream. * The device fully goes to sleep if the dream cannot be started or ends on its own. */ public static final int WAKEFULNESS_DOZING = 3; }
Although the comments have been written in detail, you may not know some concepts. I will describe these four device statuses in an ugly way.
- WAKEFULNESS_ASLEEP: Indicates that the device is in sleep state. The screen is in the state of de-screen or is in the process of de-screen. The equipment can only bewakeup()Wake up, for example, the Power key wakes up the device.
- WAKEFULNESS_AWAKE: Indicates that the device is in a wake-up state. The screen is in a state of light or dark. When the user's behavior timed out (screen timed out), the device may turn on the dream (referring to screen saver) or enter a dormant state. certainlygoToSleep()It can also make the device sleep.
- WAKEFULNESS_DREAMING: The device is in a dream state, which refers to the display screensaver here. Can be passedwakeup()End the screen saver and wake the device, such as clicking the screen saver. Can also be passedgoToSleep()End the screen saver and put the device into hibernation, for example, press the Power key during the screen saver.
- WAKEFULNESS_DOZING: The device is dozing. This state is almost a sleep state, but the screen is in a low power state. The system will ask the dream manager to start a doze component, which will draw some simple information on the screen, but the premise is that the screen must support the AOD (always on display) function. I once bought a mobile phone with an OLED screen. When the screen is turned off, the screen will display time, notification icons, and other information. I thought it was quite cool at that time. In fact, this is the implementation of the AOD function. If the doze component fails to start, the device goes to sleep. Can be passedwakeup()End this dozing state, leaving the device in a wake state, for example, the Power key is on.
OK, let's go back to the topic. We just analyzed that when the Power key turns off the screen, depending on the parameter flags, wakefulness may be updated to WAKEFULNESS_DOZING or WAKEFULNESS_ASLEEP, which means that the device enters a dozing or hibernation state.
The process of the device entering a dormant state is consistent with the process of the device lighting up in the previous article, and the process is simpler. Please analyze it yourself. This article analyzes the process of the device entering a dormant state.
2. The device enters a dozing state
According to the analysis just now, wakefulness is updated to WAKEFULNESS_DOZING, causing the device to enter a dozing state. And according to the previous article, we can see that at this time mDirty sets the DIRTY_DISPLAY_GROUP_WAKEFULNESS and DIRTY_WAKEFULNESS mark bits, respectively representing the wakefulness change of the display packet and the wakefulness change of the PowerManagerService, which actually means the device status change.
Now update the power status according to mDirty
// private void updatePowerStateLocked() { if (!mSystemReady || mDirty == 0) { return; } if (!(mLock)) { (TAG, "Power manager lock was not held when calling updatePowerStateLocked"); } (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 = (); 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.TRACE_TAG_POWER); } }
According to the previous article, it can be seen that there are many functions included, but the steps related to the Power key screen deactivation process are as follows
- updateUserActivitySummaryLocked()Update user behavior. One of the factors that affect screen request policies is user behavior. See [2.1 Update user behavior】
- updateDisplayPowerStateLocked()Update the power state of the display, which will initiate a power request to the DisplayManagerService, thereby determining the status of the screen, such as light, off, dark, etc. See [2.2 Update the power status of the display】
- updateDreamLocked()Updating the dream state is actually to start the doze component through the dream manager and then update the dream state of the PowerManagerService. See [2.3 Updated Dream State】
Both the screensaver and the doze components are started by the dream manager. In PowerManagerService, the screensaver is called dream and the doze component is called doze dream.
2.1 Update user behavior
// private void updateUserActivitySummaryLocked(long now, int dirty) { // ... // traversal display group id for (int groupId : ()) { int groupUserActivitySummary = 0; long groupNextTimeout = 0; // Note that the dormant state cannot determine the user's behavior if ((groupId) != WAKEFULNESS_ASLEEP) { final long lastUserActivityTime = (groupId); final long lastUserActivityTimeNoChangeLights = ( groupId); // 1. Get user behavior and timeout time // The last user behavior time >= The last time the screen was awakened if (lastUserActivityTime >= mLastWakeTime) { groupNextTimeout = lastUserActivityTime + screenOffTimeout - screenDimDuration; if (now < groupNextTimeout) { // There is no time to dim groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT; } else { groupNextTimeout = lastUserActivityTime + screenOffTimeout; if (now < groupNextTimeout) { // In dim time period groupUserActivitySummary = USER_ACTIVITY_SCREEN_DIM; } } } // ... } // 2. DisplayGroupPowerStateMapper Saves user behavior (groupId, groupUserActivitySummary); } } // traversal display group id ends // ... // 3. Regularly update power status // This step decides to automatically shut down the screen if (hasUserActivitySummary && nextTimeout >= 0) { scheduleUserInactivityTimeout(nextTimeout); } }
Updating user behavior is actually to save user behavior by DisplayGroupPowerStateMapper. What we analyze now is that the Power key causes the screen to go from lit to quit, so the user behavior obtained here is USER_ACTIVITY_SCREEN_BRIGHT. If it is a process from dark to extinction, then the user behavior is USER_ACTIVITY_SCREEN_DIM.
So, do you have any doubts that the system is entering a dozing state, why the user behavior is USER_ACTIVITY_SCREEN_BRIGHT or USER_ACTIVITY_SCREEN_DIM, which are not user behaviors that are deactivated. Because the system does not define the user behavior of shutting down the screen at all.
All user behaviors are as follows
private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0; private static final int USER_ACTIVITY_SCREEN_DIM = 1 << 1; private static final int USER_ACTIVITY_SCREEN_DREAM = 1 << 2;
There are only three types of user behaviors: the screen becomes brighter, dimmed, or enters the screen saver, and there is no user behavior of dozing off at all. So why is this so?
Although wakefulness is WAKEFULNESS_DOZING at this time, it just means that you are entering a dozing state and you are actually not officially in a dozing state. The sign that the system really enters a doze state is that the dream manager successfully starts the doze component and obtains the wake-up lock.PowerManager.DOZE_WAKE_LOCK. Therefore, it is difficult to define a dozing user behavior.
2.2 Update the power status of the display
According to the previous article, updating the power state of the display is actually to initiate a request to the DisplayManagerService, and the request policy is to truly determine the screen state (light, turn off, dark, etc.).
The method of obtaining the request policy is as follows
// int getDesiredScreenPolicyLocked(int groupId) { final int wakefulness = (groupId); final int wakeLockSummary = (groupId); if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) { return DisplayPowerRequest.POLICY_OFF; } else if (wakefulness == WAKEFULNESS_DOZING) { // The following conditions indicate that the dream manager has obtained the PowerManager.DOZE_WAKE_LOCK wake-up lock if ((wakeLockSummary & WAKE_LOCK_DOZE) != 0) { return DisplayPowerRequest.POLICY_DOZE; } // mDozeAfterScreenOff defaults to false // However, it can be set to true by SystemUI, indicating that the screen is first turned off and then enters the doze state if (mDozeAfterScreenOff) { return DisplayPowerRequest.POLICY_OFF; } } if (mIsVrModeEnabled) { return DisplayPowerRequest.POLICY_VR; } if ((wakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0 || !mBootCompleted || ((groupId) & USER_ACTIVITY_SCREEN_BRIGHT) != 0 || mScreenBrightnessBoostInProgress) { return DisplayPowerRequest.POLICY_BRIGHT; } return DisplayPowerRequest.POLICY_DIM; }
Although the wakefulness is WAKEFULNESS_DOZING, the user behavior is still determined to request the policy at this time. According to the analysis just now, the user behavior at this time is USER_ACTIVITY_SCREEN_BRIGHT or USER_ACTIVITY_SCREEN_DIM, so the policy is DisplayPowerRequest.POLICY_BRIGHT or DisplayPowerRequest.POLICY_DIM. That is to say, the screen status continues to remain unchanged.
Seeing this, my friends and I were shocked! The current situation is clearly that the Power key is deactivated, but why the current analysis result is that the screen status continues to remain unchanged. You read it right, and I didn't write it wrong. We just mentioned that the device is not officially dozing because doze dream has not been started yet. When doze dream is successfully started, the dream manager will obtain the wake-up lock.PowerManager.DOZE_WAKE_LOCK, when PowerManagerService updates the power status again, the policy will be updated toDisplayPowerRequest.POLICY_DOZE, it will put the screen into a doze state and enable the AOD function.
If you don't want to keep the screen state unchanged temporarily when the screen is turned off, you canmDozeAfterScreenOffSet to true, which causes the request policy to be updated toDisplayPowerRequest.POLICY_OFF, that is, let the screen go to sleep immediately.
2.3 Updated Dream State
We have been stressing that the device really goes into doze after starting the doze dream. The startup process of doze dream is during the process of updating the dream state
// private void updateDreamLocked(int dirty, boolean displayBecameReady) { if ((dirty & (DIRTY_WAKEFULNESS | DIRTY_USER_ACTIVITY | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_ATTENTIVE | DIRTY_WAKE_LOCKS | DIRTY_BOOT_COMPLETED | DIRTY_SETTINGS | DIRTY_IS_POWERED | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE | DIRTY_BATTERY_STATE)) != 0 || displayBecameReady) { if (()) { // The final call handleSandman() scheduleSandmanLocked(); } } } private void handleSandman(int groupId) { // runs on handler thread // Handle preconditions. final boolean startDreaming; final int wakefulness; synchronized (mLock) { mSandmanScheduled = false; final int[] ids = (); if (!(ids, groupId)) { // Group has been removed. return; } wakefulness = (groupId); if ((wakefulness == WAKEFULNESS_DREAMING || wakefulness == WAKEFULNESS_DOZING) && (groupId) && (groupId)) { // 1. Decide whether to start the dream // canDreamLocked() indicates whether to start the screen saver in the dream // canDozeLocked() indicates whether to start the doze component in the dream. The judgment condition is that wakefulness is WAKEFULNESS_DOZING startDreaming = canDreamLocked(groupId) || canDozeLocked(); // Reset the "Summoning Sleeping Elf" state (groupId, false); } else { startDreaming = false; } } final boolean isDreaming; if (mDreamManager != null) { // Restart the dream whenever the sandman is summoned. if (startDreaming) { (false /*immediate*/); // 2. Start the dream doze component (wakefulness == WAKEFULNESS_DOZING); } // Determine whether it is being started isDreaming = (); } else { isDreaming = false; } mDozeStartInProgress = false; synchronized (mLock) { final int[] ids = (); if (!(ids, groupId)) { return; } if (startDreaming && isDreaming) { // ... } if ((groupId) || (groupId) != wakefulness) { return; // wait for next cycle } // Determine whether the dream should continue. long now = (); if (wakefulness == WAKEFULNESS_DREAMING) { // ... } else if (wakefulness == WAKEFULNESS_DOZING) { // 3. The doze component of the dream is being activated, then continue if (isDreaming) { return; // continue dozing } // 4. The startup is not successful, or the doze component ends the dream by itself and enters the update wakefulness for WAKEFULNESS_ASLEEP process // Doze has ended or will be stopped. Update the power state. reallySleepDisplayGroupNoUpdateLocked(groupId, now, Process.SYSTEM_UID); updatePowerStateLocked(); } } // ... }
The process of updating the dream state is as follows
- Determine whether you can enter a dream. Dreams actually have two functions, one is a screensaver and the other is a doze component. Since wakefulness is WAKEFULNESS_DOZING at this time, the condition for starting doze dream can be met.
- Start dream with dream manager. At this time, the doze dream is started, not the screen saver.
- If it is starting, then continue. What to continue? See [Start doze dream】
- If the startup fails, enter the hibernation process.
The process of hibernation is the simplest. First update wakefulenss to WAKEFULNESS_ASLEEP, and then update the request policy toDisplayPowerRequest.POLICY_OFF, this causes the screen to be directly deactivated. The process of updating the request policy is as follows
int getDesiredScreenPolicyLocked(int groupId) { final int wakefulness = (groupId); final int wakeLockSummary = (groupId); if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) { return DisplayPowerRequest.POLICY_OFF; } else if (wakefulness == WAKEFULNESS_DOZING) { // ... } // ... }
As you can see, when wakefulness is WAKEFULNESS_ASLEEP, that is, when the device is in a sleep state, the request policy is not affected by any factors, and is directly DisplayPowerRequest.POLICY_OFF, which will make the screen sleep.
3. Start doze dream
Now we are only one step away from the device officially entering a nap state, and this step is to callDreamManagerService#startDreamInternal()Start doze dream
// private void startDreamInternal(boolean doze) { final int userId = (); // Get doze dream or screensaver final ComponentName dream = chooseDreamForUser(doze, userId); if (dream != null) { synchronized (mLock) { // Start dream, the doze dream started at this time, startDreamLocked(dream, false /*isTest*/, doze, userId); } } } private ComponentName chooseDreamForUser(boolean doze, int userId) { if (doze) { ComponentName dozeComponent = getDozeComponent(userId); return validateDream(dozeComponent) ? dozeComponent : null; } // ... } private ComponentName getDozeComponent(int userId) { if (mForceAmbientDisplayEnabled || (userId)) { // Get config_dozeComponent from the configuration file return (()); } else { return null; } }
The system does not have a doze dream component, but it doesn't matter. After studying some of the implemented doze components in the source code, we can find that the doze component is inherited from a namedDreamServiceService, this service is the service of four major components.
Now continue to look at the process of starting the doze component
// private void startDreamLocked(final ComponentName name, final boolean isTest, final boolean canDoze, final int userId) { // ... final Binder newToken = new Binder(); mCurrentDreamToken = newToken; mCurrentDreamName = name; mCurrentDreamIsTest = isTest; mCurrentDreamCanDoze = canDoze; mCurrentDreamUserId = userId; wakeLock = mPowerManager .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream"); // WakeLockThe #wrap() method ensures that the lock is acquired before the Runnbale is executed and the lock is released after the Runnable is executed. // That is, keep the CPU running until the doze dream is finished starting. ((() -> { (true); if (!(mAmbientDisplayComponent)) { (DreamManagerEvent.DREAM_START); } // Turn on dream (newToken, name, isTest, canDoze, userId, wakeLock); })); }
passDreamController#startDream()Start doze dream
// public void startDream(Binder token, ComponentName name, boolean isTest, boolean canDoze, int userId, wakeLock) { stopDream(true /*immediate*/, "starting new dream"); try { // In fact, it is to send Intent.ACTION_CLOSE_SYSTEM_DIALOGS broadcast // Close the notification shade. No need to send to all, but better to be explicit. (mCloseNotificationShadeIntent, ); // 1. Create a record dream record // Note that DreamRecord implements ServiceConnection mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId, wakeLock); mDreamStartTime = (); (mContext, ? : ); Intent intent = new Intent(DreamService.SERVICE_INTERFACE); (name); (Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); try { // 2. Connect to Service if (!(intent, mCurrentDream, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, new UserHandle(userId))) { (TAG, "Unable to bind dream service: " + intent); stopDream(true /*immediate*/, "bindService failed"); return; } } catch (SecurityException ex) { (TAG, "Unable to bind dream service: " + intent, ex); stopDream(true /*immediate*/, "unable to bind service: SecExp."); return; } = true; (mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT); } finally { (Trace.TRACE_TAG_POWER); } }
Since doze dream is a Service, the process of starting it is the process of binding the Service.
Since DreamRecord implements ServiceConnection, it will be called when the service is successfully connected.DreamRecord#onServiceConnected()
// public void onServiceConnected(ComponentName name, final IBinder service) { (() -> { mConnected = true; if (mCurrentDream == && mService == null) { attach((service)); // Wake lock will be released once dreaming starts. } else { releaseWakeLockIfNeeded(); } }); } private void attach(IDreamService service) { try { // DreamRecord Monitor Service Life and Death ().linkToDeath(mCurrentDream, 0); // The third parameter is a binder callback, used to receive the result (, , ); } catch (RemoteException ex) { (TAG, "The dream service died unexpectedly.", ex); stopDream(true /*immediate*/, "attach failed"); return; } = service; // Send Intent.ACTION_DREAMING_STARTED broadcast if (!) { (mDreamingStartedIntent, ); = true; } }
You can see that after the Service is successfully started, it will be calledDreamService#attach(), and then send the broadcast started by dreamIntent.ACTION_DREAMING_STARTED。
Here we need to combine the specific doze dream service to analyze. Since the system is not configured, then take DozeService in SystemUI as an example for analysis. First, take it as a look at itsonCreate()process
public class DozeService extends DreamService implements , RequestDoze, PluginListener<DozeServicePlugin> { @Override public void onCreate() { (); // Set to windowless mode setWindowless(true); (this, , false /* allowMultiple */); DozeComponent dozeComponent = (this); mDozeMachine = (); } }
Note that it sets a windowless mode, which will be used later.
As I just analyzed, after the DreamService binding is successful, it will be calledDreamService#attach()
private void attach(IBinder dreamToken, boolean canDoze, IRemoteCallback started) { // ... mDreamToken = dreamToken; mCanDoze = canDoze; // Only doze dream can have no windows if (mWindowless && !mCanDoze) { throw new IllegalStateException("Only doze dreams can be windowless"); } mDispatchAfterOnAttachedToWindow = () -> { if (mWindow != null || mWindowless) { mStarted = true; try { // Implemented by subclasses onDreamingStarted(); } finally { try { (null); } catch (RemoteException e) { throw (); } } } }; if (!mWindowless) { // ... } else { // In the absence of window, call onDreamingStarted() directly (); } }
For SystemUI's DozeService, it is windowless, so its onDreamingStarted() method is called directly
// public void onDreamingStarted() { (); (); // Call the parent class method startDozing(); if (mDozePlugin != null) { (); } }
Enter againDreamService#startDozing()
public void startDozing() { if (mCanDoze && !mDozing) { mDozing = true; updateDoze(); } } private void updateDoze() { if (mDreamToken == null) { (TAG, "Updating doze without a dream token."); return; } if (mDozing) { try { // Notify the dream manager that the service is starting the doze function (mDreamToken, mDozeScreenState, mDozeScreenBrightness); } catch (RemoteException ex) { // system server died } } }
Finally, return the information to the DreamManagerService to start doze
// private void startDozingInternal(IBinder token, int screenState, int screenBrightness) { synchronized (mLock) { if (mCurrentDreamToken == token && mCurrentDreamCanDoze) { mCurrentDreamDozeScreenState = screenState; mCurrentDreamDozeScreenBrightness = screenBrightness; // 1. Notify PowerManagerService to save the screen status and screen brightness in doze state ( screenState, screenBrightness); if (!mCurrentDreamIsDozing) { mCurrentDreamIsDozing = true; //2. Get PowerManager.DOZE_WAKE_LOCK wake-up lock (); } } } }
DreamManagerService passes the information to PowerManagerService, which includes the screen status under doze and the screen brightness, and PowerManagerService simply saves this information.
Then I get a PowerManager.DOZE_WAKE_LOCK, which is the most important step for the device to enter a dozing state. It affects the screen request policy as follows
// int getDesiredScreenPolicyLocked(int groupId) { final int wakefulness = (groupId); final int wakeLockSummary = (groupId); if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) { return DisplayPowerRequest.POLICY_OFF; } else if (wakefulness == WAKEFULNESS_DOZING) { // The following conditions indicate that the dream manager has obtained the PowerManager.DOZE_WAKE_LOCK wake-up lock if ((wakeLockSummary & WAKE_LOCK_DOZE) != 0) { return DisplayPowerRequest.POLICY_DOZE; } if (mDozeAfterScreenOff) { return DisplayPowerRequest.POLICY_OFF; } } // ... }
You can see that after DreamManagerService successfully obtains the PowerManager.DOZE_WAKE_LOCK wake-up lock, the request policy is now DisplayPowerRequest.POLICY_DOZE, which will cause the screen to enter the doze state, which is an almost dormant state, and is also a low-power state, and the AOD function is turned on. Of course, the premise is that the screen supports this function. It is said that only the OLED screen supports the AOD function.
At this time, the device is truly dozing. I don’t think the subsequent process of PowerManagerService updating the power state is important, and it is left to readers for their own analysis.
Finish
This article analyzes the screen-destroying process and how the device enters a dozing state, which can be said to be ups and downs. But be aware that this is just a manual screen deactivation. We usually see automatic screen deactivation caused by screen timeout, so the next article continues to analyze it.
In this article, we also mentioned that the device has a state, the dream state, which actually refers to the screensaver. You said it was useless, sometimes it still has some effect, you said it was useful, now you can hardly see where it is used. I am still hesitating whether to analyze whether this kind of thing that is tasteless and a pity to discard.
The above is the detailed content of PowerManagerService's manual screen deactivation. For more information about PowerManagerService's screen deactivation, please follow my other related articles!