When analyzing the on-off screen flow in Android R PowerManagerService module (4) and Android R PowerManagerService module (3) on screen flow, focus on the PMS part of the flow. The process involved in THE DMS is not analyzed, only the request to the DMS to set the screen brightness and Display state is omitted.
In the analysis of DMS module, emphasis will be placed on the process related to Display. This article will make a detailed analysis of the process after PMS sends a request to DMS in the process of switching on and off the screen, so as to understand the whole logic of setting brightness and Display state.
In the DMS module, the interaction with the PMS is handled by the DisplayPowerController, such as controlling the screen brightness, Display status, and the off screen of the PSensor. DisplayPowerController is a DMS module, but its core logic runs on the PMS thread, ensuring independence from the PMS. It does not share any state with the PMS. The PMS initiates a request to the DMS, and the DisplayPowerController receives the request and notifies the PMS of the change through a callback when the request is processed.
The DisplayPowerController object is created during PMS startup:
public void systemReady(IAppOpsService appOps) {...// Initialize display power management.mDisplayManagerInternal.initPowerManagement( mDisplayPowerCallbacks, mHandler, sensorManager); . }Copy the code
Create DMS in Local Service:
// frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
@Override
public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager) {
synchronized (mSyncRoot) {
DisplayBlanker blanker = new DisplayBlanker() {
......
// Create the DisplayPowerController object
mDisplayPowerController = new DisplayPowerController(
mContext, callbacks, handler, sensorManager, blanker,
mDisplayDevices.get(Display.DEFAULT_DISPLAY));
mSensorManager = sensorManager;
}
mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION);
}
Copy the code
DisplayPowerController controls state and brightness Settings through two other classes:
- DisplayPowerState: Represents the overall state of the current Display. Updates to the state and brightness are handed to it for further processing;
- LocalDisplayAdapter: An adapter that represents the default screen. DisplayPowerState will give it the Display state and brightness, and it will set the state and brightness to the connected physical screen.
The next step is to continue the on-off screen process.
1. RequestPowerState () initiates the request
PMS is called updateDisplayPowerStateLocked request update the Display () method, this method finally call DisplayPowerController# requesetPowerState () method:
/ * * *@paramRequest Request parameters encapsulated in the PMS *@paramThe action of the PSensor lock after the release of waitForNegativeProximity and Proximity Wakelock *@returnTrue indicates that the request processing is complete. False indicates that the request processing is not complete
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mLock) {
boolean changed = false;
// Whether the PSensor listening is delayed after the PSensor WakeLock lock is released
if(waitForNegativeProximity && ! mPendingWaitForNegativeProximityLocked) { mPendingWaitForNegativeProximityLocked =true;
changed = true;
}
// Enter for the first time after booting
if (mPendingRequestLocked == null) {
mPendingRequestLocked = new DisplayPowerRequest(request);
changed = true;
} else if(! mPendingRequestLocked.equals(request)) {// The request has changed
mPendingRequestLocked.copyFrom(request);
changed = true;
}
Return false to the PMS to indicate that the request is not completed
if (changed) {
mDisplayReadyLocked = false;
}
// Start processing new requests
if(changed && ! mPendingRequestChangedLocked) {// Indicates that the request has changed and the global request is about to be updated
mPendingRequestChangedLocked = true;
sendUpdatePowerStateLocked();
}
returnmDisplayReadyLocked; }}Copy the code
In the above methods, whether this request can be processed as a new request is determined by the following three conditions:
- Whether waitForNegativeProximity is true;
- If the function is entered for the first time after startup, mPendingRequestLocked is null, and the DisplayPowerRequest object representing the request is instantiated.
- Check whether this request object is the same as the last request object.
If waitForNegativeProximity is true, it indicates that during the release of PROXIMITY_SCREEN_OFF_WAKE_LOCK WakeLock, If PSenor reports an proximity event and the screen is off, In this case, the MONITORING of the PSensor is removed only after the PSensor reports a remote event and the screen turns on. This value is true when powerManager.release_FLAG_WAIT_FOR_no_proximity is used when releasing wakelock. For details, see The WakeLock mechanism in Android R PowerManagerService module (2).
After applying PROXIMITY_SCREEN_OFF_WAKE_LOCK, release the lock using release() and release(RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) respectively in the case of screen occlusion. Different results can be seen.
MPendingRequestChangedLocked variable is used to say the last request has been processed. The DisplayPowerRequest object represents a request object that encapsulates a number of request parameters:
public static final class DisplayPowerRequest {
public int policy; // Display status of the request
public boolean useProximitySensor; // Whether PROXIMITY_SCREEN_OFF_WAKE_LOCK is held
public int screenBrightnessOverride; // Whether to override brightness, especially from WindowMananger
public boolean useAutoBrightness; // Whether to use automatic brightness
public boolean lowPowerMode; // Whether the battery is in low power mode
public float screenLowPowerBrightnessFactor; // Adjust brightness factor in low power mode
public boolean boostScreenBrightness; // Whether brightness enhancement is used
public int dozeScreenBrightness; // Screen brightness after entering Doze state
public int dozeScreenState; // Display state after entering Doze state
Copy the code
After the sendUpdatePowerStateLocked () method, through the Handler into the PMS thread began to process the request:
private void sendUpdatePowerStateLocked(a) {
if(! mPendingUpdatePowerStateLocked) {// The power state needs to be updated
mPendingUpdatePowerStateLocked = true; Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE); mHandler.sendMessage(msg); }}Copy the code
Then you go to the updatePowerState() method, which is the core method in the DisplayPowerController that does the parsing and processing of the request.
2. UpdatePowerState () Updates the status
The updatePowerState() method is very large, and handles the on-off screen, brightness adjustments, and Display state updates. The complete code for this method is as follows:
private void updatePowerState(a) {
// Update the power state request.
final boolean mustNotify; // Whether to notify PMS to complete request processing
final int previousPolicy;
boolean mustInitialize = false; // Whether to initialize
int brightnessAdjustmentFlags = 0; // Automatic brightness adjustment factor mark
mBrightnessReasonTemp.set(null); // Record the cause of brightness change
// ####################################################Part 1####################################################
synchronized (mLock) {
mPendingUpdatePowerStateLocked = false; // means "update is about to start", which has already started, so reset to true
if (mPendingRequestLocked == null) {
return; // wait until first actual power request
}
if (mPowerRequest == null) { // The if code block is entered only for the first time after the system is booted
mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
mPendingRequestChangedLocked = false;
mustInitialize = true;
previousPolicy = DisplayPowerRequest.POLICY_BRIGHT;
} else if (mPendingRequestChangedLocked) { // Update global DisplayPowerRequest
previousPolicy = mPowerRequest.policy;
mPowerRequest.copyFrom(mPendingRequestLocked); / / update the mPowerRequest
mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
mPendingRequestChangedLocked = false; / / reset
mDisplayReadyLocked = false;
} else{ previousPolicy = mPowerRequest.policy; } mustNotify = ! mDisplayReadyLocked; }if (mustInitialize) {
initialize(); // Initialize the on-off screen animation, the DisplayPowerState object...
}
// ####################################################Part 2####################################################
int state;
float brightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
boolean performScreenOffTransition = false; // Whether to perform the screen-off animation
switch (mPowerRequest.policy) { // The state of Display to be set will be determined according to policy
case DisplayPowerRequest.POLICY_OFF: // If policy is off, the Display state will be set to off
state = Display.STATE_OFF;
performScreenOffTransition = true;
break;
case DisplayPowerRequest.POLICY_DOZE: / / the policy to doze, can according to mPowerRequest. DozeScreenState determine the status of the Display, the default state to doze
if(mPowerRequest.dozeScreenState ! = Display.STATE_UNKNOWN) { state = mPowerRequest.dozeScreenState; }else {
state = Display.STATE_DOZE;
}
if(! mAllowAutoBrightnessWhileDozingConfig) {// Whether automatic brightness is supported in Doze state. Default is false
brightnessState = mPowerRequest.dozeScreenBrightness; // Set the brightness to the Doze state brightness specified in PMS
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE); // Record the reason for the brightness change -- the brightness of doze state
}
break;
case DisplayPowerRequest.POLICY_VR: // If policy is VR, set the Display state to VR
state = Display.STATE_VR;
break;
case DisplayPowerRequest.POLICY_DIM: // If policy is DIM or BRIGHT, the Display state is set to ON
case DisplayPowerRequest.POLICY_BRIGHT:
default:
state = Display.STATE_ON;
break;
}
assert(state ! = Display.STATE_UNKNOWN);// #################################################### Part 3 ####################################################
if(mProximitySensor ! =null) {
// If a Proximity WakeLock lock is held, and the Display status is not set to OFF
if(mPowerRequest.useProximitySensor && state ! = Display.STATE_OFF) {// Register PSensor listener
setProximitySensorEnabled(true);
// Proximity incident reported
if(! mScreenOffBecauseOfProximity && mProximity == PROXIMITY_POSITIVE) {// represents "Is the screen off due to PSensor receiving the approach time?"
mScreenOffBecauseOfProximity = true;
// The callback notifies the PMS that the PSensor received a proximity event
sendOnProximityPositiveWithWakelock();
}
If a Proximity WakeLock is released with a "1" marker, and the PSensor continues to wait and monitor the Proximity WakeLock because the PSensor is off and no remote event has been received
} else if(mWaitingForNegativeProximity && mScreenOffBecauseOfProximity && mProximity == PROXIMITY_POSITIVE && state ! = Display.STATE_OFF) { setProximitySensorEnabled(true);
} else {
// When the screen is off or a Proximity WakeLock is released, remove the PSensor monitoring
setProximitySensorEnabled(false);
mWaitingForNegativeProximity = false;
}
/ / received from incident, reset mScreenOffBecauseOfProximity
if(mScreenOffBecauseOfProximity && mProximity ! = PROXIMITY_POSITIVE) { mScreenOffBecauseOfProximity =false;
// Notify the PMS that the PSensor received the away eventsendOnProximityNegativeWithWakelock(); }}else {
// If the PSensor is not available, set the value to false
mWaitingForNegativeProximity = false;
}
// If the PSensor receives a report that the time is approaching, it needs to turn OFF the screen, so set the Display state to OFF
if (mScreenOffBecauseOfProximity) {
state = Display.STATE_OFF;
}
// #################################################### Part 4 ####################################################
final int oldState = mPowerState.getScreenState();
// Set the Display state
animateScreenStateChange(state, performScreenOffTransition);
state = mPowerState.getScreenState();
// #################################################### Part 5 ####################################################
// If the Display status is set to OFF, it indicates that the screen is OFF, and the brightness is set to -1.0F
if (state == Display.STATE_OFF) {
brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT;
// Record the cause of brightness change
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_SCREEN_OFF);
}
// If the Display state is set to VR, it is not used frequently
if (state == Display.STATE_VR) {
brightnessState = mScreenBrightnessForVr;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_VR);
}
// Use brightness overlay in PMS, brightness from WindowManager such as video interface
if ((Float.isNaN(brightnessState))
&& isValidBrightnessValue(mPowerRequest.screenBrightnessOverride)) {
brightnessState = mPowerRequest.screenBrightnessOverride;
// Record the cause of brightness change
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_OVERRIDE);
// indicates that overlay brightness is used
mAppliedScreenBrightnessOverride = true;
} else {
mAppliedScreenBrightnessOverride = false;
}
// Determine whether to use auto brightness in Doze state, usually false
final boolean autoBrightnessEnabledInDoze =
mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state);
// Check whether auto Brightness is available: Auto Brightness & Bright screen state is started & the first several types of brightness are not used & Auto Brightness curve mapping is configured
final booleanautoBrightnessEnabled = mPowerRequest.useAutoBrightness && (state == Display.STATE_ON || autoBrightnessEnabledInDoze) && Float.isNaN(brightnessState) && mAutomaticBrightnessController ! =null;
// Updates the status of the manually set brightness value in the user status bar and Settings. Returns true if the user Settings brightness changes
final boolean userSetBrightnessChanged = updateUserSetScreenBrightness();
// This brightness represents the brightness when the user drags the brightness bar adjustment and does not let go, so it is a "temporary" brightness and must be used if it exists
if (isValidBrightnessValue(mTemporaryScreenBrightness)) {
brightnessState = mTemporaryScreenBrightness;
// Indicates temporary user brightness is used
mAppliedTemporaryBrightness = true;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_TEMPORARY);
} else {
mAppliedTemporaryBrightness = false;
}
// Updates the auto brightness curve adjustment value, returning true if the adjustment value changes
final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
// Since the change has been updated to the global variable, there is no need for "temporary" automatic variable adjustment, reset
if (autoBrightnessAdjustmentChanged) {
mTemporaryAutoBrightnessAdjustment = Float.NaN;
}
final float autoBrightnessAdjustment;
// If a temporary automatic variable adjustment value exists, use it as the global automatic variable adjustment value, and then its value is updated to the global automatic variable adjustment value and reset, as seen in the first five lines
if(! Float.isNaN(mTemporaryAutoBrightnessAdjustment)) { autoBrightnessAdjustment = mTemporaryAutoBrightnessAdjustment; brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO_TEMP;// Indicates that a temporary automatic brightness adjustment value is used
mAppliedTemporaryAutoBrightnessAdjustment = true;
// Otherwise use the global auto brightness adjustment value
} else {
autoBrightnessAdjustment = mAutoBrightnessAdjustment;
brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO;
mAppliedTemporaryAutoBrightnessAdjustment = false;
}
// If brightness enhancement is used and the Display state is not off, the brightness will be set to the maximum
if(mPowerRequest.boostScreenBrightness && brightness ! = PowerManager.BRIGHTNESS_OFF) { brightnessState = PowerManager.BRIGHTNESS_ON; mBrightnessReasonTemp.setReason(BrightnessReason.REASON_BOOST);// Indicates that brightness enhancement is used
mAppliedBrightnessBoost = true;
} else {
mAppliedBrightnessBoost = false;
}
/ / indicates whether or not the user has launched a brightness change: don't use more than a few class brightness & (automatic brightness adjustment value change | | users to set the brightness)
// If this value is true, the brightness is changed by the user dragging
boolean userInitiatedChange = (Float.isNaN(brightnessState))
&& (autoBrightnessAdjustmentChanged || userSetBrightnessChanged);
// Whether the automatic brightness has been manually adjusted
boolean hadUserBrightnessPoint = false;
if(mAutomaticBrightnessController ! =null) {
hadUserBrightnessPoint = mAutomaticBrightnessController.hasUserDataPoints();
// Set automatic brightness parameters
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mBrightnessConfiguration,
mLastUserSetScreenBrightness,
userSetBrightnessChanged, autoBrightnessAdjustment,
autoBrightnessAdjustmentChanged, mPowerRequest.policy); }
// #################################################### Part 6 ####################################################
boolean slowChange = false;
if (brightness < 0) { // If the first several types of brightness are not used, use automatic brightness
float newAutoBrightnessAdjustment = autoBrightnessAdjustment;
if (autoBrightnessEnabled) {
// Get automatic brightness
brightnessState = mAutomaticBrightnessController.getAutomaticScreenBrightness();
// Get the new auto brightness adjustment value
newAutoBrightnessAdjustment =
mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment();
}
// Auto brightness is used
if (isValidBrightnessValue(brightnessState)) {
// Limit the range of automatic brightness obtained
brightnessState = clampScreenBrightness(brightness);
// These two conditions are adjusted by automatic brightness
if(mAppliedAutoBrightness && ! autoBrightnessAdjustmentChanged) {// Use to control the brightness adjustment rate
slowChange = true;
}
// Update the brightness value to Settings
putScreenBrightnessSetting(brightnessState);
// Indicates that auto brightness is used
mAppliedAutoBrightness = true;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC);
} else {
mAppliedAutoBrightness = false;
}
// If the automatic brightness adjustment value changes, update the automatic brightness adjustment value to Settings
if(autoBrightnessAdjustment ! = newAutoBrightnessAdjustment) { putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment); }else {
// It is pure auto brightness, and there is no adjustment
brightnessAdjustmentFlags = 0; }}else {
mAppliedAutoBrightness = false;
brightnessAdjustmentFlags = 0;
}
// #################################################### Part 7 ####################################################
// If the PMS does not specify the Doze state brightness, use the default Doze state brightness
if ((Float.isNaN(brightnessState))
&& Display.isDozeState(state)) {
brightnessState = mScreenBrightnessDozeConfig;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
}
// #################################################### Part 8 ####################################################
// If there is no brightness here, the user-set brightness will be used
if (Float.isNaN(brightnessState)) {
brightnessState = clampScreenBrightness(mCurrentScreenBrightnessSetting);
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL);
}
// #################################################### Part 9 ####################################################
// Set the brightness after entering Dim
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
if (brightnessState > mScreenBrightnessRangeMinimum) {
brightnessState = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_DIMMED);
}
if(! mAppliedDimming) { slowChange =false; // Indicates that the brightness needs to be set quickly
}
mAppliedDimming = true; // Indicates that Dim is used
} else if (mAppliedDimming) {
slowChange = false;
mAppliedDimming = false;
}
// #################################################### Part 10 ####################################################
// In low power mode, lower the brightness to save power consumption
if (mPowerRequest.lowPowerMode) {
if (brightnessState > mScreenBrightnessRangeMinimum) {
final float brightnessFactor =
Math.min(mPowerRequest.screenLowPowerBrightnessFactor, 1);
final float lowPowerBrightnessFloat = (brightnessState * brightnessFactor);
brightnessState = Math.max(lowPowerBrightness, mScreenBrightnessRangeMinimum);
mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_LOW_POWER);
}
if(! mAppliedLowPower) { slowChange =false;
}
// Indicates that low power mode brightness is used
mAppliedLowPower = true;
} else if (mAppliedLowPower) {
slowChange = false;
mAppliedLowPower = false;
}
// #################################################### Part 11 ####################################################
if(! mPendingScreenOff) {if (mSkipScreenOnBrightnessRamp) { / / mSkipScreenOnBrightnessRamp says bright screen when not using brightness animation
if (state == Display.STATE_ON) {
if (mSkipRampState == RAMP_STATE_SKIP_NONE && mDozing) {
mInitialAutoBrightness = brightness;
mSkipRampState = RAMP_STATE_SKIP_INITIAL;
} else if(mSkipRampState == RAMP_STATE_SKIP_INITIAL && mUseSoftwareAutoBrightnessConfig && brightness ! = mInitialAutoBrightness) { mSkipRampState = RAMP_STATE_SKIP_AUTOBRIGHT; }else if(mSkipRampState == RAMP_STATE_SKIP_AUTOBRIGHT) { mSkipRampState = RAMP_STATE_SKIP_NONE; }}else{ mSkipRampState = RAMP_STATE_SKIP_NONE; }}// Whether is or was in VR state
final boolean wasOrWillBeInVr =
(state == Display.STATE_VR || oldState == Display.STATE_VR);
// Indicates whether to use the brightness animation when the screen is on. Use the brightness animation when the screen is on. Determined by the mSkipScreenOnBrightnessRamp
final booleaninitialRampSkip = state == Display.STATE_ON && mSkipRampState ! = RAMP_STATE_SKIP_NONE;// Whether the display hardware supports the full range of brightness values, if not, do not use brightness animation Settings when setting brightness
final boolean hasBrightnessBuckets =
Display.isDozeState(state) && mBrightnessBucketsInDozeConfig; // Whether the display hardware supports the full range of brightness values when representing the doZE state
// Whether colorfade has finished covering the display content, if it has, then there is no need to use brightness animation, because the display content is no longer visible
final boolean isDisplayContentVisible =
mColorFadeEnabled && mPowerState.getColorFadeLevel() == 1.0 f;
// Whether temporary brightness is used
final boolean brightnessIsTemporary =
mAppliedTemporaryBrightness || mAppliedTemporaryAutoBrightnessAdjustment;
float animateValue = brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT
? PowerManager.BRIGHTNESS_MIN : brightnessState;
if (isValidBrightnessValue(animateValue)) {
// Set brightness directly, no brightness animation (rate=0)
if(initialRampSkip || hasBrightnessBuckets || wasOrWillBeInVr || ! isDisplayContentVisible || brightnessIsTemporary) { animateScreenBrightness(animateValue, SCREEN_ANIMATION_RATE_MINIMUM); }else {
animateScreenBrightness(animateValue,
slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
}
// #################################################### Part 12 ####################################################
// Call brightnestempo rary and userInitial Change to record each brightness change
// common brightnessistemtempo () specifies whether to use temporary brightness. The default value is false and will revert to false when the tempo tempo tempo is changed
// userInitiatedChange indicates whether the user has adjusted brightness. False during brightness adjustment, true after adjustment, and false again the next time the method is executed
// Therefore, whenever the brightness changes, it will enter the following statistics, userInitiatedChange indicates whether the change is initiated by the user, Perfect!
// However, notifyBrightnessChanged() limits the statistical conditions: Only count changes using auto brightness, turn off auto brightness, and use windowOverlay brightness without counting
if(! brightnessIsTemporary) {if (userInitiatedChange && (mAutomaticBrightnessController == null| |! mAutomaticBrightnessController.hasValidAmbientLux())) { userInitiatedChange =false; } notifyBrightnessChanged(brightness, userInitiatedChange, hadUserBrightnessPoint); }}// After each brightness adjustment, the log output is quite useful for daily handling problems
if(! mBrightnessReasonTemp.equals(mBrightnessReason) || brightnessAdjustmentFlags ! =0) {
Slog.v(TAG, "Brightness [" + brightnessState + "] reason changing to: '"
+ mBrightnessReasonTemp.toString(brightnessAdjustmentFlags)
+ "', previous reason: '" + mBrightnessReason + "'.");
mBrightnessReason.set(mBrightnessReasonTemp);
}
// #################################################### Part 13 ####################################################
if(mDisplayWhiteBalanceController ! =null) { // Adjust the color temperature
if (state == Display.STATE_ON && mDisplayWhiteBalanceSettings.isEnabled()) {
mDisplayWhiteBalanceController.setEnabled(true);
mDisplayWhiteBalanceController.updateDisplayColorTemperature();
} else {
mDisplayWhiteBalanceController.setEnabled(false); }}// #################################################### Part 14 ####################################################
/ / mPendingScreenOnUnblocker for bright screen process, not empty screen has said is blocked, waiting for the WindowManager module after completion callback will be bright screen operation it is set to null
// Colorfade is a dark layer animation that fades in and out when the screen is on and off
final boolean ready = mPendingScreenOnUnblocker == null&& (! mColorFadeEnabled || (! mColorFadeOnAnimator.isStarted() && ! mColorFadeOffAnimator.isStarted()))// Is there a colorfade animation going on
&& mPowerState.waitUntilClean(mCleanListener); // Check whether the screen state and ColorFade are set, and return true when both are set
// So ready indicates whether the display state is set
// Indicates that the display state is set and the brightness is set
final booleanfinished = ready && ! mScreenBrightnessRampAnimator.isAnimating();// Whether the brightness animation is in progress
/ / mReportedScreenStateToPolicy said report to PhoneWindowManager kill bright screen phase value
if(ready && state ! = Display.STATE_OFF && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_ON) { setReportedScreenState(REPORTED_TO_POLICY_SCREEN_ON);/ / sets the mReportedScreenStateToPolicy to REPORTED_TO_POLICY_SCREEN_ON, said bright screen completion
mWindowManagerPolicy.screenTurnedOn(); / / PhoneWindowManager report
}
// Indicates that the update display Settings or brightness Settings have not been completed and need to be locked to ensure that they are completed
if(! finished && ! mUnfinishedBusiness) { mCallbacks.acquireSuspendBlocker(); mUnfinishedBusiness =true;
}
// The callback notifies the PMS that the display status has been updated and the PMS will initiate the request again
if (ready && mustNotify) {
synchronized (mLock) {
if(! mPendingRequestChangedLocked) { mDisplayReadyLocked =true; // Indicates that the update is complete
}
}
sendOnStateChangedWithWakelock(); / / callback PMS
}
// Update display and brightness Settings are complete, release the lock
if (finished && mUnfinishedBusiness) {
mUnfinishedBusiness = false;
mCallbacks.releaseSuspendBlocker();
}
// Record whether the Display state was set to ON last timemDozing = state ! = Display.STATE_ON; }Copy the code
According to specific functions, it is divided into several parts according to functions:
- Part 1: Update of mPowerRequest, which represents the request encapsulation object in the current PMS;
- Part 2: Determine the Display state to be set according to the policy parameter in the mPowerRequest object.
- Part 3: Processing of Proximity Sensor;
- Part 4: Set the Display state according to the state specified in Part2 and Part3;
- Part 5: Determine screen brightness;
- Part 6: Application of automatic brightness;
- Part 7: In Doze state, use Doze default brightness;
- Part 8: Application user manually adjust brightness;
- Part 9: Setting the brightness of Dim;
- Part 10: Setting brightness at low power state;
- Part 11: Determine whether to use brightness animation and brightness Settings;
- Part 12: Log output and record after brightness changes;
- Part 13: Update color temperature adjustment state;
- Part 14: Processing after Display status and brightness Settings are completed.
Parts 1, 2, 4, 11, and 14 are the key processes involved in the on-off screen. Parts 1 and 2 determine the Display state to be set according to the policy in the PMS. This is easy to understand and annotated in the code, so the following steps are directly started from Part4.
3. AnimateScreenStateChange () out the screen animated execution and update the Display state
After determining the Display State to set, use the animateScreenStateChange() method to set it:
private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
if (mColorFadeEnabled &&
(mColorFadeOnAnimator.isStarted() || mColorFadeOffAnimator.isStarted())) { // If the ColorFade animation is already underway, return it directly when it is not display.on
if(target ! = Display.STATE_ON) {return;
}
// Indicates whether the screen has been set to fade (ColorFade, black screen)
mPendingScreenOff = false;
}
// Do you need to transition to the OFF state before exiting the Doze state
if (mDisplayBlanksAfterDozeConfig // The default is fale&& Display.isDozeState(mPowerState.getScreenState()) && ! Display.isDozeState(target)) { mPowerState.prepareColorFade(mContext, mColorFadeFadesConfig ? ColorFade.MODE_FADE : ColorFade.MODE_WARM_UP);if(mColorFadeOffAnimator ! =null) {
mColorFadeOffAnimator.end();
}
// Go to the OFF statesetScreenState(Display.STATE_OFF, target ! = Display.STATE_OFF/*reportOnly*/);
}
// If the Display OFF request is received, the Display state is directly set to OFF without waiting for the completion of the Display OFF animation
if(mPendingScreenOff && target ! = Display.STATE_OFF) { setScreenState(Display.STATE_OFF); mPendingScreenOff =false; / / reset
mPowerState.dismissColorFadeResources(); / / remove ColorFade
}
// Follow the request status
if (target == Display.STATE_ON) { // Display The target status is on
// Set Display with DisplayPowerState and notify PhoneWindowManager, WMS callback returns true
if(! setScreenState(Display.STATE_ON)) {return;
}
// Whether a bright-screen animation is used. The default is false
if (USE_COLOR_FADE_ON_ANIMATION && mColorFadeEnabled && mPowerRequest.isBrightOrDim()) {
if (mPowerState.getColorFadeLevel() == 1.0 f) {
mPowerState.dismissColorFade();
} else if (mPowerState.prepareColorFade(mContext,
mColorFadeFadesConfig ?
ColorFade.MODE_FADE :
ColorFade.MODE_WARM_UP)) {
mColorFadeOnAnimator.start(); // Start the transition of the screen animation
} else{ mColorFadeOnAnimator.end(); }}else { // If no ColorFade animation is used, set the ColorFade level to 1(full transparency).
mPowerState.setColorFadeLevel(1.0 f); mPowerState.dismissColorFade(); }}else if (target == Display.STATE_VR) { // Display target state is VR, this state is omitted
/ /...
} else if (target == Display.STATE_DOZE) { // Display target state is DOZE
// If you are performing the brightness setting process while the screen is on, return first
if (mScreenBrightnessRampAnimator.isAnimating()
&& mPowerState.getScreenState() == Display.STATE_ON) {
return;
}
// Set the Doze state
if(! setScreenState(Display.STATE_DOZE)) {return;
}
mPowerState.setColorFadeLevel(1.0 f);
mPowerState.dismissColorFade();
} else if (target == Display.STATE_DOZE_SUSPEND) { // Display target state is STATE_DOZE_SUSPEND
if(mScreenBrightnessRampAnimator.isAnimating() && mPowerState.getScreenState() ! = Display.STATE_DOZE_SUSPEND) {return;
}
// State must be STATE_DOZE before Display is set to STATE_DOZE_SUSPEND
if(mPowerState.getScreenState() ! = Display.STATE_DOZE_SUSPEND) {if(! setScreenState(Display.STATE_DOZE)) {return;
}
setScreenState(Display.STATE_DOZE_SUSPEND);
}
mPowerState.setColorFadeLevel(1.0 f);
mPowerState.dismissColorFade();
} else if (target == Display.STATE_ON_SUSPEND) { // Display the target state is STATE_ON_SUSPEND
if(mScreenBrightnessRampAnimator.isAnimating() && mPowerState.getScreenState() ! = Display.STATE_ON_SUSPEND) {return;
}
// State must be STATE_ON before Display is set to STATE_ON_SUSPEND
if(mPowerState.getScreenState() ! = Display.STATE_ON_SUSPEND) {if(! setScreenState(Display.STATE_ON)) {return;
}
setScreenState(Display.STATE_ON_SUSPEND);
}
mPowerState.setColorFadeLevel(1.0 f);
mPowerState.dismissColorFade();
} else { // If only STATE_OFF is left, the screen is off
mPendingScreenOff = true; // Indicates the start of the ColorFade animation
if(! mColorFadeEnabled) {// If ColorFade is not supported, add it directly
mPowerState.setColorFadeLevel(0.0 f);
}
// The ColorFade animation has been executed, so start setting the STATE_OFF state
if (mPowerState.getColorFadeLevel() == 0.0 f) {
setScreenState(Display.STATE_OFF);
mPendingScreenOff = false; / / reset
mPowerState.dismissColorFadeResources();
} else if(performScreenOffTransition && mPowerState.prepareColorFade(mContext, mColorFadeFadesConfig ? ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN) && mPowerState.getScreenState() ! = Display.STATE_OFF) {// If the above conditions are not met, enter here and start executing the animation, the first time will enter the else-if block
mColorFadeOffAnimator.start(); // Start performing the screen-off animation
} else {
mColorFadeOffAnimator.end(); // The screen is off}}}Copy the code
This method is also long, but has only two effects:
- Call setScreenState() to continue setting the Display state;
- Perform the on-off animation with ColorFade.
ColorFade is a mask that is completely transparent when its level is set to 1 and black when its level is set to 0. When the screen lights up, gradually set the level to 1 to give the effect of gradually lighting up the screen. When the screen is off, the level is gradually set to 0.
This method can be seen that, when the screen is on, set the Display state first, and then set the ColorFadelevel to 1; When the screen is off, set the ColorFade level to 0 and then set the Display state. This difference results in setting state and brightness priorities during the final on-off screen.
Next, the setScreenState() method is executed:
private boolean setScreenState(int state, boolean reportOnly) {
// Whether to set the OFF state
final boolean isOff = (state == Display.STATE_OFF);
// If the current state is different from the target state
if(mPowerState.getScreenState() ! = state) {If it is not caused by the PSensor, it reports the status to the PhoneWindowManager
if(isOff && ! mScreenOffBecauseOfProximity) {if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON) {
// Record the status
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_OFF);
blockScreenOff();
// Notify PhoneWindowManager that the screen is off
mWindowManagerPolicy.screenTurningOff(mPendingScreenOffUnblocker);
unblockScreenOff();
} else if(mPendingScreenOffUnblocker ! =null) {
return false; }}// reportOnly is ignored, which is generally false
if(! reportOnly) {// Go to DisplayPowerState and set the Display statemPowerState.setScreenState(state); }}if(isOff && mReportedScreenStateToPolicy ! = REPORTED_TO_POLICY_SCREEN_OFF && ! mScreenOffBecauseOfProximity) {// Record the status
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF);
// Unblock
unblockScreenOn();
mWindowManagerPolicy.screenTurnedOff(); // Notify PhoneWindowManager that the screen is off
} else if(! isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_OFF) {// In this case, the user intends to turn on the screen after the screen is half off. In this case, the user should also complete the process of turning off the screen
unblockScreenOff();
mWindowManagerPolicy.screenTurnedOff(); // Notify PhoneWindowManager that the screen is off
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF);
}
// The state is changed from OFF to another state
if(! isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) { setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_ON);if (mPowerState.getColorFadeLevel() == 0.0 f) {
// ColorFade level is always 0, which makes it impossible to set the brightness of the screen and blocks the brightness process until a callback is received in WMS
blockScreenOn();
} else {
unblockScreenOn(); // Unblock
}
mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker); // Notify PhoneWindowManager that the screen is off
}
/ / mPendingScreenOnUnblocker in unblockScreenOn () set to null, said unblocked
return mPendingScreenOnUnblocker == null;
}
Copy the code
In this method, you set the Display state and notify the PhoneWindowManager. MReportedScreenStateToPolicy variable is used to record the current state, according to the different states to PhoneWindowManager notice. When the Display state changes, the value will be set to the corresponding value whenever a certain step is taken. There are four values in total:
// Set the non-off state, or OFF state
private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0;
// Start setting the non-off state
private static final int REPORTED_TO_POLICY_SCREEN_TURNING_ON = 1;
// Complete in non-off state
private static final int REPORTED_TO_POLICY_SCREEN_ON = 2;
// Start setting the non-off state
private static final int REPORTED_TO_POLICY_SCREEN_TURNING_OFF = 3;
Copy the code
Based on these values, notify the PhoneWindowManger to perform the corresponding action. If, at the beginning of the bright screen will call mWindowManagerPolicy. ScreenTurningOn (mPendingScreenOnUnblocker), WMS module corresponding processing, after receiving the call will be made in the process, Because mPendingScreenOnUnblocker object is not empty, setScreenState () returns false, lead to blocking colorFade set, thus unable to set the screen brightness.
In WMS processing has been completed, and through callback DMS mPendingScreenOnUnblocker parameters, and through unblockScreenOn () method, which will be mPendingScreenOnUnblocker object is null:
private void unblockScreenOn(a) {
if(mPendingScreenOnUnblocker ! =null) {
mPendingScreenOnUnblocker = null;
longdelay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime; }}Copy the code
Again into setScreenState (after), because mPendingScreenOnUnblocker has to null, therefore does not block ColorFade and brightness Settings. Next, go to DisplayPowerState#setScreenState() to further set the state of Display.
4.DisplayPowerState#setScreenState() sets the state
DisplayPowerState represents the overall state of the current Display, including Display state, brightness and ColorFade Level value. All values related to Display will be entered into DisplayPowerState for setting at last. SetScreenState () as follows:
public void setScreenState(int state) {
if(mScreenState ! = state) { mScreenState = state;// Update the current Display state
mScreenReady = false; // Indicates that the update of Display state, brightness and ColorFade level is not completed
scheduleScreenUpdate(); // Perform the update operation}}Copy the code
The mScreenState variable is updated to false to indicate that the Display state has not been updated, and the scheduleScreenUpdate() method is called. The scheduleScreenUpdate() method analyzes the process in the DisplayController after it has been analyzed.
5. AnimateScreenBrightness update brightness ()
Back in updatePowerState(), after executing Part4, let’s look at the setting of brightness in Part11. To set the brightness value use the animateScreenBrightness() method:
private void animateScreenBrightness(float target, int rate) {
/ / mScreenBrightnessRampAnimator began to set the brightness
if(mScreenBrightnessRampAnimator.animateTo(target, rate)) { ....... }}Copy the code
The first parameter represents the luminance value to be set, and the second parameter represents the rate at which the luminance value is set. Obtaining the luminance value and the luminance setting rate value, as well as the luminance animation, will be analyzed in detail in the luminance setting section later. This article will focus on the setting process.
Brightness Settings, not as complicated as setting Display state, mScreenBrightnessRampAnimator is a RampAnimator object, class, the class is a custom animation dedicated to update the brightness. After animateTo() of this class, it will finally call the setScreenBrightness() method of DisplayPowerState to set the brightness to DisplayPowerState.
DisplayPowerState#setScreenBrightness() set brightness
public void setScreenBrightness(float brightness) {
if(mScreenBrightness ! = brightness) {// Update the current brightness value
mScreenBrightness = brightness;
if(mScreenState ! = Display.STATE_OFF) {// Indicates that the update of Display state, brightness and ColorFade level is not completed
mScreenReady = false;
// Perform the update operationscheduleScreenUpdate(); }}}Copy the code
The mScreenBrightness variable was updated and scheduleScreenUpdate() was called to start the update operation. The state and brightness of the Display are now passed to DisplayPowerState, which will begin with the scheduleScreenUpdate() method.
ScheduleScreenUpdate () executes the update
private void scheduleScreenUpdate(a) {
if(! mScreenUpdatePending) {// Indicates that the Display status will be updated
mScreenUpdatePending = true; postScreenUpdateThreadSafe(); }}private void postScreenUpdateThreadSafe(a) {
mHandler.removeCallbacks(mScreenUpdateRunnable);
mHandler.post(mScreenUpdateRunnable);
}
Copy the code
MScreenUpdatePending (true) endgame (screenUpdatepending) endGame (true) endGame (true) endGame (true) endGame (true) endGame (true) endGame (true) endGame (true) endGame (true) endGame
private final Runnable mScreenUpdateRunnable = new Runnable() {
@Override
public void run(a) {
mScreenUpdatePending = false;
// Confirm the final brightness. When the Display state is OFF, or when the ColorFade level is 0, it will be set to 0, otherwise it will be set to the brightness value passed in the DPC
floatbrightnessState = mScreenState ! = Display.STATE_OFF && mColorFadeLevel >0f ? mScreenBrightness : PowerManager.BRIGHTNESS_OFF_FLOAT;
The PhotonicModulator is a separate thread used to update Display status and brightness
if (mPhotonicModulator.setState(mScreenState, brightnessState)) {
// The update is complete
mScreenReady = true;
invokeCleanListenerIfNeeded();
} else{}}};Copy the code
There is another confirmation of the brightness value to be updated, a final brightness value based on the Display state, ColorFade, and then the update starts in the mPhotonicModulator.
PhotonicModulator#setState() updates the child thread
PhotonicModulator is a class that inherits Thread and is used to update Display state and brightness. Therefore, updating screen state and backlight is done asynchronously in a separate Thread. The setState() method is as follows:
public boolean setState(int state, int backlight) {
synchronized (mLock) {
// Whether the Display state is changed. MPendingState indicates the state that is to be set, and will not be cleared after the setting
booleanstateChanged = state ! = mPendingState;// Whether the brightness has changed, mPendingBacklight indicates the brightness to be set, and will not be cleared after setting
booleanbacklightChanged = backlight ! = mPendingBacklight;// When either the Display status or brightness changes, the update starts
if (stateChanged || backlightChanged) {
mPendingState = state; // Update the mPendingState value
mPendingBacklight = backlight; // Update the mPendingBacklight value
// Indicates whether the change process is in progress
boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
mStateChangeInProgress = stateChanged || mStateChangeInProgress;
mBacklightChangeInProgress = backlightChanged || mBacklightChangeInProgress;
// Invoke the PhotonicModulator thread when not in the change process
if (!changeInProgress) {
mLock.notifyAll();
}
}
return! mStateChangeInProgress;// Return true as soon as the State update is complete}}Copy the code
When either screen state or brightness changes, a notifyAll() is used to wake up the PhotonicModulator thread, which then executes its Run () method. This is a production-consumer model that must have waited () somewhere else. Let’s look at its run() method:
public void run(a) {
for (;;) {
final int state;
final boolean stateChanged;
final int backlight;
final boolean backlightChanged;
synchronized (mLock) {
state = mPendingState;
// mActualState indicates the actual Display statestateChanged = (state ! = mActualState); backlight = mPendingBacklight;// mActualBacklight indicates the actual brightnessbacklightChanged = (backlight ! = mActualBacklight);if(! stateChanged) {// Initiate the update process again
postScreenUpdateThreadSafe();
mStateChangeInProgress = false;
}
if(! backlightChanged) { mBacklightChangeInProgress =false;
}
if(! stateChanged && ! backlightChanged) {try {
// After state and brightness are set, the thread enters wait state
mLock.wait();
} catch (InterruptedException ex) { }
continue;
}
mActualState = state;
mActualBacklight = backlight;
}
// Call DisplayBlanker to request DisplaymBlanker.requestDisplayState(state, backlight); }}Copy the code
After the Display status and brightness are updated, the thread is WAITTING using object.wait (). In this way, the Display state and brightness are constantly set.
. In the end, the call mBlanker requestDisplayState () to set, the next step to here again after the DMS, the final state of the specific object of DisplayDevice and brightness Settings, this logic is in the middle of the skip.
9.LocalDisplayDevice#requestDisplayStateLocked()
RequestDisplayStateLocked () to a specific physical screen to set the new Display state and brightness values:
@Override
public Runnable requestDisplayStateLocked(final int state, final float brightnessState) {
final booleanstateChanged = (mState ! = state);final booleanbrightnessChanged = (! BrightnessSynchronizer.floatEquals( mBrightnessState, brightnessState)) && mBacklight ! =null;
if (stateChanged || brightnessChanged) {
......
return new Runnable() {
@Override
public void run(a) {...// Set brightness
if (brightnessChanged || vrModeChange) {
setDisplayBrightness(brightnessState);
}
// Set the state
if (state != currentState) {
setDisplayState(state);
}
}
private void setDisplayState(int state) {...try {
SurfaceControl.setDisplayPowerMode(token, mode);
} finally{}}private void setDisplayBrightness(float brightness) {
try {
if(mBacklight ! =null) { mBacklight.setBrightness(brightness); }}finally{}}}; }return null;
}
Copy the code
Finally, the brightness is set to The LightsService and the state is set to the SurfaceControl, and the two modules will set the brightness and state respectively to the SurfaceFlinger.
Back in updatePowerState(), in Part14, mDisplayReadyLocked is set to true after the Display status and brightness are set, indicating that the Display status update is complete. And in sendOnStateChangedWithWakelock () method of the callback PMS, the PMS again initiated the request, because mDisplayReadyLocked has become true, so returns true, the PMS will think the DMS to request processing is completed.
The above is the on-off screen process involved in display module. Combined with the previous two on-off screen processes in THE PMS, the on-off screen processes in the Framework layer are analyzed.
Sequence diagram of bright screen:
Screen off sequence diagram: