前言
亮灭涉及的东西非常多,因此单独写一个文档,进行详细说明,亮灭屏包括的东西不只是亮灭屏,还包括亮度调节、屏幕状态变化等东西。本文仅作学习使用,不涉及商业,侵权请联系删除。
framework层的学习链接:Android R PowerManagerService模块(3) 亮屏流程 - 掘金 (juejin.cn)
一、概述
当响应按键事件时,屏幕的整个系统,一般分为两部分,按键事件传递流程和屏幕响应流程,中间通过策略类来衔接。如下图所示。框架上分为硬件层、驱动层、framework层。
对于事件的传递流程暂时不做了解,未来走TP流程的时候再细细琢磨,本文主讲屏幕响应的部分,将从上层应用走到底层硬件的所有流程。
对部分名词进行简称:PMS(PowerMangerService)
DMC(DisplayManagerControl)
DMS(DisplayManagerServices)
二、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:
更新屏幕电源状态的很清晰,如下
- 首先获取请求,并更新请求参数。请求参数中,主要关心的是策略参数,它决定了屏幕的状态,也就是到底是亮屏还是灭屏。
- 向 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();
}
}
// ...
}
更新梦境状态过程如下
- 判断是否能进入梦境。梦境其实有两种功能,一种是屏保,另一种是 doze 组件。由于此时 wakefulness 为 WAKEFULNESS_DOZING,因此可以满足启动 doze dream 的条件。
- 通过 dream manager 启动 dream。此时,启动的就是 doze dream,而不是屏保。
- 如果正在启动,那就继续。继续什么呢?查看下节。
- 如果启动失败,进入休眠的流程。
休眠的流程最简单了,首先更新 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