SoFunction
Updated on 2025-03-01

Analysis of the screen-bright process example of PowerManagerService

Preface

There are many ways to light up the screen, the most commonly used one is to light up the screen with the Power key. This process is relatively simple. This article hopes to analyze this process to clarify the useful process of operating the screen and lay the foundation for the subsequent articles.

Power keys to light up the screen

This article uses the Power key to light up the screen as an example for analysis, and it will callPowerManagerService#wakeUp()

// 
@Override // Binder call
public void wakeUp(long eventTime, @WakeReason int reason, String details,
        String opPackageName) {
    // ...
    try {
        // Can only wake up the display screen under default display group        wakeDisplayGroup(Display.DEFAULT_DISPLAY_GROUP, eventTime, reason, details, uid,
                opPackageName, uid);
    } finally {
        (ident);
    }
}  
private void wakeDisplayGroup(int groupId, long eventTime, @WakeReason int reason,
        String details, int uid, String opPackageName, int opUid) {
    synchronized (mLock) {
        // 1. Update wakefulness to WAKEFULNESS_AWAKE        // Including wakefulness that updates PowerManagerService and DisplayGroupPowerStateMapper        if (wakeDisplayGroupNoUpdateLocked(groupId, eventTime, reason, details, uid,
                opPackageName, opUid)) {
            // 2. Update power status            updatePowerStateLocked();
        }
    }
} 

Notice,PowerManagerService#wakeUp()Only the screens under default grouping can be operated.

Android has added a grouping function to multiple screens since some time ago. Mobile phones usually have only one screen, which belongs to the default grouping.

There are two steps to light up the screen

  • Update wakefulness to WAKEFULNESS_AWAKE. Mainly updates the wakefulness of PowerManagerService and DisplayGroupPowerStateMapper.
  • Update power status. The process of lighting the screen is handled here.

1. Update wakefulness

private boolean wakeDisplayGroupNoUpdateLocked(int groupId, long eventTime,
        @WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
    // ...
    try {
        // ...
        // Set wakefulness to WAKEFULNESS_AWAKE        setWakefulnessLocked(groupId, WAKEFULNESS_AWAKE, eventTime, uid, reason, opUid,
                opPackageName, details);
        // Update the information of the grouping display        (groupId, eventTime);
        (groupId, true);
    } 
    return true;
}
void setWakefulnessLocked(int groupId, int wakefulness, long eventTime, int uid, int reason,
        int opUid, String opPackageName, String details) {
    // 1. Update wakefulness of DisplayGroupPowerStateMapper    if ((groupId, wakefulness)) {
        // display group wakefulness has changed        mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS;
        // 2. Update PMS' wakefulness        // Note that the first parameter takes the maximum wakefulness of all display groups, and the priority is as follows        //  PowerManagerInternal#WAKEFULNESS_AWAKE
        //  PowerManagerInternal#WAKEFULNESS_DREAMING
        //  PowerManagerInternal#WAKEFULNESS_DOZING
        //  PowerManagerInternal#WAKEFULNESS_ASLEEP
        // TODO: Why is the wakefulness of PMS to be set to the largest wakefulness of all display groups?        setGlobalWakefulnessLocked((),
                eventTime, reason, uid, opUid, opPackageName, details);
        if (wakefulness == WAKEFULNESS_AWAKE) {
            // Kick user activity to prevent newly awake group from timing out instantly.
            // 3. Save the time of user behavior            userActivityNoUpdateLocked(
                    groupId, eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
        }
    }
}    

The process of updating wakefulness to WAKEFULNESS_AWAKE is as follows

  • Update the wakefulness of DisplayGroupPowerStateMapper to WAKEFULNESS_AWAKE.
  • Update the wakefulness of PMS to WAKEFULNESS_AWAKE. Here, other system components will be notified that wakefulness/interaction status has changed. See [1.1 Update PMS wakefulness
  • Save the time for user behavior. This time is used to determine the time to automatically shut down the screen. See [1.2 Save user behavior time

1.1 Update PMS wakefulness

// 
private void setGlobalWakefulnessLocked(int wakefulness, long eventTime, int reason, int uid,
        int opUid, String opPackageName, String details) {
    if (getWakefulnessLocked() == wakefulness) {
        return;
    }
    // Phase 1: Handle pre-wakefulness change bookkeeping.
    final String traceMethodName;
    switch (wakefulness) {
        // ...
        case WAKEFULNESS_AWAKE:
            // Save the time to wake up the device            // This time will be used later when updating user behavior            mLastWakeTime = eventTime;
            mLastWakeReason = reason;
            break;
        // ...
    }
    try {
        // Phase 2: Handle wakefulness change and bookkeeping.
        // Under lock, invalidate before set ensures caches won't return stale values.
        ();
        // Update wakefulness-related variables of PMS        mWakefulnessRaw = wakefulness;
        mWakefulnessChanging = true;
        // mDirty set DIRTY_WAKEFULNESS, indicating that the wakefulness of PMS has changed        mDirty |= DIRTY_WAKEFULNESS;
        mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING);
        // Notify other components, wakefulness changes or interactive state changes        if (mNotifier != null) {
            (wakefulness, reason, eventTime);
        }
        (wakefulness);
        // Phase 3: Handle post-wakefulness change bookkeeping.
        switch (wakefulness) {
            case WAKEFULNESS_AWAKE:
                // Record and detect whether there is permission                (reason, details, uid, opPackageName, opUid);
                if (sQuiescent) {
                    mDirty |= DIRTY_QUIESCENT;
                }
                break;
            // ...
        }
    } finally {
        (Trace.TRACE_TAG_POWER);
    }
}

According to the English comments, the wakefulness process of updating the PMS is divided into three stages. The most important thing is that in the second stage, update wakefulness-related variables, and then Notifier notifies other components and sends a screen-lit notification. The process is as follows, just take a look, this is not the point.

// 
public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
    // Determine whether the new wakefulness is interactive    // WAKEFULNESS_AWAKE is interactive    final boolean interactive = (wakefulness);
    // 1. Notify AMS wakefulness has changed    (new Runnable() {
        @Override
        public void run() {
            (wakefulness);
        }
    });
    // 2. Handle interaction state changes    // Handle any early interactive state changes.
    // Finish pending incomplete ones from a previous cycle.
    // Handle early interactive state changes    if (mInteractive != interactive) {
        // Finish up late behaviors if needed.
        // mInteractiveChanging is true, indicating that the last processing process has not been completed yet        // Here we will first execute the previous process        if (mInteractiveChanging) {
            handleLateInteractiveChange();
        }
        // 2.1 Update the interactive status of system components        // Start input as soon as we start waking up or going to sleep.
        (interactive);
        (interactive);
        // ...
        // Handle early behaviors.
        // 2.2 Update variables about interaction state        mInteractive = interactive;
        mInteractiveChangeReason = reason;
        mInteractiveChangeStartTime = eventTime;
        // The interaction state is changing        mInteractiveChanging = true;
        // 2.3 Handle early interactive state changes tasks        handleEarlyInteractiveChange();
    }
}
private void handleEarlyInteractiveChange() {
    synchronized (mLock) {
        if (mInteractive) {
            // Notify PhoneWindowManager, PhoneWindowManager notify SystemUI keyguard            (() -> (mInteractiveChangeReason));
            // Send a bright screen broadcast            mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
            mPendingWakeUpBroadcast = true;
            updatePendingBroadcastLocked();
        } else {
            // ...
        }
    }
}    

1.2 Save user behavior time

// 
private boolean userActivityNoUpdateLocked(int groupId, long eventTime, int event, int flags,
        int uid) {
    if (eventTime < mLastSleepTime || eventTime < mLastWakeTime || !mSystemReady) {
        return false;
    }
    (Trace.TRACE_TAG_POWER, "userActivity");
    try {
        if (eventTime > mLastInteractivePowerHintTime) {
            setPowerBoostInternal(, 0);
            mLastInteractivePowerHintTime = eventTime;
        }
        // 1. Notify the system components that user behavior occurs        (event, uid);
        (eventTime, event);
        if (mUserInactiveOverrideFromWindowManager) {
            mUserInactiveOverrideFromWindowManager = false;
            mOverriddenTimeout = -1;
        }
        final int wakefulness = (groupId);
        if (wakefulness == WAKEFULNESS_ASLEEP
                || wakefulness == WAKEFULNESS_DOZING
                || (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
            return false;
        }
        maybeUpdateForegroundProfileLastActivityLocked(eventTime);
        if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
            // Here is the logic to extend the time of the screen to light up...        } else {
            if (eventTime > (
                    groupId)) {
                // 2. Save user activity time                (groupId, eventTime);
                // 3. mDirty sets the DIRTY_USER_ACTIVITY flag bit,                // Indicates that the user activity has been updated                mDirty |= DIRTY_USER_ACTIVITY;
                if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
                    mDirty |= DIRTY_QUIESCENT;
                }
                return true;
            }
        }
    } finally {
        (Trace.TRACE_TAG_POWER);
    }
    return false;
}

The process of updating user behavior by PMS

  • Notify other components of user behavior through Notifier.
  • DisplayGroupPowerStateMapper Saves the time for user behavior. This time will be used to determine the time to automatically shut down the screen.
  • mDirty Set the DIRTY_USER_ACTIVITY flag to indicate that the user activity has been updated, and the power status will be used to update later.

A brief look at the first step, as follows

    private void sendUserActivity(int event) {
        synchronized (mLock) {
            if (!mUserActivityPending) {
                return;
            }
            mUserActivityPending = false;
        }
        // I don't know what I've done here for the time being        TelephonyManager tm = ();
        ();
        // PhoneWindowManger will notify SystemUI        ();
        // If FaceDownDetector is performing the flip-down task, there is user behavior at this time, cancel this task        (event);
    }

1.3 Update wakefulness summary

Through the above analysis, we should see an essence, and the process of updating wakefulness is roughly as follows

  • Update the wakefulness of DisplayGroupPowerStateMapper, mDirty sets the flag DIRTY_DISPLAY_GROUP_WAKEFULNESS.
  • Update the wakefulness of PowerManagerService, mDirty setting flag bit DIRTY_WAKEFULNESS.
  • Notifier Notifies other components wakefulness/interaction status has changed and sends a broadcast with the on-screen/off screen.

2. Update power status

// 
private void updatePowerStateLocked() {
    if (!mSystemReady || mDirty == 0) {
        return;
    }
    // Pay attention to the technology here, the thread can determine whether a lock has been acquired    if (!(mLock)) {
        (TAG, "Power manager lock was not held when calling updatePowerStateLocked");
    }
    (Trace.TRACE_TAG_POWER, "updatePowerState");
    try {
        // Phase 0: Basic state updates.
        // Power saving mode function        updateIsPoweredLocked(mDirty);
        // "Charging function" in settings        updateStayOnLocked(mDirty);
        // Brightness increase function        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;
            // Include all wake locks into mWakeLockSummary            updateWakeLockSummaryLocked(dirtyPhase1);
            // 1. Update user behavior            updateUserActivitySummaryLocked(now, dirtyPhase1);
            updateAttentiveStateLocked(now, dirtyPhase1);
            // Decide whether to enter sleep/dream/doze state            // If you enter a certain state, wakefulness will be updated, so here we need to update the above things through a loop            if (!updateWakefulnessLocked(dirtyPhase1)) {
                break;
            }
        }
        // Phase 2: Lock profiles that became inactive/not kept awake.
        updateProfilesLocked(now);
        // Phase 3: Update display power state.
        // 2. Update the power status of the display        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);
    }
}

All functions of PowerManagerService are concentrated in this function, but there are two main steps related to the bright screen.

  • updateUserActivitySummaryLocked()Update user behavior. This user behavior determines the final brightness of the screen. See [2.1 Update user behavior
  • updateDisplayPowerStateLocked()Updates the power status of the display, which initiates a power request for DisplayManagerService, thereby determining the brightness of the screen. See [2.2 Update the power status of the display

2.1 Update user behavior

// 
private void updateUserActivitySummaryLocked(long now, int dirty) {
    // Update the status of the user activity timeout timer.
    if ((dirty & (DIRTY_DISPLAY_GROUP_WAKEFULNESS | DIRTY_WAKE_LOCKS
            | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) == 0) {
        return;
    }
    (MSG_USER_ACTIVITY_TIMEOUT);
    // Default is -1    final long attentiveTimeout = getAttentiveTimeoutLocked();
    // Hibernation timeout, default is -1    final long sleepTimeout = getSleepTimeoutLocked(attentiveTimeout);
    // Screen timeout    long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout,
            attentiveTimeout);
    // dim duration = 20 % screen off timeout
    final long screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
    screenOffTimeout =
            getScreenOffTimeoutWithFaceDownLocked(screenOffTimeout, screenDimDuration);
    final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
    long nextTimeout = -1;
    boolean hasUserActivitySummary = false;
    // 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            // 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;
                    }
                }
            }
            // Timeout, but because a certain lock is released, the screen time needs to be extended            if (groupUserActivitySummary == 0
                    && lastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                // ...
            }
            // General timeout situation,            if (groupUserActivitySummary == 0) {
                // ...
            }
            // When PhoneWindowManager handles KeyEvent.KEYCODE_SOFT_SLEEP, userInactiveOverride is true            // KeyEvent.KEYCODE_SOFT_SLEEP hibernation button of this software?            if (groupUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM
                    && userInactiveOverride) {
                // ...
            }
            // The user behavior is to light the screen, and WakeLock does not keep the screen lit up, use AttentionDetector to calculate the screen timeout time again            if ((groupUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
                    && ((groupId)
                    & WAKE_LOCK_STAY_AWAKE) == 0) {
                // ...
            }
            hasUserActivitySummary |= groupUserActivitySummary != 0;
            if (nextTimeout == -1) {
                nextTimeout = groupNextTimeout;
            } else if (groupNextTimeout != -1) {
                // Here it indicates the case of nextTimeout != -1, which also indicates that there are multiple display groups                // From here, we can see that the timeout time of multiple display groups is the same                nextTimeout = (nextTimeout, groupNextTimeout);
            }
        }
        // 2. DisplayGroupPowerStateMapper Saves user behavior        (groupId,
                groupUserActivitySummary);
        }
    } // traversal display group id ends    final long nextProfileTimeout = getNextProfileTimeoutLocked(now);
    if (nextProfileTimeout > 0) {
        nextTimeout = (nextTimeout, nextProfileTimeout);
    }
    // 3. Regularly update power status    // This step decides to automatically shut down the screen    if (hasUserActivitySummary && nextTimeout >= 0) {
        scheduleUserInactivityTimeout(nextTimeout);
    }
}

This function is not only used to update user behavior, but also updates the screen timeout time, and regularly updates the power state to achieve the function of automatically extinguishing the screen.

Update user behavior In step 1, when updating wakefulness, PMS saves the wakefulness time mLastWakeTime, and DisplayGroupPowerStateMapper saves the user behavior time. Therefore, for the process from the screen-off state to the screen-on state, the value of the user behavior is now USER_ACTIVITY_SCREEN_BRIGHT, indicating that the user behavior is the screen-on.

2.2 Update the power status of the display

// 
private boolean updateDisplayPowerStateLocked(int dirty) {
    final boolean oldDisplayReady = ();
    if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
            | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
            | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
            DIRTY_QUIESCENT | DIRTY_DISPLAY_GROUP_WAKEFULNESS)) != 0) {
        if ((dirty & DIRTY_QUIESCENT) != 0) {
            // ...
        }
        // traversal display group        for (final int groupId : ()) {
            // 1. Get the request to display group            final DisplayPowerRequest displayPowerRequest =
                    (groupId);
            // 2. Update various parameters of the request            // Update the requested policy parameters. The so-called policy is to light the screen, or to turn off the screen, or make the screen dim, etc.             = getDesiredScreenPolicyLocked(groupId);
            // ...Omit the process of updating other request parameters...            // 3. Make a request to DisplayManagerService            // If this request is different from the last request, then the processing of this request is an asynchronous processing process, and false is returned at this time.            // Otherwise, no processing is required and returns true directly.            final boolean ready = (groupId,
                    displayPowerRequest, mRequestWaitForNegativeProximity);
            // Update the ready status of DisplayGroupPowerStateMapper            final boolean displayReadyStateChanged =
                    (groupId, ready);
            // If the asynchronous request is processed, DMS will call back to notify PMS, and PMS will update the status and go here.            // If the screen is turned on for too long, then use log to record it            final boolean poweringOn =
                    (groupId);
            if (ready && displayReadyStateChanged && poweringOn
                    && (
                    groupId) == WAKEFULNESS_AWAKE) {
                (groupId, false);
                (Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
                final int latencyMs = (int) (()
                        - (groupId));
                if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
                    (TAG, "Screen on took " + latencyMs + " ms");
                }
            }
        }
        mRequestWaitForNegativeProximity = false;
    }
    // The return value indicates whether it changes from a non-ready state to a ready state    return () && !oldDisplayReady;
}

The power status of the screen is very clear, as follows

  • First get the request and update the request parameters. Among the request parameters, the main concern is the policy parameters, which determine the status of the screen, that is, whether the screen is on or off.
  • Make a request to DisplayManagerService. Note that if the current request is different from the last request, the processing is asynchronous and the returned ready state is false. Otherwise, the processing is synchronous and the returned ready is true.

Let's take a look at how to update the request policy

// 
 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) {
        // ...
    }
    if (mIsVrModeEnabled) {
        return DisplayPowerRequest.POLICY_VR;
    }
    // Since the UserActivity at this time is USER_ACTIVITY_SCREEN_BRIGHT, the policy is DisplayPowerRequest.POLICY_BRIGHT    if ((wakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
            || !mBootCompleted
            || ((groupId)
            & USER_ACTIVITY_SCREEN_BRIGHT) != 0
            || mScreenBrightnessBoostInProgress) {
        return DisplayPowerRequest.POLICY_BRIGHT;
    }
    return DisplayPowerRequest.POLICY_DIM;
}

The user behavior we just analyzed is USER_ACTIVITY_SCREEN_BRIGHT, so the policy is ultimately DisplayPowerRequest.POLICY_BRIGHT. When a request is initiated to DisplayManagerService, the screen will eventually light up.

2.3 Handling updates to screen status

As we mentioned earlier, the process of processing screen requests may be asynchronous or synchronous. If the process from the screen to the screen opening is bound to the screen opening, the process must be asynchronous. So how does PowerManagerService know that the DisplayManagerService has been processed? In fact, PowerManagerService has registered a callback to DisplayManagerService

// 
public void systemReady(IAppOpsService appOps) {
    synchronized (mLock) {
        (
                mDisplayPowerCallbacks, mHandler, sensorManager);                 
    }
}
private final  mDisplayPowerCallbacks =
        new () {
    @Override
    public void onStateChanged() {
        synchronized (mLock) {
            // Indicates that the screen status has been updated            mDirty |= DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED;
            updatePowerStateLocked();
        }
    }
}    

When the PowerManagerService learns through the callback that the DisplayManagerService has processed the screen request, it updates the power status again.

at this time,updateDisplayPowerStateLocked()Then initiate a request to DisplayManagerService. Since it is the same as the last request, DisplayManagerService does not process it, and the returned ready status is true.

The remaining process of updating the power state is the ending. Let's take a look at it roughly

// 
private void finishWakefulnessChangeIfNeededLocked() {
    // Note that one of the conditions is that all display groups need to be ready    if (mWakefulnessChanging && ()) {
        // ...
        // The display is ready, and the work of changing PMS wakefulness is considered to be completed        mWakefulnessChanging = false;
        // Notier notifies that wakefulness changes have been completed        ();
    }
}
// 
public void onWakefulnessChangeFinished() {
    if (mInteractiveChanging) {
        mInteractiveChanging = false;
        // Post-tasks that handle interaction state        handleLateInteractiveChange();
    }
}
private void handleLateInteractiveChange() {
    synchronized (mLock) {
        final int interactiveChangeLatency =
                (int) (() - mInteractiveChangeStartTime);
        if (mInteractive) {
            // Finished waking up...
            (() -> {
                // Notify PhoneWindowManager to complete the device wake-up work                (mInteractiveChangeReason);
            });
        } else {
            // ...
        }
    }
}

2.4 Summary

We analyze the process from extinguishing the screen to extinguishing the screen, but we should see an essential problem. It is actually to initiate a request to the DisplayManagerService to update the screen status (such as turning on the screen, extinguishing the screen).

The requested policy ultimately determines the state of the screen, but there are many factors that affect the requested policy, such as system status (referring to the wakefulness of the PMS), user behavior, wake-up lock, etc. We will see more about deciding on request strategies in a later article.

Summarize

Although this article analyzes the process from extinguishing the screen to turning on the screen, we need to see an essential process, which is actually only two steps.

  • Update wakefulness.
  • Send a request to DisplayManagerService to update the screen status.

The above is the detailed analysis of the PowerManagerService's screen-brightening process example. For more information about the PowerManagerService screen-brightening process, please pay attention to my other related articles!