android亮灭屏流程分析

news2025/5/16 11:22:45

前言

亮灭涉及的东西非常多,因此单独写一个文档,进行详细说明,亮灭屏包括的东西不只是亮灭屏,还包括亮度调节、屏幕状态变化等东西。本文仅作学习使用,不涉及商业,侵权请联系删除。

framework层的学习链接:Android R PowerManagerService模块(3) 亮屏流程 - 掘金 (juejin.cn)

一、概述

当响应按键事件时,屏幕的整个系统,一般分为两部分,按键事件传递流程和屏幕响应流程,中间通过策略类来衔接。如下图所示。框架上分为硬件层、驱动层、framework层。

对于事件的传递流程暂时不做了解,未来走TP流程的时候再细细琢磨,本文主讲屏幕响应的部分,将从上层应用走到底层硬件的所有流程。

对部分名词进行简称:PMS(PowerMangerService)

DMC(DisplayManagerControl)

DMS(DisplayManagerServices)

img

二、Framework

对于framework层的东西不是很了解,因此很多东西都是从网络上获取的知识加以理解,会存在些许错误,链接已在前言贴出,本文和链接中有些许不同,应该时android版本不同所致,且我的工作对于framework层的东西只是了解学习,主要还是底层。

1、亮屏

亮屏方式由很多种,如上图的Power键亮屏、插入充电器亮屏、来电亮屏…等等,虽然方式不太同,但是在屏幕响应部分的流程都是相同的。PMS中提供了 wakeUp() 方法用于点亮屏幕,因此从该函数为入口开始分析。

 void wakeUp(long eventTime, String reason, String opPackageName) //亮屏时间,亮屏原因,细节描述
-->wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
     //验证和亮屏状态更新
   -->wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)
     //更新状态
   -->updatePowerStateLocked();

1.1、wakeUpNoUpdateLocked()

此处,主要是更新wakefulness,

// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private boolean wakeUpNoUpdateLocked(long eventTime, @WakeReason int reason, String details,
        int reasonUid, String opPackageName, int opUid) {
    // 此次亮屏时间小于最近一次灭屏时间、已经处于亮屏、系统未启动完成或强制suspend,不会进行亮屏
    if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
            || !mBootCompleted || !mSystemReady || mForceSuspendActive) {
        return false;
    }
 
    try {
        mLastWakeTime = eventTime;  // 更新最后一次亮屏时间
        mLastWakeReason = reason;   // 更新亮屏原因
        // 更新mWakefulness值
        setWakefulnessLocked(WAKEFULNESS_AWAKE, reason, eventTime);
        // 通知其他组件亮屏动作
        mNotifier.onWakeUp(reason, details, reasonUid, opPackageName, opUid);
        // 更新用户活动时间
        userActivityNoUpdateLocked(
                eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return true;
}

首先,进行亮屏时间和状态的验证,如果满足以下三个条件之一,则亮屏不会成功,返回false,验证完成后,开始执行亮屏流程:

  • 此次亮屏时间小于最近一次灭屏时间;
  • 唤醒状态已经处于亮屏;
  • 系统未启动完成或强制suspend。

接下来,会更新mLastWakeTime和mLastWakeReason,表示最后一次亮屏时间和原因。

然后,调用 setWakefulnessLocked()方法来设置表示PMS唤醒状态mWakefulness的值为WAKEFULNESS_AWAKE。

最后,执行 userActivityNoUpdateLocked()方法更新用户活动时间。

setWakefulnessLocked()
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

    void setWakefulnessLocked(int wakefulness, int reason) {
        if (mWakefulness != wakefulness) {
	    PowerManager.invalidateIsInteractiveCaches();
	    //更新wakefulness
            mWakefulness = wakefulness;
            mWakefulnessChanging = true;
            mDirty |= DIRTY_WAKEFULNESS;
        // mNotifier中做mWakefuless转变的开始工作,通知其它组件,wakefulness改变 或者 交互状态改变
            if (mNotifier != null) {
                mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
            }
        }
    }

这里会将mWakefulness的值设置为WAKEFULNESS_AWAKE,表示屏幕状态为Awake,同时更新mDirty,后续会根据该值去更新电源状态。然后通过Notifier#onWakefulnessChangeStarted()方法进行屏幕状态开始改变但未完成切断的工作(如亮灭屏广播),具体可以在前言的链接中去做了解。

1.2、wakefulness的值

上边讲了的wakefulness 表示设备处于何种状态,非常重要,它有四个值,如下

public abstract class PowerManagerInternal {
    /**
     * Wakefulness: The device is asleep.  It can only be awoken by a call to wakeUp().
     * The screen should be off or in the process of being turned off by the display controller.
     * The device typically passes through the dozing state first.
     */
    public static final int WAKEFULNESS_ASLEEP = 0;

    /**
     * Wakefulness: The device is fully awake.  It can be put to sleep by a call to goToSleep().
     * When the user activity timeout expires, the device may start dreaming or go to sleep.
     */
    public static final int WAKEFULNESS_AWAKE = 1;

    /**
     * Wakefulness: The device is dreaming.  It can be awoken by a call to wakeUp(),
     * which ends the dream.  The device goes to sleep when goToSleep() is called, when
     * the dream ends or when unplugged.
     * User activity may brighten the screen but does not end the dream.
     */
    public static final int WAKEFULNESS_DREAMING = 2;

    /**
     * Wakefulness: The device is dozing.  It is almost asleep but is allowing a special
     * low-power "doze" dream to run which keeps the display on but lets the application
     * processor be suspended.  It can be awoken by a call to wakeUp() which ends the dream.
     * The device fully goes to sleep if the dream cannot be started or ends on its own.
     */
    public static final int WAKEFULNESS_DOZING = 3;
} 

翻译一下:
WAKEFULNESS_ASLEEP : 表示设备处于休眠状态。屏幕处于灭屏状态,或者处于灭屏的过程中。设备只能被 wakeup() 唤醒,例如 Power 键唤醒设备。

WAKEFULNESS_AWAKE :表示设备处于唤醒状态。屏幕处于亮屏或者暗屏的状态。当用户行为超时(屏幕超时),设备可能会开启梦境(指屏保)或者进入休眠状态。
当然 goToSleep() 也能使设备进入休眠状态。

WAKEFULNESS_DREAMING :设备处于梦境状态,这里指的是显示屏保。可以通过 wakeup() 结束屏保,唤醒设备,例如点击屏保。 也可以通过 goToSleep() 结
束屏保,使设备进入休眠,例如,屏保时按 Power 键。

WAKEFULNESS_DOZING : 设备处于打盹状态(dozing)。这种状态几乎是一种休眠状态,但是屏幕处于一种低功耗状态。系统会让 dream manager 启动一个 doze
 组件,这个组件会绘制一些简单的信息在屏幕上,但是前提是屏幕要支持 AOD(always on display)功能。我曾经买了一款 OLED 屏的手机,当关闭屏幕时,屏
幕会显示时间、通知图标,等等一些信息,当时就觉得相当炫酷,其实这就是 AOD 功能的实现。如果 doze 组件启动失败,那么设备就进入休眠状态。可以通过
 wakeup() 结束这个打盹状态,使设备处于唤醒状态,例如 Power 键亮屏。


1.3、updatePowerStateLocked()

更新电源状态。

// PowerManagerService.java

private void updatePowerStateLocked() {
    if (!mSystemReady || mDirty == 0) {
        return;
    }
    // 注意这里的技术,线程可以判断是否获取了某个锁
    if (!Thread.holdsLock(mLock)) {
        Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
    }
    Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
    try {
        // Phase 0: Basic state updates.
        // 省电模式功能
        updateIsPoweredLocked(mDirty);
        // 设置中"充电常亮功能"
        updateStayOnLocked(mDirty);
        // 亮度增加功能
        updateScreenBrightnessBoostLocked(mDirty);
        // Phase 1: Update wakefulness.
        // Loop because the wake lock and user activity computations are influenced
        // by changes in wakefulness.
        final long now = mClock.uptimeMillis();
        int dirtyPhase2 = 0;
        for (;;) {
            int dirtyPhase1 = mDirty;
            dirtyPhase2 |= dirtyPhase1;
            mDirty = 0;
            // 把所有的唤醒锁归纳到 mWakeLockSummary
            updateWakeLockSummaryLocked(dirtyPhase1);
            // 1. 更新用户行为!!!
            updateUserActivitySummaryLocked(now, dirtyPhase1);
            updateAttentiveStateLocked(now, dirtyPhase1);
            // 决定是否进入休眠/dream/doze状态
            // 如果进入某一种状态,会更新 wakefulness,因此这里要通过循环再来更新上面的东西
            if (!updateWakefulnessLocked(dirtyPhase1)) {
                break;
            }
        }
        // Phase 2: Lock profiles that became inactive/not kept awake.
        updateProfilesLocked(now);
        // Phase 3: Update display power state.
        // 2. 更新显示屏的电源状态!!
        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.traceEnd(Trace.TRACE_TAG_POWER);
    }
}

PowerManagerService 的所有功能都集中在这个函数中,但是与亮屏相关的主要有两步

  • **updateUserActivitySummaryLocked()**更新用户行为。这个用户行为会决定屏幕的最终亮度
  • updateDisplayPowerStateLocked() 更新显示屏的电源状态,它会对 DisplayManagerService 发起电源请求,从而决定屏幕屏的亮度。
1.3.1、更新用户行为updateUserActivitySummaryLocked:

这个函数不单单是用于更新用户行为,还更新了屏幕超时时间,并且以这个时间来定时更新电源状态,以实现自动灭屏的功能。

更新用户行为在第1步,前面分析更新 wakefulness 时,PMS 保存了唤醒的时间 mLastWakeTime。因此,对于从灭屏状态到亮屏状态这一过程来说,用户行为的值现在是 mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT,表示用户行为是亮屏。

private void updateUserActivitySummaryLocked(long now, int dirty) {
    // Update the status of the user activity timeout timer.
    if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
            | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
        mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);

        long nextTimeout = 0;
        if (mWakefulness == WAKEFULNESS_AWAKE
                || mWakefulness == WAKEFULNESS_DREAMING
                || mWakefulness == WAKEFULNESS_DOZING) {
            final int sleepTimeout = getSleepTimeoutLocked();//屏幕休眠超时时间,默认为-1
            final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);//屏幕超时时间
            final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);//DIM
            final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;

            mUserActivitySummary = 0;
		// 上一次用户行为的时间 >= 上一次唤醒屏幕的时间
            if (mLastUserActivityTime >= mLastWakeTime) {
                nextTimeout = mLastUserActivityTime
                        + screenOffTimeout - screenDimDuration;
                if (now < nextTimeout) {// 没有到 dim 时间
                    mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                } else {
                    nextTimeout = mLastUserActivityTime + screenOffTimeout;
                    if (now < nextTimeout) {// 处于 dim 时间段
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                    }
                }
            }
            // 超时了,但是由于释放了某一个锁,需要延长亮屏时间,或者亮屏时刻
            if (mUserActivitySummary == 0
                    && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
                if (now < nextTimeout) {
                    if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT
                            || mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_VR) {
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                    } else if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                    }
                }
            }
            // 一般超时情况
            if (mUserActivitySummary == 0) {
                if (sleepTimeout >= 0) {
                    final long anyUserActivity = Math.max(mLastUserActivityTime,
                            mLastUserActivityTimeNoChangeLights);
                    if (anyUserActivity >= mLastWakeTime) {
                        nextTimeout = anyUserActivity + sleepTimeout;
                        if (now < nextTimeout) {
                            mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                        }
                    }
                } else {
                    mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                    nextTimeout = -1;
                }
            }
            // PhoneWindowManager 处理 KeyEvent.KEYCODE_SOFT_SLEEP 时,userInactiveOverride 为 true
            // KeyEvent.KEYCODE_SOFT_SLEEP 这个软件的休眠按键 ?
            if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
                if ((mUserActivitySummary &
                        (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {
                    // Device is being kept awake by recent user activity
                    if (nextTimeout >= now && mOverriddenTimeout == -1) {
                        // Save when the next timeout would have occurred
                        mOverriddenTimeout = nextTimeout;
                    }
                }
                mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                nextTimeout = -1;
            }

            if (mUserActivitySummary != 0 && nextTimeout >= 0) {
                Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, nextTimeout);
            }
        } else {
            mUserActivitySummary = 0;
        }

        if (DEBUG) {
            Slog.d(TAG, "updateUserActivitySummaryLocked: mWakefulness="
                    + PowerManagerInternal.wakefulnessToString(mWakefulness)
                    + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
                    + ", nextTimeout=" + TimeUtils.formatUptime(nextTimeout));
        }
    }
}
1.3.2、更新显示屏电源状态updateDisplayPowerStateLocked:

更新屏幕电源状态的很清晰,如下

  1. 首先获取请求,并更新请求参数。请求参数中,主要关心的是策略参数,它决定了屏幕的状态,也就是到底是亮屏还是灭屏。
  2. 向 DisplayManagerService 发起请求。注意,如果当前的请求与上一次请求不同,那么处理过程是异步的,并且返回的 ready 状态为 false。否则,处理过程是同步的,返回的 ready 为 true。
    private boolean updateDisplayPowerStateLocked(int dirty) {
        final boolean oldDisplayReady = mDisplayReady;
        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)) != 0) {
	    //请求策略,亮屏返回
            mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();

            // Determine appropriate screen brightness and auto-brightness adjustments.
            boolean brightnessSetByUser = true;
            int screenBrightness = mScreenBrightnessSettingDefault;
            float screenAutoBrightnessAdjustment = 0.0f;
            boolean autoBrightness = (mScreenBrightnessModeSetting ==
                    Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
            if (!mBootCompleted) {
                // Keep the brightness steady during boot. This requires the
                // bootloader brightness and the default brightness to be identical.
                autoBrightness = false;
                brightnessSetByUser = false;
            } else if (mIsVrModeEnabled) {
                screenBrightness = mScreenBrightnessForVrSetting;
                autoBrightness = false;
            } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
                screenBrightness = mScreenBrightnessOverrideFromWindowManager;
                autoBrightness = false;
                brightnessSetByUser = false;
            } else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) {
                screenBrightness = mTemporaryScreenBrightnessSettingOverride;
            } else if (isValidBrightness(mScreenBrightnessSetting)) {
                screenBrightness = mScreenBrightnessSetting;
            }
            if (autoBrightness) {
                screenBrightness = mScreenBrightnessSettingDefault;
                if (isValidAutoBrightnessAdjustment(
                        mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) {
                    screenAutoBrightnessAdjustment =
                            mTemporaryScreenAutoBrightnessAdjustmentSettingOverride;
                } else if (isValidAutoBrightnessAdjustment(
                        mScreenAutoBrightnessAdjustmentSetting)) {
                    screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting;
                }
            }
            screenBrightness = Math.max(Math.min(screenBrightness,
                    mScreenBrightnessSettingMaximum), mScreenBrightnessSettingMinimum);
            screenAutoBrightnessAdjustment = Math.max(Math.min(
                    screenAutoBrightnessAdjustment, 1.0f), -1.0f);

            // Update display power request.
            mDisplayPowerRequest.screenBrightness = screenBrightness;
            mDisplayPowerRequest.screenAutoBrightnessAdjustment =
                    screenAutoBrightnessAdjustment;
            mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser;
            mDisplayPowerRequest.useAutoBrightness = autoBrightness;
            mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
            mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();

            updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);

            if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
                mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
                if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND
                        && (mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
                    mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
                }
                mDisplayPowerRequest.dozeScreenBrightness =
                        mDozeScreenBrightnessOverrideFromDreamManager;
            } else {
                mDisplayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
                mDisplayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
            }

            mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
                    mRequestWaitForNegativeProximity);
            mRequestWaitForNegativeProximity = false;

            if ((dirty & DIRTY_QUIESCENT) != 0) {
                sQuiescent = false;
            }
            if (DEBUG) {
                Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
                        + ", policy=" + mDisplayPowerRequest.policy
                        + ", mWakefulness=" + mWakefulness
                        + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
                        + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
                        + ", mBootCompleted=" + mBootCompleted
                        + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress
                        + ", mIsVrModeEnabled= " + mIsVrModeEnabled
                        + ", sQuiescent=" + sQuiescent);
            }
        }
        return mDisplayReady && !oldDisplayReady;
    }

接下来看一下如何更新请求的策略,

// PowerManagerService.java

 int getDesiredScreenPolicyLocked(int groupId) {
    final int wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
    final int wakeLockSummary = mDisplayGroupPowerStateMapper.getWakeLockSummaryLocked(groupId);
    if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
        return DisplayPowerRequest.POLICY_OFF;
    } else if (wakefulness == WAKEFULNESS_DOZING) {
        // ...
    }
    if (mIsVrModeEnabled) {
        return DisplayPowerRequest.POLICY_VR;
    }
    // 由于此时的 UserActivity 为 USER_ACTIVITY_SCREEN_BRIGHT,因此策略为 DisplayPowerRequest.POLICY_BRIGHT
    if ((wakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
            || !mBootCompleted
            || (mDisplayGroupPowerStateMapper.getUserActivitySummaryLocked(groupId)
            & USER_ACTIVITY_SCREEN_BRIGHT) != 0
            || mScreenBrightnessBoostInProgress) {
        return DisplayPowerRequest.POLICY_BRIGHT;
    }
    return DisplayPowerRequest.POLICY_DIM;
}

我们刚才分析的用户行为是 USER_ACTIVITY_SCREEN_BRIGHT,因此策略最终为 DisplayPowerRequest.POLICY_BRIGHT。当通过requestPowerState方法向 DMS起请求时,最终会导致屏幕点亮。

1.3.3、 requestPowerState()

之前所有的分析,最终会决策出电源请求策略DisplayPowerRequest.POLICY_BRIGHT,由requestPowerState方法向DMS发起请求,在DisplayPowerController中更新Display状态和亮度,并将请求结果返回给PMS。

    public boolean requestPowerState(DisplayPowerRequest request,
            boolean waitForNegativeProximity) {

        synchronized (mLock) {
            boolean changed = false;
         // 是否需要等待PSensor上报远离事件
            if (waitForNegativeProximity
                    && !mPendingWaitForNegativeProximityLocked) {
                mPendingWaitForNegativeProximityLocked = true;
                changed = true;
            }
        // 判断是否是新的请求
            if (mPendingRequestLocked == null) {
                mPendingRequestLocked = new DisplayPowerRequest(request);
                changed = true;
            } else if (!mPendingRequestLocked.equals(request)) {
                mPendingRequestLocked.copyFrom(request);
                changed = true;
            }

            if (changed) {
                mDisplayReadyLocked = false;
            }
        // 开始处理请求
            if (changed && !mPendingRequestChangedLocked) {
                mPendingRequestChangedLocked = true;
                sendUpdatePowerStateLocked();
            }
        // 返回给PMS,表示请求是否处理完成
            return mDisplayReadyLocked;
        }
    }

以上方法中,能否将此次请求作为一个新请求处理,由以下三个条件确定:

  • waitForNegativeProximity是否为true;
  • 如果开机第一次进入该函数,则mPendingRequestLocked的值为null,则实例化代表将要请求的DisplayPowerRequest对象;
  • 本次请求对象和上次请求对象是否相同。

mPendingRequestChangedLocked变量用于表示上次请求已经处理完毕。DisplayPowerRequest对象代表一个请求对象,封装了许多的请求参数:

public static final class DisplayPowerRequest {
    public int policy;                      // 请求的Display状态
    public boolean useProximitySensor;      // 是否持有PROXIMITY_SCREEN_OFF_WAKE_LOCK锁
    public int screenBrightnessOverride;    // 是否要覆盖亮度,尤其是来自WindowMananger的亮度
    public boolean useAutoBrightness;       // 是否使用自动亮度
    public boolean lowPowerMode;            // 是否进入了低电量模式
    public float screenLowPowerBrightnessFactor;   // 低电量模式下调整亮度因子
    public boolean boostScreenBrightness;   // 是否使用了亮度增强
    public int dozeScreenBrightness;        // 进入Doze状态后的屏幕亮度
    public int dozeScreenState;             // 进入Doze状态后的Display状态

之后的流程为:

requestPowerState()
-->sendUpdatePowerStateLocked();

sendUpdatePowerStateLocked方法中,通过Handler进入到PMS线程中开始处理请求:

private void sendUpdatePowerStateLocked() {
    if (!mPendingUpdatePowerStateLocked) {
        // 表示需要更新power state
        mPendingUpdatePowerStateLocked = true;
        Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
        mHandler.sendMessage(msg);
    }
}

之后将进入updatePowerState()方法中,这个方法是DisplayPowerController中的核心方法,对请求的解析和处理就是它来完成。

updatePowerState()方法非常庞大,处理亮灭屏、调节亮度、Display状态的更新,都会在这里进行处理。该方法的完整代码如下:

private void updatePowerState() {
    // Update the power state request.
    final boolean mustNotify;   // 是否要通知PMS完成请求处理
    final int previousPolicy;
    boolean mustInitialize = false;  //是否要进行初始化
    int brightnessAdjustmentFlags = 0;  // 自动亮度调整因子标记
    mBrightnessReasonTemp.set(null);   // 记录亮度变化原因
    // ####################################################Part 1####################################################
    synchronized (mLock) {
        mPendingUpdatePowerStateLocked = false;   // 代表"即将开始更新",这里已经开始了,所以重置为true
        if (mPendingRequestLocked == null) {
            return; // wait until first actual power request
        }
 
        if (mPowerRequest == null) {   // 只有系统开机后第一次会进入该if代码块
            mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
            mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
            mPendingWaitForNegativeProximityLocked = false;
            mPendingRequestChangedLocked = false;
            mustInitialize = true;
            previousPolicy = DisplayPowerRequest.POLICY_BRIGHT;
        } else if (mPendingRequestChangedLocked) {   // 更新全局DisplayPowerRequest
            previousPolicy = mPowerRequest.policy;  
            mPowerRequest.copyFrom(mPendingRequestLocked);   // 更新mPowerRequest
            mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
            mPendingWaitForNegativeProximityLocked = false;
            mPendingRequestChangedLocked = false;   // 重置
            mDisplayReadyLocked = false;
        } else {
            previousPolicy = mPowerRequest.policy;
        }
 
        mustNotify = !mDisplayReadyLocked;
    }
 
    if (mustInitialize) {
        initialize();  //初始化亮灭屏动画、DisplayPowerState对象...
    }
    // ####################################################Part 2####################################################
    int state;
    float brightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
    boolean performScreenOffTransition = false;    // 是否执行灭屏动画
    switch (mPowerRequest.policy) {                // 将根据policy确定Display要设置的状态
        case DisplayPowerRequest.POLICY_OFF:       // policy为off,会将Display状态设置为OFF
            state = Display.STATE_OFF;
            performScreenOffTransition = true;
            break;
        case DisplayPowerRequest.POLICY_DOZE:    // policy为doze,则会根据mPowerRequest.dozeScreenState确定Display的状态,默认为DOZE状态
            if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
                state = mPowerRequest.dozeScreenState;
            } else {
                state = Display.STATE_DOZE;
            }
            if (!mAllowAutoBrightnessWhileDozingConfig) {    // 是否支持在Doze状态时使用自动亮度,默认false
                brightnessState = mPowerRequest.dozeScreenBrightness;    // 将亮度设置为PMS中指定的Doze状态亮度
                mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE);   // 记录亮度变化原因——doze状态的亮度
            }
            break;
        case DisplayPowerRequest.POLICY_VR:  // policy为VR时,设置Display状态为VR
            state = Display.STATE_VR;
            break;
        case DisplayPowerRequest.POLICY_DIM:  // policy为DIM或者BRIGHT时,都表示亮屏,所以将Display状态设置为ON
        case DisplayPowerRequest.POLICY_BRIGHT:
        default:
            state = Display.STATE_ON;
            break;
    }
    assert(state != Display.STATE_UNKNOWN);
    // #################################################### Part 3 ####################################################
    if (mProximitySensor != null) {
        // 如果持有Proximity WakeLock锁,且请求Display状态不为OFF
        if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {   
            // 注册PSensor监听
            setProximitySensorEnabled(true);   
            // 上报了靠近事件
            if (!mScreenOffBecauseOfProximity
                    && mProximity == PROXIMITY_POSITIVE) {  
                // 代表“是否由于PSensor收到靠近时间而灭屏”
                mScreenOffBecauseOfProximity = true;  
                // 回调通知PMS PSensor收到靠近事件
                sendOnProximityPositiveWithWakelock();  
            }
        // 如果释放Proximity WakeLock锁时带有1标记,发现由于PSensor灭屏且还未收到远离事件,则继续等待,并保持PSensor监听
        } else if (mWaitingForNegativeProximity  
                && mScreenOffBecauseOfProximity
                && mProximity == PROXIMITY_POSITIVE
                && state != Display.STATE_OFF) {
            setProximitySensorEnabled(true);
        } else {  
            // 在灭屏时或者释放Proximity WakeLock锁后,解除PSensor监听
            setProximitySensorEnabled(false);
            mWaitingForNegativeProximity = false;
        }
        // 收到远离事件后,重置mScreenOffBecauseOfProximity
        if (mScreenOffBecauseOfProximity
                && mProximity != PROXIMITY_POSITIVE) {   
            mScreenOffBecauseOfProximity = false;
            // 通知PMS PSensor收到远离事件
            sendOnProximityNegativeWithWakelock();  
        }
    } else { 
        // 说明PSensor不可用,那下慢这个值也没用,直接置为false
        mWaitingForNegativeProximity = false;
    }
    // 如果PSensor收到上报靠近时间了,需要灭屏,于是将Display状态设置为OFF
    if (mScreenOffBecauseOfProximity) {   
        state = Display.STATE_OFF;
    }
    // #################################################### Part 4 ####################################################
    final int oldState = mPowerState.getScreenState();
    // 设置Display状态
    animateScreenStateChange(state, performScreenOffTransition);   
    state = mPowerState.getScreenState();
    // #################################################### Part 5 ####################################################
    // 如果Display状态设置为OFF,说明要灭屏,则将亮度设置为-1.0f
    if (state == Display.STATE_OFF) {   
        brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT;
        // 记录亮度变化原因
        mBrightnessReasonTemp.setReason(BrightnessReason.REASON_SCREEN_OFF);   
    }
    // 如果Display状态设置为VR,不常用
    if (state == Display.STATE_VR) {   
        brightnessState = mScreenBrightnessForVr;
        mBrightnessReasonTemp.setReason(BrightnessReason.REASON_VR);
    }
    // 使用PMS中的亮度覆盖,来自WindowManager如视频界面的亮度
    if ((Float.isNaN(brightnessState))
                && isValidBrightnessValue(mPowerRequest.screenBrightnessOverride)) {  
        brightnessState = mPowerRequest.screenBrightnessOverride;
        // 记录亮度变化原因
        mBrightnessReasonTemp.setReason(BrightnessReason.REASON_OVERRIDE);  
        // 表示使用了覆盖亮度
        mAppliedScreenBrightnessOverride = true;   
    } else {
        mAppliedScreenBrightnessOverride = false;
    }
    // 判断是否在Doze状态下使用自动亮度,一般为false
    final boolean autoBrightnessEnabledInDoze =
            mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state);
    // 判断自动亮度是否可用: 开始了自动亮度&亮屏状态&未使用前几类亮度&配置了自动亮度曲线映射
    final boolean autoBrightnessEnabled = mPowerRequest.useAutoBrightness
                && (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
                && Float.isNaN(brightnessState)
                && mAutomaticBrightnessController != null;
    // 用来更新用户状态栏、设置中手动设置的亮度值的状态,如果用户设置亮度发生变化,返回true
    final boolean userSetBrightnessChanged = updateUserSetScreenBrightness();
    // 该亮度表示用户拖动亮度条调节且未放手时的亮度,所以是一个"临时"亮度,如果存在这个值,则必须使用这个值
    if (isValidBrightnessValue(mTemporaryScreenBrightness)) {
        brightnessState = mTemporaryScreenBrightness;
        // 表示使用了临时用户亮度
        mAppliedTemporaryBrightness = true;   
        mBrightnessReasonTemp.setReason(BrightnessReason.REASON_TEMPORARY);
    } else {
        mAppliedTemporaryBrightness = false;
    }
    // 更新自动亮度曲线调整值,如果调整值发生变化,返回true
    final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
    // 由于发生变化已经更新到全局变量上,所以不需要"临时"自动变量调整值,重置
    if (autoBrightnessAdjustmentChanged) {  
        mTemporaryAutoBrightnessAdjustment = Float.NaN;
    }
 
    final float autoBrightnessAdjustment;
    // 如果临时自动变量调整值存在,则使用它作为全局自动变量调整值,随后它的值将更新到全局自动变量调整值上,并将它重置,如前五行看到的
    if (!Float.isNaN(mTemporaryAutoBrightnessAdjustment)) { 
        autoBrightnessAdjustment = mTemporaryAutoBrightnessAdjustment;
        brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO_TEMP;  
        // 表示使用了临时自动亮度调整值
        mAppliedTemporaryAutoBrightnessAdjustment = true; 
    // 否则使用全局自动亮度调整值
    } else {   
        autoBrightnessAdjustment = mAutoBrightnessAdjustment;
        brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO;  
        mAppliedTemporaryAutoBrightnessAdjustment = false;
    }
    // 如果使用了亮度增强,Display状态不处于灭屏,会将亮度设置到最大
    if (mPowerRequest.boostScreenBrightness
            && brightness != PowerManager.BRIGHTNESS_OFF) {   
        brightnessState = PowerManager.BRIGHTNESS_ON;
        mBrightnessReasonTemp.setReason(BrightnessReason.REASON_BOOST);
        // 表示使用了亮度增强
        mAppliedBrightnessBoost = true;  
    } else {
        mAppliedBrightnessBoost = false;
    }
    // 表示是否用户发起了亮度的改变:没有使用以上几类亮度&(自动亮度调整值发生变化||用户设置了亮度)
    // 这个值若为true,说明亮度被用户拖动发生改变了
    boolean userInitiatedChange = (Float.isNaN(brightnessState))
            && (autoBrightnessAdjustmentChanged || userSetBrightnessChanged);
    // 是否用户手动调节过自动亮度
    boolean hadUserBrightnessPoint = false;   
    if (mAutomaticBrightnessController != null) {
        hadUserBrightnessPoint = mAutomaticBrightnessController.hasUserDataPoints();
        // 配置自动亮度相关参数
    mAutomaticBrightnessController.configure(autoBrightnessEnabled,
            mBrightnessConfiguration,
            mLastUserSetScreenBrightness,
            userSetBrightnessChanged, autoBrightnessAdjustment,
            autoBrightnessAdjustmentChanged, mPowerRequest.policy);    }
 
    // #################################################### Part 6 ####################################################
    boolean slowChange = false;
    if (brightness < 0) {   // 如果前面几类亮度未使用,则使用自动亮度
        float newAutoBrightnessAdjustment = autoBrightnessAdjustment;
        if (autoBrightnessEnabled) {
            // 获取自动亮度
            brightnessState = mAutomaticBrightnessController.getAutomaticScreenBrightness(); 
            // 获取新的自动亮度调整值
            newAutoBrightnessAdjustment =
               mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment(); 
        }
        // 说明使用了自动亮度
        if (isValidBrightnessValue(brightnessState)) {  
            // 对得到的自动亮度限制范围
            brightnessState = clampScreenBrightness(brightness);  
            // 这俩条件说明是由自动亮度的调节
            if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {  
                 // 用来控制亮度调节速率
                slowChange = true;
            }
            // 将亮度值更新到settings中
            putScreenBrightnessSetting(brightnessState);
            // 表示使用了自动亮度
            mAppliedAutoBrightness = true;   
            mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC);
        } else {
            mAppliedAutoBrightness = false;
        }
        // 如果自动亮度调整值发生变化,更新自动亮度调整值到settings中
        if (autoBrightnessAdjustment != newAutoBrightnessAdjustment) {   
            putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment);
        } else {
            // 说明是纯自动亮度,并没有调整
            brightnessAdjustmentFlags = 0;  
        }
    } else {
        mAppliedAutoBrightness = false;
        brightnessAdjustmentFlags = 0;
    }
    // #################################################### Part 7 ####################################################
    // 如果进入Doze状态后,PMS中未指定Doze状态亮度,使用默认的doze亮度
    if ((Float.isNaN(brightnessState))
            && Display.isDozeState(state)) {   
        brightnessState = mScreenBrightnessDozeConfig;
        mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
    }
 
    // #################################################### Part 8 ####################################################
    // 如果这里还没有亮度,那么将使用用户设置的亮度
    if (Float.isNaN(brightnessState)) {   
        brightnessState = clampScreenBrightness(mCurrentScreenBrightnessSetting);
        mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL);
    }
    // #################################################### Part 9 ####################################################
    // 设置进入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;   // 表示需要快速设置亮度
        }
        mAppliedDimming = true;  // 表示使用了Dim亮度
    } else if (mAppliedDimming) {
        slowChange = false;
        mAppliedDimming = false;
    }
    // #################################################### Part 10 ####################################################
    // 低电量模式下,需要调低亮度以节约功耗
    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;
        }
        // 表示使用了低电量模式的亮度
        mAppliedLowPower = true;  
    } else if (mAppliedLowPower) {
        slowChange = false;
        mAppliedLowPower = false;
    }
    // #################################################### Part 11 ####################################################
    if (!mPendingScreenOff) {
        if (mSkipScreenOnBrightnessRamp) {   // mSkipScreenOnBrightnessRamp表示亮屏时不使用亮度动画
            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;
            }
        }
        // 是否处于或原本处于VR状态
        final boolean wasOrWillBeInVr =
                (state == Display.STATE_VR || oldState == Display.STATE_VR);
        // 表示是否在亮屏时,使用亮度动画,使用亮度动画,在亮屏时可能会出现缓慢的设置亮度。由mSkipScreenOnBrightnessRamp决定
        final boolean initialRampSkip =
                state == Display.STATE_ON && mSkipRampState != RAMP_STATE_SKIP_NONE;
        // display硬件是否支持全范围亮度值,如果不支持,设置亮度时就不使用亮度动画设置
        final boolean hasBrightnessBuckets =
                Display.isDozeState(state) && mBrightnessBucketsInDozeConfig;    // 表示doze状态时,display硬件是否支持全范围亮度值
        // 是否colorfade已经完成对显示内容的覆盖,如果已经覆盖,那么就没必要使用亮度动画了,因为已经看不到显示内容了
        final boolean isDisplayContentVisible =
                mColorFadeEnabled && mPowerState.getColorFadeLevel() == 1.0f;
        // 是否使用到了临时亮度
        final boolean brightnessIsTemporary =
                mAppliedTemporaryBrightness || mAppliedTemporaryAutoBrightnessAdjustment;
  
        float animateValue = brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT
                    ? PowerManager.BRIGHTNESS_MIN : brightnessState;
            if (isValidBrightnessValue(animateValue)) {
                // 以下条件,直接设置亮度,没有亮度动画(rate=0)
                if (initialRampSkip || hasBrightnessBuckets
                        || wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
                    animateScreenBrightness(animateValue, SCREEN_ANIMATION_RATE_MINIMUM);
                } else {
                    animateScreenBrightness(animateValue,
                            slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
                }
        // #################################################### Part 12 ####################################################
        // 每次亮度发生变化后,对这次变化进行记录, 依据就是brightnessIsTemporary和userInitiatedChange
        // brightnessIsTemporary表示是否使用临时亮度,默认为false,并且在拖动过程中,这个值为ture,拖动亮度条结束后,将重回false
        // userInitiatedChange表示用户是否调整过亮度调整过程中为false,调整完成后将变为ture,并在下一次执行到该方法时又重回false
        // 因此,只要亮度发生变化,就会进入下面进行统计,userInitiatedChange则表示是否是用户发起的变化,perfect!
        // 不过,notifyBrightnessChanged()中则对统计条件进行了限制:只统计使用自动亮度情况下的变化,关闭自动亮度,使用windowOverlay亮度都是不会统计的
        if (!brightnessIsTemporary) { 
            if (userInitiatedChange && (mAutomaticBrightnessController == null
                    || !mAutomaticBrightnessController.hasValidAmbientLux())) {
                userInitiatedChange = false;
            }
            notifyBrightnessChanged(brightness, userInitiatedChange, hadUserBrightnessPoint);
        }
    }
    // 每次亮度调整后,log的输出,日常处理问题相当有用
    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) {    // 自调节色温
        if (state == Display.STATE_ON && mDisplayWhiteBalanceSettings.isEnabled()) {
            mDisplayWhiteBalanceController.setEnabled(true);
            mDisplayWhiteBalanceController.updateDisplayColorTemperature();
        } else {
            mDisplayWhiteBalanceController.setEnabled(false);
        }
    }
    // #################################################### Part 14 ####################################################
    // mPendingScreenOnUnblocker用于亮屏过程,非空表示屏幕目前被阻塞,等待WindowManager模块完成亮屏操作后回调将它置为null
    // Colorfade是一个暗层动画,亮灭屏时会淡入淡出
    final boolean ready = mPendingScreenOnUnblocker == null &&
            (!mColorFadeEnabled ||   
                    (!mColorFadeOnAnimator.isStarted() && !mColorFadeOffAnimator.isStarted()))   // 是否正在有colorfade动画进行
            && mPowerState.waitUntilClean(mCleanListener);   // 判断屏幕状态和ColorFade是否设置完成,两个都完成时返回true
    // 所以ready表示display状态是否设置完成
    // 表示display状态设置完毕,亮度也设置完毕
    final boolean finished = ready
            && !mScreenBrightnessRampAnimator.isAnimating();   // 亮度动画是否在进行
    // mReportedScreenStateToPolicy表示向PhoneWindowManager报告亮灭屏阶段的值
    if (ready && state != Display.STATE_OFF
            && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_ON) {
        setReportedScreenState(REPORTED_TO_POLICY_SCREEN_ON);   // 将mReportedScreenStateToPolicy设置为REPORTED_TO_POLICY_SCREEN_ON,表示亮屏完成
        mWindowManagerPolicy.screenTurnedOn();    // 报告PhoneWindowManager
    }
    // 表示更新display的设置或者亮度的设置还没有完成,需要持锁保证它们的完成
    if (!finished && !mUnfinishedBusiness) {
        mCallbacks.acquireSuspendBlocker();
        mUnfinishedBusiness = true;
    }
    // 回调通知PMS,display状态完成更新,PMS将会再次发起请求
    if (ready && mustNotify) {
        synchronized (mLock) {
            if (!mPendingRequestChangedLocked) {
                mDisplayReadyLocked = true;    // 表示更新完成了
            }
        }
        sendOnStateChangedWithWakelock();  // 回调PMS
    }
    // 表示更新display和亮度的设置全部完成,释放锁
    if (finished && mUnfinishedBusiness) {
        mUnfinishedBusiness = false;
        mCallbacks.releaseSuspendBlocker();
    }
    // 用来记录上次设置Display状态是否为ON
    mDozing = state != Display.STATE_ON;
}

根据具体功能将它按功能划分成了几部分来看:

  • Part 1:mPowerRequest的更新,mPowerRequest代表当前PMS中的请求封装对象;
  • Part 2:根据mPowerRequest对象中的policy参数确定要设置的Display状态;
  • Part 3:针对Proximity Sensor的处理;
  • Part 4:根据Part2、Part3确定的state开始设置Display状态;
  • Part 5:确定屏幕亮度;
  • Part 6:应用自动亮度;
  • Part 7:Doze状态时,使用Doze默认亮度;
  • Part 8:应用用户手动调节亮度;
  • Part 9:设置Dim时亮度;
  • Part 10:设置低电量状态时的亮度;
  • Part 11:确定是否使用亮度动画和亮度的设置;
  • Part 12:亮度变化后的log输出和记录;
  • Part 13:更新色温调节状态;
  • Part 14:Display状态和亮度设置完成后的处理。
1.3.4、scheduleScreenUpdate()执行更新
private void scheduleScreenUpdate() {
    if (!mScreenUpdatePending) {    // 表示将开始更新Display整体状态
        mScreenUpdatePending = true;
        postScreenUpdateThreadSafe();
    }
}
private void postScreenUpdateThreadSafe() {
    mHandler.removeCallbacks(mScreenUpdateRunnable);
    mHandler.post(mScreenUpdateRunnable);
}

以上两个方法中,先将mScreenUpdatePending设置为true,表示将开始更新Display整体状态,然后通过Handler将在mScreenUpdateRunnable这个runnable中进行处理:


    private final Runnable mScreenUpdateRunnable = new Runnable() {
        @Override
        public void run() {
            mScreenUpdatePending = false;
            // 确认最终的亮度,在Display状态为OFF时,或者ColorFade level为0时,将设置为0,其他情况下设置为DPC中传入的亮度值
            float brightnessState = mScreenState != Display.STATE_OFF
                    && mColorFadeLevel > 0f ? mScreenBrightness : PowerManager.BRIGHTNESS_OFF_FLOAT;
            // PhotonicModulator是一个独立的线程,专门用来更新Display状态和亮度
            if (mPhotonicModulator.setState(mScreenState, brightnessState)) {
                // 更新完成
                mScreenReady = true;
                invokeCleanListenerIfNeeded();
            } else {
            }
        }
    };
1.3.5、PhotonicModulator#setState()子线程进行更新

PhotonicModulator是一个继承于Thread的类,专门用于更新Display状态和亮度,因此更新屏幕状态和背光是在独立的线程中异步进行的,setState()方法如下:

public boolean setState(int state, int backlight) {
    synchronized (mLock) {
        // Display状态是否发生变化,mPendingState表示即将开始设置的状态,设置完成后也不会清除
        boolean stateChanged = state != mPendingState;  
        // 亮度是否发生变化,mPendingBacklight表示即将开始设置的亮度,设置完成后也不会清除
        boolean backlightChanged = backlight != mPendingBacklight;  
        // Display状态或亮度任意一个发生变化,就开始更新
        if (stateChanged || backlightChanged) {  
            mPendingState = state;           // 更新mPendingState值
            mPendingBacklight = backlight;   // 更新mPendingBacklight值
            // 表示是否处于change过程中
            boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
            mStateChangeInProgress = stateChanged || mStateChangeInProgress;   
            mBacklightChangeInProgress = backlightChanged || mBacklightChangeInProgress;
            // 当不处于change过程中时,唤起PhotonicModulator线程
            if (!changeInProgress) { 
                mLock.notifyAll();
            }
        }
        return !mStateChangeInProgress;  // 只要State更新完成,就返回true
    }
}

当屏幕状态和亮度任意一个发生变化,将通过notifyAll()唤醒PhotonicModulator线程,然后执行该线程的run()方法,这是一个/看下它的run()方法:

public void run() {
    for (;;) {
        final int state;
        final boolean stateChanged;
        final int backlight;
        final boolean backlightChanged;
        synchronized (mLock) {
            state = mPendingState;
            // mActualState表示实际Display状态
            stateChanged = (state != mActualState);   
            backlight = mPendingBacklight;
            // mActualBacklight表示实际亮度
            backlightChanged = (backlight != mActualBacklight);   
            if (!stateChanged) {
                // 再一次发起更新流程
                postScreenUpdateThreadSafe();   
                mStateChangeInProgress = false;
            }
            if (!backlightChanged) {
                mBacklightChangeInProgress = false;
            }
            if (!stateChanged && !backlightChanged) {
                try {
                    // state和亮度都设置完成后,该线程进入wait状态
                    mLock.wait();
                } catch (InterruptedException ex) { }
                continue;
            }
            mActualState = state;
            mActualBacklight = backlight;
        }
        // 调用DisplayBlanker中去请求Display
        mBlanker.requestDisplayState(state, backlight);  
    }
}

在Display状态和亮度都更新完成之后,通过Object.wait()方法,让该线程进入WAITTING状态了。通过这种方式,不设置过来的Display状态和亮度。

最终,调用mBlanker.requestDisplayState()进行下一步设置,这里又经过DMS,最后会对具体的DisplayDevice对象进行状态和亮度的设置中。

1.3.6、LocalDisplayDevice#requstDisplayStateLocked()

requestDisplayStateLocked()为具体的物理屏设置新的Display状态和亮度值:

        @Override
        public Runnable requestDisplayStateLocked(final int state, final float brightnessState) {
            final boolean stateChanged = (mState != state);
            final boolean brightnessChanged = (!BrightnessSynchronizer.floatEquals(
                    mBrightnessState, brightnessState))
                    && mBacklight != null;
            if (stateChanged || brightnessChanged) {
                ......
                return new Runnable() {
                    @Override
                    public void run() {
                        ......
                        // 设置亮度
                        if (brightnessChanged || vrModeChange) {
                            setDisplayBrightness(brightnessState);
                        }
                        // 设置状态
                        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;
        }

最终,将亮度设置给了LightsService,将状态则是给了SurfaceControl,并由这两模块将分别将亮度和状态给到SurfaceFlinger中,最终完成整个设置。
回到updatePowerState()中,在Part14部分中,当Display状态和亮度都设置完成后,会将mDisplayReadyLocked值设置为true,表示Display状态更新完成,并在 sendOnStateChangedWithWakelock()方法中回调PMS,PMS再次发起请求时,由于mDisplayReadyLocked已经变为true,因此将返回true,PMS将认为DMS对请求处理完成。

1.4 亮屏小结

主要流程:

  • 调用wakeUp()进入唤醒流程
  • 通过wakeUpNoUpdateLocked()更新时间和wakefulness。
  • 通过updateDisplayPowerStateLocked()更新电源状态,并通过requestPowerState向DMS发送更改屏幕状态的请求。

详细流程图如下
在这里插入图片描述

亮屏还存在很多细节和功能未写出,以后有时间再继续写

顺便贴出灭屏流程:

在这里插入图片描述

2、灭屏和doze

灭屏和doze都是走的灭屏流程,触发灭屏的方式也有很多,主要分为自动息屏和手动息屏,灭屏流程大体上和亮屏区别不大,但是灭屏又多了一些特有的东西,比如dream,因此,本节主要以doze状态讲述灭屏流程,doze,就是屏幕处于低功耗,而系统已经进入了休眠,常见于屏保和AOD等功能。

当按下Power键时,会调用PMS#goToSleep(),

goToSleep(long eventTime, int reason, int flags)
-->goToSleepInternal(eventTime, reason, flags, uid);
   -->goToSleepNoUpdateLocked(eventTime, reason, flags, uid)
   -->updatePowerStateLocked();

流程与亮屏一致,先更新wakefulness,再更新电源状态。

2.1、privatebooleangoToSleepNoUpdateLocked()

更新wakefulness的过程中和亮屏有些不太一致。默认地,wakefulness 更新为 WAKEFULNESS_DOZING,然而,如果参数 flags 带有 PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE,wakefulness 更新为 WAKEFULNESS_ASLEEP。

private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
	......
    setWakefulnessLocked(WAKEFULNESS_DOZING, reason);//更新wakefulness为WAKEFULNESS_DOZING
    // Skip dozing if requested.如果 flags 带有 PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE,更新 wakefulness 为 WAKEFULNESS_ASLEEP
    if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
          reallyGoToSleepNoUpdateLocked(eventTime, uid);
    }
	......
}

相当于根据flag选择wakefulness的值为WAKEFULNESS_ASLEEP还是WAKEFULNESS_DOZING。当进入ASLEEP后,流程就与上一节的亮屏一致了。

2.2、打盹状态updatePowerStateLocked()

这里调用的方法,和1.3中调用的时同一个函数,同样也是更新电源状态,不过进入打盹状态会存在差异。

// PowerManagerService.java

private void updatePowerStateLocked() {
    if (!mSystemReady || mDirty == 0) {
        return;
    }
    // 注意这里的技术,线程可以判断是否获取了某个锁
    if (!Thread.holdsLock(mLock)) {
        Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
    }
    Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
    try {
        // Phase 0: Basic state updates.
        // 省电模式功能
        updateIsPoweredLocked(mDirty);
        // 设置中"充电常亮功能"
        updateStayOnLocked(mDirty);
        // 亮度增加功能
        updateScreenBrightnessBoostLocked(mDirty);
        // Phase 1: Update wakefulness.
        // Loop because the wake lock and user activity computations are influenced
        // by changes in wakefulness.
        final long now = mClock.uptimeMillis();
        int dirtyPhase2 = 0;
        for (;;) {
            int dirtyPhase1 = mDirty;
            dirtyPhase2 |= dirtyPhase1;
            mDirty = 0;
            // 把所有的唤醒锁归纳到 mWakeLockSummary
            updateWakeLockSummaryLocked(dirtyPhase1);
            // 1. 更新用户行为!!!
            updateUserActivitySummaryLocked(now, dirtyPhase1);
            updateAttentiveStateLocked(now, dirtyPhase1);
            // 决定是否进入休眠/dream/doze状态
            // 如果进入某一种状态,会更新 wakefulness,因此这里要通过循环再来更新上面的东西
            if (!updateWakefulnessLocked(dirtyPhase1)) {
                break;
            }
        }
        // Phase 2: Lock profiles that became inactive/not kept awake.
        updateProfilesLocked(now);
        // Phase 3: Update display power state.
        // 2. 更新显示屏的电源状态!!
        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.traceEnd(Trace.TRACE_TAG_POWER);
    }
}

和上一节类似,其中和灭屏相关的步骤就只有三个:

  • updateUserActivitySummaryLocked() 更新用户行为。屏幕请求策略的影响之一的因素就是用户行为。
  • **updateDisplayPowerStateLocked()**更新显示屏的电源状态,它会对 DMS发起电源请求,从而决定屏幕屏的状态,例如亮、灭、暗,等等。
  • updateDreamLocked() 更新梦境状态,其实就是通过 dream manager 启动 doze 组件,然后更新 PMS的梦境状态。
2.2.1、更新用户行为

调用方法为updateUserActivitySummaryLocked()与1.3.1一致,通过分析该函数发现,没有doze相关的用户行为,再此处获取的用户行为

亮为USER_ACTIVITY_SCREEN_BRIGHT或者由暗到灭为USER_ACTIVITY_SCREEN_DIM。查看定义发现所有的用户行为仅有三种

    private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
    private static final int USER_ACTIVITY_SCREEN_DIM = 1 << 1;
    private static final int USER_ACTIVITY_SCREEN_DREAM = 1 << 2;

用户行为只有三种,屏幕变亮,变暗,或者进入屏保,根本没有打盹的用户行为。那么为何是这样呢?
虽然此时 wakefulness 为 WAKEFULNESS_DOZING,只是表示正在进入打盹状态,实际上还没有正式处于打盹状态。系统真正进入打盹状态的标志是,dream manager 成功启动 doze 组件,并且获取到唤醒锁 PowerManager.DOZE_WAKE_LOCK 。因此,不好定义一个打盹的用户行为。

2.2.2、更新显示屏电源

此处调用的方法也是和1.3.2中的方法一致updateDisplayPowerStateLocked(),不过,虽然此时的wakefulness为WAKEFULNESS_DOZING,但是此时决定请求策略的仍然是用户行为。

而根据刚刚的分析,此时用户行为是 USER_ACTIVITY_SCREEN_BRIGHT 或 USER_ACTIVITY_SCREEN_DIM,因此策略为 DisplayPowerRequest.POLICY_BRIGHT 或 DisplayPowerRequest.POLICY_DIM。也就是说屏幕状态继续保持不变,之所以会这样是因为,现在设备还未处于打盹状态,得等到doze dream启动成功后,dream manager 会获取唤醒锁PowerManager.DOZE_WAKE_LOCK,此时 PowerManagerService 再次更新电源状态时,策略就会更新为DisplayPowerRequest.POLICY_DOZE,它会让屏幕进入一个doze状态,并开启 AOD 功能。

当然,如果你不想在灭屏时暂时保持屏幕状态不变,可以把 mDozeAfterScreenOff 设置为 true,这会导致请求策略更新为 DisplayPowerRequest.POLICY_OFF ,也就是立即让屏幕进入休眠。

2.2.3、启动doze

设备真正进入打盹,是在启动 doze dream 之后。doze dream 的启动过程是在更新梦境状态的过程中

// PowerManagerService.java

private void updateDreamLocked(int dirty, boolean displayBecameReady) {
    if ((dirty & (DIRTY_WAKEFULNESS
            | DIRTY_USER_ACTIVITY
            | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED
            | DIRTY_ATTENTIVE
            | DIRTY_WAKE_LOCKS
            | DIRTY_BOOT_COMPLETED
            | DIRTY_SETTINGS
            | DIRTY_IS_POWERED
            | DIRTY_STAY_ON
            | DIRTY_PROXIMITY_POSITIVE
            | DIRTY_BATTERY_STATE)) != 0 || displayBecameReady) {
        if (mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
            // 最终调用 handleSandman()
            scheduleSandmanLocked();
        }
    }
}


private void handleSandman(int groupId) { // runs on handler thread
    // Handle preconditions.
    final boolean startDreaming;
    final int wakefulness;
    synchronized (mLock) {
        mSandmanScheduled = false;
        final int[] ids = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked();
        if (!ArrayUtils.contains(ids, groupId)) {
            // Group has been removed.
            return;
        }
        wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
        if ((wakefulness == WAKEFULNESS_DREAMING || wakefulness == WAKEFULNESS_DOZING) &&
                mDisplayGroupPowerStateMapper.isSandmanSummoned(groupId)
                && mDisplayGroupPowerStateMapper.isReady(groupId)) {
            // 1. 决定是否能启动梦境
            // canDreamLocked() 表示是否启动梦境中的屏保
            // canDozeLocked() 表示是否启动梦境中的doze组件,判断条件就是 wakefulness 为 WAKEFULNESS_DOZING
            startDreaming = canDreamLocked(groupId) || canDozeLocked();
            // 重置"召唤睡梦精灵"状态
            mDisplayGroupPowerStateMapper.setSandmanSummoned(groupId, false);
        } else {
            startDreaming = false;
        }
    }

    final boolean isDreaming;
    if (mDreamManager != null) {
        // Restart the dream whenever the sandman is summoned.
        if (startDreaming) {
            mDreamManager.stopDream(false /*immediate*/);
            // 2. 启动梦境 doze 组件
            mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);
        }
        // 判断是否正在启动中
        isDreaming = mDreamManager.isDreaming();
    } else {
        isDreaming = false;
    }

    mDozeStartInProgress = false;
    synchronized (mLock) {
        final int[] ids = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked();
        if (!ArrayUtils.contains(ids, groupId)) {
            return;
        }

        if (startDreaming && isDreaming) {
            // ...
        }

        if (mDisplayGroupPowerStateMapper.isSandmanSummoned(groupId)
                || mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId) != wakefulness) {
            return; // wait for next cycle
        }

        // Determine whether the dream should continue.
        long now = mClock.uptimeMillis();
        if (wakefulness == WAKEFULNESS_DREAMING) {
            // ...
        } else if (wakefulness == WAKEFULNESS_DOZING) {
            // 3. 正在启动梦境的doze组件,那继续
            if (isDreaming) {
                return; // continue dozing
            }

            // 4. 没有启动成功,或者doze组件自己结束梦境,进入更新 wakefulness 为 WAKEFULNESS_ASLEEP 流程
            // Doze has ended or will be stopped.  Update the power state.
            reallySleepDisplayGroupNoUpdateLocked(groupId, now, Process.SYSTEM_UID);
            updatePowerStateLocked();
        }
    }
    // ...
}

更新梦境状态过程如下

  1. 判断是否能进入梦境。梦境其实有两种功能,一种是屏保,另一种是 doze 组件。由于此时 wakefulness 为 WAKEFULNESS_DOZING,因此可以满足启动 doze dream 的条件。
  2. 通过 dream manager 启动 dream。此时,启动的就是 doze dream,而不是屏保。
  3. 如果正在启动,那就继续。继续什么呢?查看下节。
  4. 如果启动失败,进入休眠的流程。

休眠的流程最简单了,首先更新 wakefulenss 为 WAKEFULNESS_ASLEEP,然后更新请求策略为 DisplayPowerRequest.POLICY_OFF , 剩下的然后就和亮屏流程一致,这使屏幕直接灭屏。

2.3、启动doze dream

现在我们离设备正式进入打盹状态,只有一步之遥,而这一步就是调用 **DMS#startDreamInternal()**启动 doze dream

// DreamManagerService.java

private void startDreamInternal(boolean doze) {
    final int userId = ActivityManager.getCurrentUser();
    // 获取 doze dream 或 screensaver
    final ComponentName dream = chooseDreamForUser(doze, userId);
    if (dream != null) {
        synchronized (mLock) {
            // 启动 dream,此时启动的 doze dream,
            startDreamLocked(dream, false /*isTest*/, doze, userId);
        }
    }
}

private ComponentName chooseDreamForUser(boolean doze, int userId) {
    if (doze) {
        ComponentName dozeComponent = getDozeComponent(userId);
        return validateDream(dozeComponent) ? dozeComponent : null;
    }
    // ...
}

private ComponentName getDozeComponent(int userId) {
    if (mForceAmbientDisplayEnabled || mDozeConfig.enabled(userId)) {
        // 从配置文件 config.xml 中获取 config_dozeComponent 
        return ComponentName.unflattenFromString(mDozeConfig.ambientDisplayComponent());
    } else {
        return null;
    }

}

系统没有配置 doze dream 组件,但是没关系,经过研究源码中的一些已经实现的 doze 组件,我们可以发现, doze 组件都是继承自一个名为 DreamService 的 Service,这个 Service 就是四大组件的 Service。
现在继续看看启动 doze 组件的过程

// DreamManagerService.java

private void startDreamLocked(final ComponentName name,
        final boolean isTest, final boolean canDoze, final int userId) {
    // ...

    final Binder newToken = new Binder();
    mCurrentDreamToken = newToken;
    mCurrentDreamName = name;
    mCurrentDreamIsTest = isTest;
    mCurrentDreamCanDoze = canDoze;
    mCurrentDreamUserId = userId;

    PowerManager.WakeLock wakeLock = mPowerManager
            .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
    // WakeLock#wrap() 方法,是保证在执行 Runnbale 之前获取锁,并且执行完 Runnable 后释放锁。
    // 也就是说,保持 CPU 运行,直到启动 doze dream 完毕。
    mHandler.post(wakeLock.wrap(() -> {
        mAtmInternal.notifyDreamStateChanged(true);
        if (!mCurrentDreamName.equals(mAmbientDisplayComponent)) {
            mUiEventLogger.log(DreamManagerEvent.DREAM_START);
        }
        // 开启 dream
        mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock);
    }));
}

通过 DreamController #startDream() 启动 doze dream

// DreamController.java

public void startDream(Binder token, ComponentName name,
        boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
    stopDream(true /*immediate*/, "starting new dream");

    try {
        // 其实是发送 Intent.ACTION_CLOSE_SYSTEM_DIALOGS 广播
        // Close the notification shade. No need to send to all, but better to be explicit.
        mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);

        // 1. 创建一条记录 dream 记录
        // 注意,DreamRecord 实现了 ServiceConnection
        mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId, wakeLock);

        mDreamStartTime = SystemClock.elapsedRealtime();
        MetricsLogger.visible(mContext,
                mCurrentDream.mCanDoze ? MetricsEvent.DOZING : MetricsEvent.DREAMING);

        Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
        intent.setComponent(name);
        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        try {
            // 2. 连接Service
            if (!mContext.bindServiceAsUser(intent, mCurrentDream,
                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                    new UserHandle(userId))) {
                Slog.e(TAG, "Unable to bind dream service: " + intent);
                stopDream(true /*immediate*/, "bindService failed");
                return;
            }
        } catch (SecurityException ex) {
            Slog.e(TAG, "Unable to bind dream service: " + intent, ex);
            stopDream(true /*immediate*/, "unable to bind service: SecExp.");
            return;
        }

        mCurrentDream.mBound = true;
        mHandler.postDelayed(mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
}

既然 doze dream 是一个 Service,那么启动它的过程就是绑定 Service 的过程。由于 DreamRecord 实现了 ServiceConnection,因此当服务成功连接上,会调用DreamRecord#onServiceConnected()

// DreamController.java

public void onServiceConnected(ComponentName name, final IBinder service) {
    mHandler.post(() -> {
        mConnected = true;
        if (mCurrentDream == DreamRecord.this && mService == null) {
            attach(IDreamService.Stub.asInterface(service));
            // Wake lock will be released once dreaming starts.
        } else {
            releaseWakeLockIfNeeded();
        }
    });
}

private void attach(IDreamService service) {
    try {
        // DreamRecord 监听 Service 生死
        service.asBinder().linkToDeath(mCurrentDream, 0);
        // 第三个参数是一个binder回调,用于接收结果
        service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze,
                mCurrentDream.mDreamingStartedCallback);
    } catch (RemoteException ex) {
        Slog.e(TAG, "The dream service died unexpectedly.", ex);
        stopDream(true /*immediate*/, "attach failed");
        return;
    }

    mCurrentDream.mService = service;

    // 发送 Intent.ACTION_DREAMING_STARTED 广播
    if (!mCurrentDream.mIsTest) {
        mContext.sendBroadcastAsUser(mDreamingStartedIntent, UserHandle.ALL);
        mCurrentDream.mSentStartBroadcast = true;
    }
}

可以看到,成功启动 Service 后,会调用 DreamService#attach() ,然后发送 dream 启动的广播 Intent.ACTION_DREAMING_STARTED

这里要结合具体的 doze dream Service 来分析,既然系统没有配置,那么以 SystemUI 中的 DozeService 为例进行分析,首先看看它的 onCreate() 过程

public class DozeService extends DreamService
        implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {


    @Override
    public void onCreate() {
        super.onCreate();
  
        // 设置为无窗口模式
        setWindowless(true);

        mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */);
        DozeComponent dozeComponent = mDozeComponentBuilder.build(this);
        mDozeMachine = dozeComponent.getDozeMachine();
    }
}  

注意,它设置了一个无窗口模式,后面会用到。

刚才分析过,DreamService 绑定成功后,会调用 DreamService#attach()

private void attach(IBinder dreamToken, boolean canDoze, IRemoteCallback started) {
    // ...

    mDreamToken = dreamToken;
    mCanDoze = canDoze;
    // 只有 doze dream 才能无窗口
    if (mWindowless && !mCanDoze) {
        throw new IllegalStateException("Only doze dreams can be windowless");
    }

    mDispatchAfterOnAttachedToWindow = () -> {
        if (mWindow != null || mWindowless) {
            mStarted = true;
            try {
                // 由子类实现
                onDreamingStarted();
            } finally {
                try {
                    started.sendResult(null);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
        }
    };

    if (!mWindowless) {
        // ...
    } else {
        // 无窗口下,直接调用 onDreamingStarted()
        mDispatchAfterOnAttachedToWindow.run();
    }
}

对于 SystemUI 的 DozeService,它是无窗口的,因此直接调用了它的 onDreamingStarted() 方法

// DozeService.java

public void onDreamingStarted() {
    super.onDreamingStarted();
    mDozeMachine.requestState(DozeMachine.State.INITIALIZED);
    // 调用父类的方法
    startDozing();
    if (mDozePlugin != null) {
        mDozePlugin.onDreamingStarted();
    }
}

再次进入 DreamService#startDozing()

public void startDozing() {
    if (mCanDoze && !mDozing) {
        mDozing = true;
        updateDoze();
    }
}

private void updateDoze() {
    if (mDreamToken == null) {
        Slog.w(TAG, "Updating doze without a dream token.");
        return;
    }

    if (mDozing) {
        try {
            // 通知 dream mananger,service 正在启动 doze 功能
            mDreamManager.startDozing(mDreamToken, mDozeScreenState, mDozeScreenBrightness);
        } catch (RemoteException ex) {
            // system server died
        }
    }
}

最终,把启动 doze 的信息返回给 DMS

// DreamManagerService.java

private void startDozingInternal(IBinder token, int screenState,
        int screenBrightness) {
    synchronized (mLock) {
        if (mCurrentDreamToken == token && mCurrentDreamCanDoze) {
            mCurrentDreamDozeScreenState = screenState;
            mCurrentDreamDozeScreenBrightness = screenBrightness;
            // 1. 通知PowerManagerService,保存doze状态下的屏幕状态和屏幕亮度
            mPowerManagerInternal.setDozeOverrideFromDreamManager(
                    screenState, screenBrightness);
            if (!mCurrentDreamIsDozing) {
                mCurrentDreamIsDozing = true;
                //2. 获取 PowerManager.DOZE_WAKE_LOCK 唤醒锁
                mDozeWakeLock.acquire();
            }
        }
    }
}

DMS又把信息传递给了 PMS,这些信息包括 doze 下的屏幕状态,以及屏幕亮度,而PMS也只是简单保存了这些信息.

然后获取了一个 PowerManager.DOZE_WAKE_LOCK,这就是设备进入打盹状态的最重要的一步。它会影响屏幕请求策略,如下

// PowerManagerService.java

int getDesiredScreenPolicyLocked(int groupId) {
    final int wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
    final int wakeLockSummary = mDisplayGroupPowerStateMapper.getWakeLockSummaryLocked(groupId);
    if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
        return DisplayPowerRequest.POLICY_OFF;
    } else if (wakefulness == WAKEFULNESS_DOZING) {
        // 如下的条件表示dream manager获取了 PowerManager.DOZE_WAKE_LOCK 唤醒锁
        if ((wakeLockSummary & WAKE_LOCK_DOZE) != 0) {
            return DisplayPowerRequest.POLICY_DOZE;
        }
        if (mDozeAfterScreenOff) {
            return DisplayPowerRequest.POLICY_OFF;
        }
    }

    // ...
}

可以看到 DMS成功获取到 PowerManager.DOZE_WAKE_LOCK 唤醒锁后,请求策略现在为 DisplayPowerRequest.POLICY_DOZE,这会导致屏幕进入 doze 状态,这是一种几乎休眠的状态,也是一种低功耗状态,并且开启了 AOD 功能,当然前提是屏幕支持这个功能。

三、SurfaceFlinger

参考链接

四、亮度设置流程

我在移植新平台时,发现应用层设置了亮度,但实际亮度没有变化,就整理了一下整个流程,查找问题

1、基本流程

android8和android11亮度设置流程存在差异,在JNI的时候,Android8通过HDIL 的light2.0接口去调用底层接口,android11通过调用surfaceflinger->DRM的流程去设置

在这里插入图片描述

2、Framework具体流程

2.1、BrightnessController.java

路径:frameworks/base/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java

app设置亮度后,最总会调用该文件中

        setBrightness(valFloat);
        if (!tracking) {
            AsyncTask.execute(new Runnable() {
                    public void run() {
                        Settings.System.putFloatForUser(mContext.getContentResolver(),
                                settingToChange, valFloat, UserHandle.USER_CURRENT);//调用DM中接口设置亮度
                    }
                });
        }

2.2、DisplayManager.java

路径:frameworks/base/core/java/android/hardware/display/DisplayManager.java

调用DRM中的setTemporaryBrightness

 public void setTemporaryBrightness(int brightness) {
		 mGlobal.setTemporaryBrightness(brightness);
 }

2.3、DisplayManagerGlobal.java

路径:frameworks/base/core/java/android/hardware/display/DisplayManagerGlobal.java

    public void setTemporaryBrightness(float brightness) {
        try {
            mDm.setTemporaryBrightness(brightness);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

2.4、DisplayManagerService.java

路径:frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java

        public void setTemporaryBrightness(float brightness) {
            mContext.enforceCallingOrSelfPermission(
                    Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
                    "Permission required to set the display's brightness");
            final long token = Binder.clearCallingIdentity();
            try {
                synchronized (mSyncRoot) {
                    mDisplayPowerController.setTemporaryBrightness(brightness);
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

2.5、DisplayPowerController.java

路径:frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

    public void setTemporaryBrightness(float brightness) {
        Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_BRIGHTNESS,
                Float.floatToIntBits(brightness), 0 /*unused*/);
        msg.sendToTarget();//发送msg,MSG_SET_TEMPORARY_BRIGHTNESS
    }
--->
	public void handleMessage(Message msg){
······
                case MSG_SET_TEMPORARY_BRIGHTNESS:
                    // TODO: Should we have a a timeout for the temporary brightness?
                    mTemporaryScreenBrightness = Float.intBitsToFloat(msg.arg1);
                    updatePowerState();
                    break;
······
	}
--->
	 private void updatePowerState() {
······
	animateScreenBrightness(brightness, 0);

······

	}
--->
 private void animateScreenBrightness(int target, int rate) {
 	//这一句就是关键的设置语句
 	if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
  	}
 }


2.6、RampAnimator.java

路径:frameworks/base/services/core/java/com/android/server/display/RampAnimator.java

    public boolean animateTo(float target, float rate) {

        // Immediately jump to the target the first time.
        if (mFirstTime || rate <= 0) {
            if (mFirstTime || target != mCurrentValue) {
                mFirstTime = false;
                mRate = 0;
                mTargetValue = target;
                mCurrentValue = target;
                mProperty.setValue(mObject, target);//设置亮度
                if (mAnimating) {
                    mAnimating = false;
                    cancelAnimationCallback();
                }
                if (mListener != null) {
                    mListener.onAnimationEnd();
                }
                return true;
            }
            return false;
        }

·······
}

2.7、DisplayPowerState.java

路径:frameworks/base/services/core/java/com/android/server/display/RampAnimator.java

                public void setValue(DisplayPowerState object, float value) {
                    object.setScreenBrightness(value);
                }
 setScreenBrightness(int brightness){...}
 scheduleScreenUpdate() {...}
 postScreenUpdateThreadSafe(){...}
 Runnable mScreenUpdateRunnable = new Runnable() {
 	...
 	mPhotonicModulator.setState(mScreenState, brightness)
 	...
 }

       public boolean setState(int state, float brightnessState) {
······

                    mPendingState = state;
                    mPendingBacklight = brightnessState;//亮度复制给全局变量(只是在PhotonicModulator类中是全局的)
                    boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
                    mStateChangeInProgress = stateChanged || mStateChangeInProgress;
                    mBacklightChangeInProgress = backlightChanged || mBacklightChangeInProgress;
······
                return !mStateChangeInProgress;
            }
        }
	public void run() {
            for (;;) {
                ······
                    brightnessState = mPendingBacklight;
                ······
                mBlanker.requestDisplayState(state, brightnessState);
            }
        }

2.8、再调回DMS

DisplayManagerService.java

                    public void requestDisplayState(int state, float brightness) {
                        // The order of operations is important for legacy reasons.
                        if (state == Display.STATE_OFF) {
                            requestGlobalDisplayStateInternal(state, brightness);
                        }

                        callbacks.onDisplayStateChange(state);

                        if (state != Display.STATE_OFF) {
                            requestGlobalDisplayStateInternal(state, brightness); //设置亮度
                        }
                    }
                };
--->
    private void requestGlobalDisplayStateInternal(int state, float brightnessState) {
······
                // Setting the display power state can take hundreds of milliseconds
                // to complete so we defer the most expensive part of the work until
                // after we have exited the critical section to avoid blocking other
                // threads for a long time.
                for (int i = 0; i < mTempDisplayStateWorkQueue.size(); i++) {
                    mTempDisplayStateWorkQueue.get(i).run();
                }

	}

2.9、LocalDisplayAdapter.java

路径:frameworks/base/services/core/java/com/android/server/display/LocalDisplayAdapter.java

                    public void run() {
······
                        // Apply brightness changes given that we are in a non-suspended state.
                        if (brightnessChanged || vrModeChange) {
                            setDisplayBrightness(brightnessState);
                        }
······
		}

--->
private void setDisplayBrightness(float brightness) {
······
                            if (mBacklight != null) {
                                mBacklight.setBrightness(brightness);//设置亮度
                            }
······
}

2.10、LightsService.java

路径:frameworks/base/services/core/java/com/android/server/lights/LightsService.java

这个位置比较关键了,通过此处,旧版本通过Light2.0接口去设置亮度,新版本通过DRM去设置亮度,framework的流程到此就结束了,以下google注释写的比较详细

        public void setBrightness(float brightness, int brightnessMode) {
            if (Float.isNaN(brightness)) {
                Slog.w(TAG, "Brightness is not valid: " + brightness);
                return;
            }
            synchronized (this) {
                // LOW_PERSISTENCE cannot be manually set
                if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
                    Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mHwLight.id
                            + ": brightness=" + brightness);
                    return;
                }
                // Ideally, we'd like to set the brightness mode through the SF/HWC as well, but
                // right now we just fall back to the old path through Lights brightessMode is
                // anything but USER or the device shouldBeInLowPersistenceMode().
                if (brightnessMode == BRIGHTNESS_MODE_USER && !shouldBeInLowPersistenceMode()
                        && mSurfaceControlMaximumBrightness == 255) {
                    // New system
                    // TODO: the last check should be mSurfaceControlMaximumBrightness != 0; the
                    // reason we enforce 255 right now is to stay consistent with the old path. In
                    // the future, the framework should be refactored so that brightness is a float
                    // between 0.0f and 1.0f, and the actual number of supported brightness levels
                    // is determined in the device-specific implementation.
                    if (DEBUG) {
                        Slog.d(TAG, "Using new setBrightness path!");
                    }
                    SurfaceControl.setDisplayBrightness(mDisplayToken, brightness);
                } else {
                    // Old system
                    int brightnessInt = BrightnessSynchronizer.brightnessFloatToInt(
                            getContext(), brightness);
                    int color = brightnessInt & 0x000000ff;
                    color = 0xff000000 | (color << 16) | (color << 8) | color;
                    setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
                }
            }

旧版本的亮度设置比较简单,通过JNI调用,就不再继续跟了,后续主要跟一下新版本的方式,

3、HAL流程

3.1、SurfaceFlinger.cpp

路径:frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) {
······
         return getHwComposer().setDisplayBrightness(*displayId, brightness);
······

3.2、hwc_session.cpp

路径:hardware/qcom/display/composer/hwc_session.cpp

int32_t HWCSession::SetDisplayBrightness(hwc2_display_t display, float brightness) {
  if (display >= HWCCallbacks::kNumDisplays) {
    return HWC2_ERROR_BAD_DISPLAY;
  }

  if (!hwc_display_[display]) {
    return HWC2_ERROR_BAD_PARAMETER;
  }

  return INT32(hwc_display_[display]->SetPanelBrightness(brightness));
}

3.3、hwc_display_builtin.cpp

路径:hardware/qcom/display/composer/hwc_session_services.cpp

int HWCSession::DisplayConfigImpl::SetPanelBrightness(uint32_t level) {
  if (!(0 <= level && level <= 255)) {
    return -EINVAL;
  }

  if (level == 0) {
    return INT32(hwc_session_->SetDisplayBrightness(HWC_DISPLAY_PRIMARY, -1.0f));
  } else {
    return INT32(hwc_session_->SetDisplayBrightness(HWC_DISPLAY_PRIMARY, (level - 1)/254.0f));
  }
}

3.4、display_builtin.cpp

路径:hardware/qcom/display/sdm/libs/core/display_builtin.cpp

DisplayError DisplayBuiltIn::SetPanelBrightness(float brightness) {
······
  DisplayError err = hw_intf_->SetPanelBrightness(level);

······

}

3.5、hw_peripheral_drm.cpp

路径:hardware/qcom/display/sdm/libs/core/drm/hw_peripheral_drm.cpp

DisplayError HWPeripheralDRM::SetPanelBrightness(int level) {
······
  int32_t bytes = snprintf(buffer, kMaxSysfsCommandLength, "%d\n", level);
  ssize_t ret = Sys::pwrite_(fd, buffer, static_cast<size_t>(bytes), 0);
······
}

fd就是kernel暴露的亮度设置节点,通过写节点去设置亮度,底层根据不同的屏幕或者连接形式,如spi、mipi等,去配置DDIC里的51寄存器,最终控制了显示屏的亮度。

4、总结

最开始碰到的亮度无法调节的问题,最终发现lightservice没有启动,导致2.10流程无法运行,将lightservice加上后就正常运行了。

整个流程还是比较简单的,主要是对上层的流程和JAVA不了解,导致梳理的时候比较吃力。调试手段主要是靠增加日志打印,全局搜索关键字等方式,非常麻烦,不知道有没有更好的方式

end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2310771.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker Desktop常见问题记录

1.docker pull报错&#xff0c;无法连接https://registry-1.docker.io/v2/ 报错信息如下&#xff1a; Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection(Client.Timeout exceeded …

vscode+vue前端开发环境配置

目录 一、安装Vue二、使用vue新建项目 一、安装Vue 在node.js安装好之后&#xff0c; npm config set registry https://registry.npmmirror.com# 安装vue相关工具&#xff0c;webpack用来项目构建、打包、资源整合等。 npm install webpack -g# 安装vue-cli脚手架 npm insta…

Hive-08之数据仓库之建模、分析

一、目标 掌握数据仓库基本概念熟悉数据仓库的模型建立 二、知识要点 1. 数据仓库基本介绍 英文名称为Data Warehouse&#xff0c;可简写为DW或DWH。数据仓库的目的是构建面向分析的集成化数据环境&#xff0c;为企业提供决策支持&#xff08;Decision Support&#xff09;…

仿12306项目(4)

基本预定车票功能的开发 对于乘客购票来说&#xff0c;需要有每一个车次的余票信息&#xff0c;展示给乘客&#xff0c;供乘客选择&#xff0c;因此首个功能是余票的初始化&#xff0c;之后是余票查询&#xff0c;这两个都是控台端。对于会员端的购票&#xff0c;需要有余票查询…

MySQL零基础教程16—表连接进阶

复习表别名 之前已经学习过&#xff0c;查询的时候可以使用as来对检索的列进行重命名&#xff0c;这样可以让sql更加简介&#xff0c;增强易读性&#xff08;as可以省略&#xff09; 此外&#xff0c;使用表别名还可以支持在一条select语句中&#xff0c;一个表是被多次使用 …

【JavaSE-3】运算符

1、什么是运算符 就是对常量或者变量进行操作的符号&#xff0c;如&#xff1a;&#xff0c;-&#xff0c;*&#xff0c;/ 表达式&#xff1a; 用运算符把常量或者变量连接起来的&#xff0c;符合java语法的式子就是表达式。 2、 算术运算符 2.1、基本四则运算符 - * / % 都…

直接法估计相机位姿

引入 在前面的文章&#xff1a;运动跟踪——Lucas-Kanade光流中&#xff0c;我们了解到特征点法存在一些缺陷&#xff0c;并且用光流法追踪像素点的运动来替代特征点法进行特征点匹配的过程来解决这些缺陷。而这篇文章要介绍的直接法则是通过计算特征点在下一时刻图像中的位置…

VS2022C#windows窗体应用程序调用DeepSeek API

目录 一、创建DeepSeek API Key 二、创建窗体应用程序 三、设计窗体 1、控件拖放布局‌‌ 2、主窗体【Form1】设计 3、多行文本框【tbContent】 4、提交按钮【btnSubmit】 5、单行文字框 四、撰写程序 五、完整代码 六、运行效果 七、其它 一、创建DeepSeek API Ke…

kettle插件-高性能插入更新插件Upsert

场景&#xff1a;假如T日需要将a表中T-1日的数据同步到b表。由于某种业务需求a表中已经同步到b表中的数据发生了变化需要重新同步&#xff0c;这个时候就会用到插入更新插件&#xff0c;也就是 说a表中数据重新同步b表&#xff0c;若b表中存在此数据&#xff08;根据唯一id&am…

本地部署Qwen2.5-VL-7B-Instruct模型

本地部署Qwen2.5-VL-7B-Instruct模型 本地部署Permalink **创建环境** conda create -n qwenvl python3.11 -y# 报错&#xff1a; Solving environment: failedPackagesNotFoundError: The following packages are not available from current channels:# 处理&#xff1a; c…

【C++学习篇】智能指针

目录 1. 智能指针的使用场景分析 2. RAII和智能指针的设计思路 3. C标准库智能指针的使用 4.shared_ptr和weak_ptr 4.1shared_ptr的循环引用问题 4.2 weak_ptr 1. 智能指针的使用场景分析 下⾯程序中我们可以看到&#xff0c;new了以后&#xff0c;我们也delete了&#xff0c…

决策树(Decision Tree)基础知识

目录 一、回忆1、*机器学习的三要素&#xff1a;1&#xff09;*函数族2&#xff09;*目标函数2.1&#xff09;*模型的其他复杂度参数 3&#xff09;*优化算法 2、*前处理/后处理1&#xff09;前处理&#xff1a;特征工程2&#xff09;后处理&#xff1a;模型选择和模型评估 3、…

Excel基础(详细篇):总结易忽视的知识点,有用的细节操作

目录 写在前面基础篇Excel主要功能必会快捷键快捷键整理表LotusExcel的文件类型工作表基本操作表项操作选中与缩放边框线 自动添加边框线格式刷设置斜线表头双/多斜线表头不变形的:双/多斜线表头插入多行、多列单元格/行列的移动冻结窗口 方便查看数据打印的常见问题Excel格式…

Linux下学【MySQL】中如何实现:多表查询(配sql+实操图+案例巩固 通俗易懂版~)

每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” 绪论&#xff1a; 本章是MySQL篇中&#xff0c;非常实用性的篇章&#xff0c;相信在实际工作中对于表的查询&#xff0c;很多时候会涉及多表的查询&#xff0c;在多表查询的…

非平稳时间序列分析(三)——季节模型(SARIMA、STL、Holt-Winters)

此前篇章&#xff08;平稳序列&#xff09;&#xff1a; 时间序列分析&#xff08;一&#xff09;——基础概念篇 时间序列分析&#xff08;二&#xff09;——平稳性检验 时间序列分析&#xff08;三&#xff09;——白噪声检验 时间序列分析&#xff08;四&#xff09;—…

【web前端开发】CSS--CSS简介及其编写位置(上)

1、CSS简介 &#xff08;1&#xff09;CSS的全称为&#xff1a;层叠式样式表&#xff08;Cascading Style Sheets&#xff09; &#xff08;2&#xff09;CSS也是一种标记语言&#xff0c;用于给HTML结构设置样式&#xff0c;例如&#xff1a;文字大小、颜色、元素宽度等等…

云原生时代的技术桥梁

在数字化转型的大潮中&#xff0c;企业面临着数据孤岛、应用间集成复杂、高成本与低效率等问题。这些问题不仅阻碍了企业内部信息的流通和资源的共享&#xff0c;也影响了企业对外部市场变化的响应速度。当前&#xff0c;这一转型过程从IT角度来看&#xff0c;已然迈入云原生时…

【数据结构】什么是栈||栈的经典应用||分治递归||斐波那契问题和归并算法||递归实现||顺序栈和链栈的区分

文章目录 &#x1f967;栈的初步理解&#xff1a;&#x1f967;易错&#xff1a;如何判断栈满&#x1f967;栈满理解&#x1f967;栈的基本运算&#x1f4da;栈操作的伪代码逻辑&#xff08;顺序和链栈&#xff09;&#x1f4d5;顺序栈运算实现&#xff1a;顺序栈的表示&#x…

雷池WAF的为什么选择基于Docker

Docker 是一种开源的容器化平台&#xff0c;可以帮助开发人员将应用程序及其所有依赖项打包到一个称为容器的独立、可移植的环境中。Docker 的核心概念包括以下几点&#xff1a; 容器&#xff1a;Docker 使用容器来封装应用程序及其依赖项&#xff0c;使其能够在任何环境中都能…

Ubuntu20.04双系统安装及软件安装(七):Anaconda3

Ubuntu20.04双系统安装及软件安装&#xff08;七&#xff09;&#xff1a;Anaconda3 打开Anaconda官网&#xff0c;在右侧处填写邮箱&#xff08;要真实有效&#xff01;&#xff09;&#xff0c;然后Submit。会出现如图示的Success界面。 进入填写的邮箱&#xff0c;有一封Ana…