Preface
Analysis of the screen brightening process of PowerManagerServiceThe general process of lighting up the screen/disconnecting the screen is summarized.PowerManagerService: Manual screen decompressionA comprehensive analysis of the manual screen-destroying process was conducted. The previous two articles in this article are based on the analysis of automatic screen deactivation. Readers are advised to read the first two articles carefully.
Automatic screen decompression
To analyze automatic screen deactivation, you need to review itAnalysis of the screen brightening process of PowerManagerServicesome details of the bright screen logic.
When the screen is turned on, the time when the screen is turned on and the time when the user behavior is kept. These two times are used to determine the user behavior, as follows
// private void updateUserActivitySummaryLocked(long now, int dirty) { // ... for (int groupId : ()) { int groupUserActivitySummary = 0; long groupNextTimeout = 0; if ((groupId) != WAKEFULNESS_ASLEEP) { final long lastUserActivityTime = (groupId); final long lastUserActivityTimeNoChangeLights = ( groupId); // mLastWakeTime indicates the last time the screen was illuminated // lastUserActivityTime represents the last user behavior if (lastUserActivityTime >= mLastWakeTime) { // Calculate the timeout for dimming the screen groupNextTimeout = lastUserActivityTime + screenOffTimeout - screenDimDuration; if (now < groupNextTimeout) { groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT; } else { // ... } } // ... } // ... }
The user behavior obtained at this time is USER_ACTIVITY_SCREEN_BRIGHT, indicating that the user behavior is to light up the screen.
After that, a request will be initiated to the DisplayManagerService, and the request strategy that ultimately determines the screen status (light, extinguish, dark, etc.). Its update process is as follows
int getDesiredScreenPolicyLocked(int groupId) { final int wakefulness = (groupId); final int wakeLockSummary = (groupId); if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) { // ... } else if (wakefulness == WAKEFULNESS_DOZING) { // ... } if (mIsVrModeEnabled) { // ... } if ((wakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0 || !mBootCompleted || ((groupId) & USER_ACTIVITY_SCREEN_BRIGHT) != 0 || mScreenBrightnessBoostInProgress) { return DisplayPowerRequest.POLICY_BRIGHT; } // ... }
Since the user behavior is USER_ACTIVITY_SCREEN_BRIGHT, the policy is DisplayPowerRequest.POLICY_BRIGHT, which eventually causes the screen to brighten.
So how do you automatically turn off the screen after the screen is turned on?
// private void updateUserActivitySummaryLocked(long now, int dirty) { // ... for (int groupId : ()) { int groupUserActivitySummary = 0; long groupNextTimeout = 0; if ((groupId) != WAKEFULNESS_ASLEEP) { final long lastUserActivityTime = (groupId); final long lastUserActivityTimeNoChangeLights = ( groupId); if (lastUserActivityTime >= mLastWakeTime) { // Timeout time to make the screen dim groupNextTimeout = lastUserActivityTime + screenOffTimeout - screenDimDuration; if (now < groupNextTimeout) { groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT; } else { // ... } } // ... } // Use the timeout timeout when the screen becomes dimmed, send a timed message to update user behavior if (hasUserActivitySummary && nextTimeout >= 0) { scheduleUserInactivityTimeout(nextTimeout); } } private void scheduleUserInactivityTimeout(long timeMs) { final Message msg = (MSG_USER_ACTIVITY_TIMEOUT); (true); // Use the timeout time to send a timed message to update user behavior // Finally call handleUserActivityTimeout (msg, timeMs); } private void handleUserActivityTimeout() { // runs on handler thread synchronized (mLock) { // Mark user behavior needs to be updated mDirty |= DIRTY_USER_ACTIVITY; // Reupdate the power state is actually to update user behavior updatePowerStateLocked(); } }
From the above code logic, we can see that when the Power key is on, the timeout time will be calculated to make the screen dim, and then a timed message will be sent. When the timeout time for the screen dim, the user behavior will be updated again, as follows
// private void updateUserActivitySummaryLocked(long now, int dirty) { // ... for (int groupId : ()) { int groupUserActivitySummary = 0; long groupNextTimeout = 0; if ((groupId) != WAKEFULNESS_ASLEEP) { final long lastUserActivityTime = (groupId); final long lastUserActivityTimeNoChangeLights = ( groupId); if (lastUserActivityTime >= mLastWakeTime) { groupNextTimeout = lastUserActivityTime + screenOffTimeout - screenDimDuration; if (now < groupNextTimeout) { // ... } else { // Calculate the timeout of the screen to be deactivated groupNextTimeout = lastUserActivityTime + screenOffTimeout; if (now < groupNextTimeout) { // Enter DIM time period // Update user behavior groupUserActivitySummary = USER_ACTIVITY_SCREEN_DIM; } } } // ... } // ... // Use the timeout time of the screen to send a timed message to update the user behavior if (hasUserActivitySummary && nextTimeout >= 0) { scheduleUserInactivityTimeout(nextTimeout); } }
This update of user behavior calculates the timeout time of the screen deactivation, and then the user behavior is updated to USER_ACTIVITY_SCREEN_DIM, indicating that the user behavior should make the screen dim. Finally, using the timeout time of the screen-out, a timed message was sent to update the user behavior again.
Now the user behavior is to make the screen dim, and then see how the request policy is updated
int getDesiredScreenPolicyLocked(int groupId) { final int wakefulness = (groupId); final int wakeLockSummary = (groupId); if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) { // ... } else if (wakefulness == WAKEFULNESS_DOZING) { // ... } if (mIsVrModeEnabled) { // ... } if ((wakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0 || !mBootCompleted || ((groupId) & USER_ACTIVITY_SCREEN_BRIGHT) != 0 || mScreenBrightnessBoostInProgress) { // ... } return DisplayPowerRequest.POLICY_DIM; }
The request policy is updated to DisplayPowerRequest.POLICY_DIM, which eventually makes the screen dim.
When the timeout of the screen is over, let's take a look at what happens when the user behavior is updated again.
// private void updateUserActivitySummaryLocked(long now, int dirty) { // ... for (int groupId : ()) { int groupUserActivitySummary = 0; long groupNextTimeout = 0; if ((groupId) != WAKEFULNESS_ASLEEP) { final long lastUserActivityTime = (groupId); final long lastUserActivityTimeNoChangeLights = ( groupId); if (lastUserActivityTime >= mLastWakeTime) { groupNextTimeout = lastUserActivityTime + screenOffTimeout - screenDimDuration; if (now < groupNextTimeout) { groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT; } else { groupNextTimeout = lastUserActivityTime + screenOffTimeout; if (now < groupNextTimeout) { groupUserActivitySummary = USER_ACTIVITY_SCREEN_DIM; } } } // Before the screen timeout is expiring, the wake-up lock with PowerManager.ON_AFTER_RELEASE flag is released to extend the light/dark time of the screen if (groupUserActivitySummary == 0 && lastUserActivityTimeNoChangeLights >= mLastWakeTime) { // ... } // The screen timeout is over, and the screen security is allowed to enter if (groupUserActivitySummary == 0) { // ... } // Press KeyEvent.KEYCODE_SOFT_SLEEP Enter the screen saver if (groupUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) { // ... } // Use AttentionDetector to recalculate the timeout, and it is not analyzed at present if ((groupUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0 && ((groupId) & WAKE_LOCK_STAY_AWAKE) == 0) { // ... } // Determine whether there is any user behavior hasUserActivitySummary |= groupUserActivitySummary != 0; // Save timeout if (nextTimeout == -1) { nextTimeout = groupNextTimeout; } else if (groupNextTimeout != -1) { nextTimeout = (nextTimeout, groupNextTimeout); } } // DisplayGroupPowerStateMapper Saves user behavior (groupId, groupUserActivitySummary); } final long nextProfileTimeout = getNextProfileTimeoutLocked(now); if (nextProfileTimeout > 0) { nextTimeout = (nextTimeout, nextProfileTimeout); } // Use the timeout time to send a timed message if (hasUserActivitySummary && nextTimeout >= 0) { scheduleUserInactivityTimeout(nextTimeout); } }
You can see that when the timeout of the screen is over, many factors will affect the user behavior and timeout time again. We ignore these factors, so the timeout time and user behavior are both 0. Since there is no user behavior and timeout time, it is naturally not sent to update user behavior, because the screen will be turned off soon, so there is no need to update user behavior regularly.
At this time, I would like to remind everyone that from the process of turning on the screen to the automatic de-screen, wakefulness is still WAKEFULNESS_AWAKE, and the screen is about to be de-installed, so wakefulness needs to be updated again. This is the process of updating the power state.updateWakefulnessLocked()Made
// private boolean updateWakefulnessLocked(int dirty) { boolean changed = false; if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE | DIRTY_DOCK_STATE | DIRTY_ATTENTIVE | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) { final long time = (); for (int id : ()) { if ((id) == WAKEFULNESS_AWAKE && isItBedTimeYetLocked(id)) { if (isAttentiveTimeoutExpired(id, time)) { // ... Not considering attentive timeout, most projects do not support... } else if (shouldNapAtBedTimeLocked()) { // ... If the screen saver is turned on, the screen saver will also enter the screen saver... } else { // Update wakefulness to WAKEFULNESS_DOZING changed = sleepDisplayGroupNoUpdateLocked(id, time, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID); } } } } return changed; } private boolean isItBedTimeYetLocked(int groupId) { if (!mBootCompleted) { return false; } long now = (); // Not considering attentive timeout, most projects do not support it if (isAttentiveTimeoutExpired(groupId, now)) { return !isBeingKeptFromInattentiveSleepLocked(groupId); } else { return !isBeingKeptAwakeLocked(groupId); } } private boolean isBeingKeptAwakeLocked(int groupId) { return mStayOn // Whether to turn on the "Charge on" function in developer mode || mProximityPositive // Whether the distance sensor remains illuminated || ((groupId) & WAKE_LOCK_STAY_AWAKE) != 0 // Is there a wake lock keeping the screen lit || ((groupId) & ( USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0 // Is there any user behavior that is illuminated || mScreenBrightnessBoostInProgress; // Is the screen in the process of brightness enhancement}
Now you want to turn off the screen. As long as there is no factor to keep the screen bright, wakefulness will be updated to WAKEFULNESS_DOZING.
Now the device has entered a dozing state, and the process of dozing state is notPowerManagerService: Manual screen decompressionHas it been analyzed? If the device enters a doze state and can successfully start doze dream, it will actually enter a doze state, otherwise it will enter a doze state. Whether the device goes to a dozing state or sleeping state, the screen will eventually go out.
Automatic screen-destroying summary
The principle of automatic screen deactivation is to use the calculated timeout time to send a timed message to update user behavior, and update wakefulness when necessary, that is, update the system status, thereby changing the requested strategy, and ultimately changing the state of the screen (light, extinguish, dark, etc.).
Extend the screen light time
Now let's discuss a topic related to automatic screen deactivation, that is, extending the screen light time
private void updateUserActivitySummaryLocked(long now, int dirty) { // ... for (int groupId : ()) { int groupUserActivitySummary = 0; long groupNextTimeout = 0; if ((groupId) != WAKEFULNESS_ASLEEP) { final long lastUserActivityTime = (groupId); final long lastUserActivityTimeNoChangeLights = ( groupId); // 1. Before automatically extinguishing the screen, the user touches the TP, which will cause the user's behavior time to be updated, thereby extending the screen light time if (lastUserActivityTime >= mLastWakeTime) { groupNextTimeout = lastUserActivityTime + screenOffTimeout - screenDimDuration; if (now < groupNextTimeout) { groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT; } else { groupNextTimeout = lastUserActivityTime + screenOffTimeout; if (now < groupNextTimeout) { groupUserActivitySummary = USER_ACTIVITY_SCREEN_DIM; } } } // 2. If there is powerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS when updating the user, the screen will also be extended. if (groupUserActivitySummary == 0 && lastUserActivityTimeNoChangeLights >= mLastWakeTime) { // Recalculate the screen-destruction time according to lastUserActivityTimeNoChangeLights time point groupNextTimeout = lastUserActivityTimeNoChangeLights + screenOffTimeout; if (now < groupNextTimeout) { final DisplayPowerRequest displayPowerRequest = (groupId); if ( == DisplayPowerRequest.POLICY_BRIGHT || == DisplayPowerRequest.POLICY_VR) { // Theoretically, if the screen timeout, the screen will dim first, but why is the request strategy for lighting the screen here? // What if there is no time for dark screens? groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT; } else if ( == DisplayPowerRequest.POLICY_DIM) { groupUserActivitySummary = USER_ACTIVITY_SCREEN_DIM; } } } } (groupId, groupUserActivitySummary); } // ... if (hasUserActivitySummary && nextTimeout >= 0) { scheduleUserInactivityTimeout(nextTimeout); } }
You can see that there are two situations that can extend the time of the screen light
- When the screen is light/dark, if the user touches TP, the user behavior time will be updated, resulting in the extended time of the screen light. In particular, if the screen is in a dark screen state, clicking on the touch screen will cause the screen to brighten.
- If there is update user behavior with PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS, the screen will also be extended.
This article analyzes the extended screen brightening process caused by user touching TP, and the other one is asked to analyze it by the reader.
When the user touches TP, the underlying Input system will be called through JNIPowerManagerService#userActivityFromNative()
// frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) { android_server_PowerManagerService_userActivity(eventTime, eventType); } // frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) { if (gPowerManagerServiceObj) { // Call the Java layer PowerManagerService#userActivityFromNative() env->CallVoidMethod(gPowerManagerServiceObj, , nanoseconds_to_milliseconds(eventTime), eventType, 0); } }
// private void userActivityFromNative(long eventTime, int event, int displayId, int flags) { userActivityInternal(displayId, eventTime, event, flags, Process.SYSTEM_UID); } private void userActivityInternal(int displayId, long eventTime, int event, int flags, int uid) { synchronized (mLock) { // ... // Update user activity time if (userActivityNoUpdateLocked(groupId, eventTime, event, flags, uid)) { // Update power status updatePowerStateLocked(); } } }
It turns out that the user touches TP and will update the time of user behavior, and then the user behavior will also change.
private void updateUserActivitySummaryLocked(long now, int dirty) { // ... // Remove the timed message that updates the user behavior first (MSG_USER_ACTIVITY_TIMEOUT); // ... for (int groupId : ()) { int groupUserActivitySummary = 0; long groupNextTimeout = 0; if ((groupId) != WAKEFULNESS_ASLEEP) { final long lastUserActivityTime = (groupId); final long lastUserActivityTimeNoChangeLights = ( groupId); // The user touches TP and updates the user behavior time lastUserActivityTime, so the timeout time is recalculated here // In other words, the screen is extended if (lastUserActivityTime >= mLastWakeTime) { // Recalculate the timeout of the dark screen groupNextTimeout = lastUserActivityTime + screenOffTimeout - screenDimDuration; if (now < groupNextTimeout) { // User behavior is to light the screen groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT; } else { // ... } } } // ... // Send a timed message again to update user behavior if (hasUserActivitySummary && nextTimeout >= 0) { scheduleUserInactivityTimeout(nextTimeout); } }
Due to the update of user behavior time, the timeout time for the dark screen is recalculated, and the user behavior is updated to USER_ACTIVITY_SCREEN_BRIGHT.
Updates to user behavior also lead to updates to request policies, as follows
int getDesiredScreenPolicyLocked(int groupId) { final int wakefulness = (groupId); final int wakeLockSummary = (groupId); if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) { // ... } else if (wakefulness == WAKEFULNESS_DOZING) { // ... } if (mIsVrModeEnabled) { // ... } if ((wakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0 || !mBootCompleted || ((groupId) & USER_ACTIVITY_SCREEN_BRIGHT) != 0 || mScreenBrightnessBoostInProgress) { return DisplayPowerRequest.POLICY_BRIGHT; } // ... }
It can be seen that if the screen is in a light/dark state, the user touches TP and the request policy is updated to DisplayPowerRequest.POLICY_BRIGHT, which eventually leads to the screen being in a light state.
In addition, the recalculated dark screen timeout time will be used to send a timed message to update user behavior, so it is equivalent to resetting the screen timeout time.
Therefore, touching TP causes the screen to be in the screen-lit state and resets the screen timeout time, which is equivalent to extending the screen-lit time.
Finish
If you understand the process of lighting and extinguishing the screen, the principle of automatic extinguishing the screen is not that complicated. If readers find that many things are very simple when reading this article, it is because the previous article has been analyzed, so readers must carefully read the previous two articles.
Based on the current three articles, in the next article, we will discuss the last topic of PowerManagerService, Wake Lock.
The above is the detailed content of the automatic screen destruction process analysis of PowerManagerService. For more information about PowerManagerService's automatic screen destruction, please follow my other related articles!