作者:FightFightFight
来源:CSDN
原文:https://blog.csdn.net/FightFightFight/article/details/81320519
概述
DisplayPowerController(以下简称DPC)用于控制显示电源状态,用来处理亮灭屏、背光的调节,包括接近传感器(P-Senser)、光线传感器(L-senser)和亮灭屏动画。它独立于PMS的其余部分,并且不共享任何状态,而是通过DisplayPowerCallbacks接口异步回调进行通信,通知PMS有关Display的改变。当PMS中请求屏幕状态时,会等待它返回一个结果,这个结果表示显示是否准备完成(mDisplayReady)。如果显示未准备就绪,则mDisplayReady为false。
可以将DPC看做是PMS和DMS的之间的一个“中介”,此外由于DPC的功能就是独立于PMS之外,PMS将Display交给它处理,因此在分析DPC时,以Display为切入点进行分析,因此在下面我们从亮屏、灭屏、亮度调节开始进行分析。
在PMS相关文档中已经分析过了PMS部分的亮屏、灭屏了,然而,仅仅是分析了PMS中相关的逻辑,并没有分析之后在DisplayPowerController中的逻辑,分析到updatePowerStateLocked()时就停止了。在PMS的updatePowerStateLocked()方法中,会调用updateDisplayPowerStateLocked()更新显示,而这个方法中更新显示时,是通过DPC完成,接下来我们将以之前的分析过的接口为入口点,开始分析DisplayPowerController中的逻辑。
1.requestPowerState()
这个方法是亮屏、亮度调节的入口方法,PMS中调用该方法从而进入DisplayPowerController并和DisplayManagerService交互。
该方法工作原理是这样的:当亮屏或者亮度调节时,最终都会走PMS中的updatePowerStateLocked()方法,在这个方法中,通过DMS的LocalService传入封装了Display信息的DisplayPowerState对象去请求DMS,之后进入DisplayPowerController中的requsetPowerState()方法中,在这个方法中,首先会判断这次请求的DisplayPowerState是否改变,如果改变,则表示这是一次新的请求,此时在Handler中异步去执行更新操作,同时,返回给PMS的返回值mDisplayReadyLock置为false,表示Display没有更新完成。当异步操作完成后,将mDisplayReadyLock置为true,同时回调DisplayPowerCallback.onStateChanged()方法,PMS重写了这个方法,在这个方法中又调用updatePowerState()方法,因此再此会请求一遍DMS,在这次请求中,由于DisplayPowerState,没有改变,因此直接返回mDisplayReadyLock了。
首先来看PMS中的请求显示的逻辑:
private boolean updateDisplayPowerStateLocked(int dirty) {
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
return mDisplayReady && !oldDisplayReady;
}
接下来开始详细分析这个方法,其代码如下:
/**
* @param request PMS中传入的DisplayPowerState对象,封装了Display信息
* @param waitForNegativeProximity 如果带有PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY标记,则该值为true,表示在由PSensor灭屏后,当释放PROXIMITY WakeLock时,不会立即亮屏,而是直到等待PSensor收到远离事件后才亮屏
* @return 如果display改变完成则返回true
*/
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mLock) {
boolean changed = false;
if (waitForNegativeProximity
&& !mPendingWaitForNegativeProximityLocked) {
mPendingWaitForNegativeProximityLocked = true;
changed = true;
}
//开机后第一次进入
if (mPendingRequestLocked == null) {
mPendingRequestLocked = new DisplayPowerRequest(request);
changed = true;
//如果该次请求和上次请求不同,说明有状态改变,需要更新Display
} else if (!mPendingRequestLocked.equals(request)) {
mPendingRequestLocked.copyFrom(request);
changed = true;
}
/**
* changed为true,说明有改变发生,这个改变交给Handler异步去处理,此时说
* 明显示没有准备好,mDisplayReadyLocked=false
* 直到改变处理成功,mDisplayReadyLocked将被置为true,
*/
if (changed) {
mDisplayReadyLocked = false;
}
//mPendingRequestChangedLocked:用于标识电源请求状态或者PSensor标签是
//否改变
if (changed && !mPendingRequestChangedLocked) {
mPendingRequestChangedLocked = true;
sendUpdatePowerStateLocked();
}
return mDisplayReadyLocked;
}
}
Changed表示是否需要改变Display。这个方法中就好比一扇门,只有符合条件才能进入到下一个阶段。条件是什么呢?
1.先会对第二个形参进行判断,waitForNegativeProximity如果为true,则表示在释放PSensor相关的WakeLock时,如果PSensor还是靠近事件,则必须等待PSensor远离后才会亮屏,这个值释放wakelock时传入的flag有关,如果在释放wakelock时使用release(PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY)的形式释放PSensor的WakeLock,则该值为true,大多数场景下为false;
2.如果开机第一次进入该函数,则实例化代表将要请求的DisplayPowerRequest对象。
3.如果本次请求和上次请求不相同,则说明需要更新Display。mPendingRequestChangedLocked用于标识电源请求状态是否要改变,如果changed变为true,则该值会由false变为true,之后又会置为false。
如果满足以上条件,则changed变为true,表示Display需要改变,因此,调用sendUpdatePowerStateLocked()方法获取Handler,并使用Handler进行Display的更新,同时返回值为false,表示Display还没有更新准备完成。
再来看看第二个参数waitForNegativeProximity,这个值来自于PMS中:
private void releaseWakeLockInternal(IBinder lock, int flags) {
if ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) {
mRequestWaitForNegativeProximity = true;
}
}
因此,在释放WakeLock锁时,如果带有PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY标记,该值就是true,并且在每一次请求完Display之后又会重新置为false,在updateDisplayPowerStateLocked()方法中可以看到。通话过程中,如果由PSensor灭屏并一直保持,然后按Power键,此时系统将执行goToSleep流程,当再次按power键,此时系统将执行Wakeup流程,但是,如果waitForNegativeProximity为true,则系统不会亮屏,直到PSensor接收到远离数据而亮屏。具体的逻辑在updatePowerState()方法中,下面会提到。
再继续分析其异步做了哪些处理,我们接着上一步骤的分析,看看sendUpdatePowerStateLocked()方法:
private void sendUpdatePowerStateLocked() {
if (!mPendingUpdatePowerStateLocked) {
//要打算更新电源状态了
mPendingUpdatePowerStateLocked = true;
//异步更新
Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
这个方法中获取了Handler,并通过异步的方式调用了updatePowerState()方法执行下步处理:
case MSG_UPDATE_POWER_STATE:
updatePowerState();
break;
2.updatePowerState()
updatePowerState()方法是一个非常庞大的方法,也是DisplayPowerController中的核心方法,其中处理亮灭屏、调节亮度,都会在这里进行决策处理。该方法的完整代码如下:
private void updatePowerState() {
// Update the power state request.
//当DisplayPowerController中更新屏幕状态成功后是否必须通知PMS
final boolean mustNotify;
//是否要进行初始化
boolean mustInitialize = false;
//是否自动调节亮度调节值改变
boolean autoBrightnessAdjustmentChanged = false;
synchronized (mLock) {
//该值表示"是否将要更新电源状态",重置该值为false,从而可以被下一次
//sendUpdatePowerStateLocked()处理该方法
mPendingUpdatePowerStateLocked = false;
//表示"将要请求的DisplayPowerRequest对象",当PMS中发起请求后,
//在requestDisplayPowerState()中会将请求携带的DPS对象赋给该值,
//或者在系统启动时,通过请求携带的DPS对象实例化该值
if (mPendingRequestLocked == null) {
return; // wait until first actual power request
}
//mPowerRequest表示"当前的电源请求状态",初始值为null,
//由mPengdingReqestLocked对象拷贝或实例化
//因此只有系统开机后第一次会进入if中,之后不会进入
if (mPowerRequest == null) {
mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
mWaitingForNegativeProximity =
mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
mPendingRequestChangedLocked = false;
mustInitialize = true;
//标记值,如果请求状态和当前状态不同,则true
} else if (mPendingRequestChangedLocked) {
//自动调节亮度值是否改变,由"当前电源的请求状态"和"将要请求的电源请求状态"比较
autoBrightnessAdjustmentChanged =
(mPowerRequest.screenAutoBrightnessAdjustment
!= mPendingRequestLocked.screenAutoBrightnessAdjustment);
//复制mPendingRequestLocked给mPowerRequset,
//即将"将要请求的电源请求状态"赋给"当前电源的请求状态"
mPowerRequest.copyFrom(mPendingRequestLocked);
//mWaitingForNegativeProximity表示在亮屏之前是否要等待PSensor接收到远事件值
//该值由PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY标记在释放锁时决定
mWaitingForNegativeProximity |=
mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
//重置该值为false
mPendingRequestChangedLocked = false;
//表示未准备就绪
mDisplayReadyLocked = false;
}
//是否进行通知
mustNotify = !mDisplayReadyLocked;
}
// Initialize things the first time the power state is changed.
if (mustInitialize) {
//初始化亮灭屏动画、mPowerState等
initialize();
}
int state;
int brightness = PowerManager.BRIGHTNESS_DEFAULT;
boolean performScreenOffTransition = false;
//根据PMS中的请求参数决定屏幕状态和屏幕亮度值
switch (mPowerRequest.policy) {
//灭屏
case DisplayPowerRequest.POLICY_OFF:
state = Display.STATE_OFF;
performScreenOffTransition = true;
break;
//Doze模式
case DisplayPowerRequest.POLICY_DOZE:
if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
state = mPowerRequest.dozeScreenState;
} else {
state = Display.STATE_DOZE;
}
//是否允许在自动调节亮度下配置doze亮度值
if (!mAllowAutoBrightnessWhileDozingConfig) {
brightness = mPowerRequest.dozeScreenBrightness;
}
break;
//VR模式
case DisplayPowerRequest.POLICY_VR:
state = Display.STATE_VR;
break;
//DIM和亮屏
case DisplayPowerRequest.POLICY_DIM:
case DisplayPowerRequest.POLICY_BRIGHT:
default:
state = Display.STATE_ON;
break;
}
assert(state != Display.STATE_UNKNOWN);
// Apply the proximity sensor.
//PSensor相关
/*-------------PSensor设置 beg--------------*/
if (mProximitySensor != null) {
//如果mPowerRequest.useProximitySensor=true&&Display状态不等于灭屏
if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
//设置Psensor可用
setProximitySensorEnabled(true);
if (!mScreenOffBecauseOfProximity
&& mProximity == PROXIMITY_POSITIVE) {
//该值表示由PSensor灭屏
mScreenOffBecauseOfProximity = true;
//通过DisplayPowerCallback回调PMS
sendOnProximityPositiveWithWakelock();
}
} else if (mWaitingForNegativeProximity //如果该值为true
&& mScreenOffBecauseOfProximity //且由PSensor灭屏
&& mProximity == PROXIMITY_POSITIVE //且当前PSensor靠近
&& state != Display.STATE_OFF) {//且Display状态不为灭屏状态
setProximitySensorEnabled(true);
} else {
//不满足以上条件,设置PSensor不可用
setProximitySensorEnabled(false);
mWaitingForNegativeProximity = false;
}
//如果满足说明此时PSensor处理远离事件,重置mScreenOffBecauseOfProximity为false
if (mScreenOffBecauseOfProximity
&& mProximity != PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = false;
sendOnProximityNegativeWithWakelock();
}
} else {
mWaitingForNegativeProximity = false;
}
//由PSensor灭屏为true,则将state置位DISPLAY.STATE_OFF
if (mScreenOffBecauseOfProximity) {
state = Display.STATE_OFF;
}
/*-------------PSensor设置 end--------------*/
//获取屏幕状态,此时还未设置新的屏幕状态,因此是”旧”的
final int oldState = mPowerState.getScreenState();
//在这个方法中会进行屏幕状态、亮度的设置和处理亮灭屏动画
animateScreenStateChange(state, performScreenOffTransition);
//获取屏幕状态,此时已经设置新的屏幕状态
state = mPowerState.getScreenState();
// Use zero brightness when screen is off.
//如果屏幕状态为灭屏,设置亮度为0
if (state == Display.STATE_OFF) {
brightness = PowerManager.BRIGHTNESS_OFF;
}
// Configure auto-brightness.
//自动调节亮度是否可用
boolean autoBrightnessEnabled = false;
if (mAutomaticBrightnessController != null) {
//Doze模式下自动调节亮度是否可用
final boolean autoBrightnessEnabledInDoze =
mAllowAutoBrightnessWhileDozingConfig
&& (state == Display.STATE_DOZE || state ==
Display.STATE_DOZE_SUSPEND);
autoBrightnessEnabled = mPowerRequest.useAutoBrightness
&& (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
&& brightness < 0;
final boolean userInitiatedChange = autoBrightnessAdjustmentChanged
&& mPowerRequest.brightnessSetByUser;
//配置AutomaticBrightnessController
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mPowerRequest.screenAutoBrightnessAdjustment, state !=
Display.STATE_ON, userInitiatedChange);
}
/*----------------------亮度调节值计算 BEG-------------------------------------*/
//brightnessboost相关
if (mPowerRequest.boostScreenBrightness
&& brightness != PowerManager.BRIGHTNESS_OFF) {
brightness = PowerManager.BRIGHTNESS_ON;
}
// Apply auto-brightness.
boolean slowChange = false;
//如果brightness=PowerManager.BRIGHTNESS_DEFAULT=-1,说明请求屏幕状态非Off
if (brightness < 0) {//default = -1
//如果自动调节亮度可用
if (autoBrightnessEnabled) {
//从AutomaticBrightnessController中获取自动调节亮度值
brightness =
mAutomaticBrightnessController.getAutomaticScreenBrightness();
}
if (brightness >= 0) {//说明使用了自动亮度
// Use current auto-brightness value and slowly adjust to changes.
//调整brightness保持在最小值和最大值之间
//即mScreenBrightnessRangeMinimum <= brightness <= mScreenBrightnessRangeMaximum
brightness = clampScreenBrightness(brightness);
if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
slowChange = true; // slowly adapt to auto-brightness
}
mAppliedAutoBrightness = true;//表示使用自动亮度
} else {
mAppliedAutoBrightness = false;
}
} else {
mAppliedAutoBrightness = false;
}
//如果PMS中请求的屏幕状态为Doze,则将亮度设置为Doze状态的亮度
if (brightness < 0 && (state == Display.STATE_DOZE
|| state == Display.STATE_DOZE_SUSPEND)) {
brightness = mScreenBrightnessDozeConfig;
}
//如果此时brightness还为-1,说明没有使用自动调节亮度和doze状态亮度,则使用手动设置亮度
if (brightness < 0) {
//获取screenBrightness并在取值区间进行判断
brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
}
// Apply dimming by at least some minimum amount when user activity
// timeout is about to expire.
//如果PMS中请求屏幕状态为Dim状态,则使用dim状态时的亮度,基于手动调节值
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
if (brightness > mScreenBrightnessRangeMinimum) {
brightness = Math.max(Math.min(brightness -
SCREEN_DIM_MINIMUM_REDUCTION,
mScreenBrightnessDimConfig),
mScreenBrightnessRangeMinimum);
}
if (!mAppliedDimming) {
slowChange = false;
}
mAppliedDimming = true;//表示采用Dim状态brightness
} else if (mAppliedDimming) {
slowChange = false;
mAppliedDimming = false;
}
// If low power mode is enabled, scale brightness by
// screenLowPowerBrightnessFactor
// as long as it is above the minimum threshold.
//如果开启了低电量模式,则亮度值为brightness*brightnessFactor
if (mPowerRequest.lowPowerMode) {
if (brightness > mScreenBrightnessRangeMinimum) {
final float brightnessFactor =
Math.min(mPowerRequest.screenLowPowerBrightnessFactor, 1);
final int lowPowerBrightness = (int) (brightness * brightnessFactor);
brightness = Math.max(lowPowerBrightness,
mScreenBrightnessRangeMinimum);
}
if (!mAppliedLowPower) {
slowChange = false;
}
mAppliedLowPower = true;//表示采用低电量brightness
} else if (mAppliedLowPower) {
slowChange = false;
mAppliedLowPower = false;
}
// Animate the screen brightness when the screen is on or dozing.
// Skip the animation when the screen is off or suspended or transition to/from VR.
/*----------------------亮度调节值计算 END-------------------------------------*/
/*----------------------亮度动画 BEG-------------------------------------*/
//亮度值计算完毕,下面根据请求屏幕状态决定是否在调节亮度时使用动画
//当不打算灭屏时,即屏幕状态已经为灭屏或处于其他状态
if (!mPendingScreenOff) {
//是否在亮屏时跳过亮度坡度调节,默认false
if (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状态
boolean wasOrWillBeInVr = (state == Display.STATE_VR || oldState == Display.STATE_VR);
//如果当前屏幕状态或请求屏幕状态为亮屏
if ((state == Display.STATE_ON
&& mSkipRampState == RAMP_STATE_SKIP_NONE
|| state == Display.STATE_DOZE
&& !mBrightnessBucketsInDozeConfig)
&& !wasOrWillBeInVr) {
//设置亮度,slowChange=true应用于自动调节亮度
animateScreenBrightness(brightness,
slowChange ? mBrightnessRampRateSlow :
mBrightnessRampRateFast);
} else {
//其他情况下不适用亮度动画,直接设置亮度
animateScreenBrightness(brightness, 0);
}
}
/*----------------------亮度动画 END-------------------------------------*/
//ready表示屏幕状态是否准备完成,mPendingScreenOnUnblocker用于亮屏过程中,
//该值非空表示屏幕目前被阻塞,等待WindowManager回调,回调后将被置为null
//mColorFadeOnAnimator,mColorFadeOffAnimator表示亮屏和灭屏动画
final boolean ready = mPendingScreenOnUnblocker == null &&
(!mColorFadeEnabled ||
(!mColorFadeOnAnimator.isStarted()
&& !mColorFadeOffAnimator.isStarted()))
&& mPowerState.waitUntilClean(mCleanListener);
//表示屏幕状态准备完成,同时亮度设置也完成
final boolean finished = ready
&& !mScreenBrightnessRampAnimator.isAnimating();
// Notify policy about screen turned on.
if (ready && state != Display.STATE_OFF
&& mReportedScreenStateToPolicy ==
REPORTED_TO_POLICY_SCREEN_TURNING_ON) {
//设置屏幕状态报告值,该值表示亮屏完成
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_ON);
//通知WindowManager亮屏完成
mWindowManagerPolicy.screenTurnedOn();
}
// Grab a wake lock if we have unfinished business.
//finish为false,表示屏幕状态或者屏幕背光没有设置完成,需要申请一个Display锁
if (!finished && !mUnfinishedBusiness) {
mCallbacks.acquireSuspendBlocker();//申请Display锁
mUnfinishedBusiness = true;
}
// Notify the power manager when ready.
//当屏幕准备就绪,通知PMS
if (ready && mustNotify) {
// Send state change.
synchronized (mLock) {
if (!mPendingRequestChangedLocked) {
//表示屏幕状态准备就绪,就绪和亮度设置完成无关,只和屏幕状态有关
mDisplayReadyLocked = true;
}
}
//在该方法中回调PMS方法
sendOnStateChangedWithWakelock();
}
// Release the wake lock when we have no unfinished business.
//完成后释放Display锁
if (finished && mUnfinishedBusiness) {
mUnfinishedBusiness = false;
mCallbacks.releaseSuspendBlocker();
}
//mDozing记录状态值
mDozing = state != Display.STATE_ON;
}
从方法源码来看,这个方法可以拆分为六部分:
第一部分:初始化相关变量;
第二部分:根据PMS请求时携带的DisplayPowerState.policy以及PSensor相关确定要请求的屏幕状态state的值;
第三部分:调用animateScreenState()方法设置屏幕状态(灭屏时还会先设置brightness=0);
第四部分:计算亮度值,即调节亮度时的值;
从代码看,在计算亮度值时,影响亮度值的有:自动调节亮度的亮度值、Doze状态下的亮度值(配置文件中读取)、用户手动设置的亮度值、Dim状态下的亮度值、低电量模式下的亮度值,最终会根据当前的场景来选择亮度值。
第五部分:通过animateScreenBrightness()设置亮度值调节动画;
第六部分:当完成屏幕状态更新和亮度更新后、分别通知WindowManager、PMS进行相应操作。
3.animateScreenStateChange()
这个方法在updatePowerState()中调用,用来设置屏幕状态、屏幕亮度(仅仅设置灭屏亮度0)、执行灭屏动画,同时调用WindowManager中的接口进行window的绘制等。先来看看这个方法:
private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
//如果mColorFadeEnabled可用且有动画在执行还未结束,说明正在屏幕转换流程中
if (mColorFadeEnabled &&
(mColorFadeOnAnimator.isStarted() || mColorFadeOffAnimator.isStarted())) {
if (target != Display.STATE_ON) {
//如果目标状态不是亮屏状态,直接返回
return;
}
//将该变量值置为false,该变量用来表示是否打算灭屏
mPendingScreenOff = false;
}
//该值为false,表示在退出doze状态时是否跳过灭屏动画
if (mDisplayBlanksAfterDozeConfig
&& Display.isDozeState(mPowerState.getScreenState())//当前显示状态为doze状态
&& !Display.isDozeState(target)) {//目标状态非doze
mPowerState.prepareColorFade(mContext,
mColorFadeFadesConfig ? ColorFade.MODE_FADE : ColorFade.MODE_WARM_UP);
if (mColorFadeOffAnimator != null) {
mColorFadeOffAnimator.end();
}
setScreenState(Display.STATE_OFF, target != Display.STATE_OFF /*reportOnly*/);
}
//设置显示状态为灭屏状态,mPendingScreenOff表示打算灭屏,在进行灭屏时会设置为true
if (mPendingScreenOff && target != Display.STATE_OFF) {
setScreenState(Display.STATE_OFF);
mPendingScreenOff = false;
mPowerState.dismissColorFadeResources();
}
//目标状态为亮屏,则调用setScreenState()设置,并根据返回值确定是否继续下面的操作
if (target == Display.STATE_ON) {
if (!setScreenState(Display.STATE_ON)) {
return; // screen on blocked
}
//亮屏动画
if (USE_COLOR_FADE_ON_ANIMATION && mColorFadeEnabled && mPowerRequest.isBrightOrDim()) {
// Perform screen on animation.
if (mPowerState.getColorFadeLevel() == 1.0f) {
mPowerState.dismissColorFade();
} else if (mPowerState.prepareColorFade(mContext,
mColorFadeFadesConfig ?
ColorFade.MODE_FADE :
ColorFade.MODE_WARM_UP)) {
mColorFadeOnAnimator.start();
} else {
mColorFadeOnAnimator.end();
}
} else {
// Skip screen on animation.
mPowerState.setColorFadeLevel(1.0f);
mPowerState.dismissColorFade();
}
} else if (target == Display.STATE_VR) {
// Wait for brightness animation to complete beforehand when entering VR
// from screen on to prevent a perceptible jump because brightness may operate
// differently when the display is configured for dozing.
if (mScreenBrightnessRampAnimator.isAnimating()
&& mPowerState.getScreenState() == Display.STATE_ON) {
return;
}
// Set screen state.
if (!setScreenState(Display.STATE_VR)) {
return; // screen on blocked
}
// Dismiss the black surface without fanfare.
mPowerState.setColorFadeLevel(1.0f);
mPowerState.dismissColorFade();
} else if (target == Display.STATE_DOZE) {
// Want screen dozing.
// Wait for brightness animation to complete beforehand when entering doze
// from screen on to prevent a perceptible jump because brightness may operate
// differently when the display is configured for dozing.
if (mScreenBrightnessRampAnimator.isAnimating()
&& mPowerState.getScreenState() == Display.STATE_ON) {
return;
}
// Set screen state.
if (!setScreenState(Display.STATE_DOZE)) {
return; // screen on blocked
}
// Dismiss the black surface without fanfare.
mPowerState.setColorFadeLevel(1.0f);
mPowerState.dismissColorFade();
} else if (target == Display.STATE_DOZE_SUSPEND) {
if (mScreenBrightnessRampAnimator.isAnimating()
&& mPowerState.getScreenState() != Display.STATE_DOZE_SUSPEND) {
return;
}
if (mPowerState.getScreenState() != Display.STATE_DOZE_SUSPEND) {
if (!setScreenState(Display.STATE_DOZE)) {
return; // screen on blocked
}
setScreenState(Display.STATE_DOZE_SUSPEND); // already on so can't block
}
// Dismiss the black surface without fanfare.
mPowerState.setColorFadeLevel(1.0f);
mPowerState.dismissColorFade();
} else {//除以上情况外,目标状态就为灭屏状态
// Want screen off.将mPendingScreenOff置为ture
mPendingScreenOff = true;
if (!mColorFadeEnabled) {
//colorfadelevel和图像显示有关,正常显示时为1,灭屏后就为0了
mPowerState.setColorFadeLevel(0.0f);
}
//如果进入该语句,说明此时灭屏完成
if (mPowerState.getColorFadeLevel() == 0.0f) {
// Turn the screen off.
// A black surface is already hiding the contents of the screen.
setScreenState(Display.STATE_OFF);
mPendingScreenOff = false;
mPowerState.dismissColorFadeResources();
} else if (performScreenOffTransition //是否执行灭屏动画
&& mPowerState.prepareColorFade(mContext,
mColorFadeFadesConfig ?
ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN) //colorfade是否准备就绪
&& mPowerState.getScreenState() != Display.STATE_OFF) {
// Perform the screen off animation.
mColorFadeOffAnimator.start(); //开始执行灭屏动画
} else {
// Skip the screen off animation and add a black surface to hide the
// contents of the screen.
mColorFadeOffAnimator.end();//不执行灭屏动画,
}
}
}
在这个方法中,一些内容就不再进行分析了,在代码中都有对应的注释,这里我们只分析重点代码。首先,在进入该方法后,变量mPendingScreenOff设置为false,该值意思就是"是否打算将要灭屏?";其次,会根据参数target来进行决策,并调用setScreenState()进行设置对应的屏幕状态,最后,会根据是否需要动画效果而显示动画效果。
现在以灭屏为例,当灭屏时,由updatePowerState()中调用该方法,我们已经分析过了,target为Display.STATE_OFF,进入该方法后,此时只满足最后一个else语句:
} else {
// Want screen off.
mPendingScreenOff = true;//设置为true
//如果colorFadeEnable=false,则直接将ColorFade设置为0.0
if (!mColorFadeEnabled) {
mPowerState.setColorFadeLevel(0.0f);
}
if (mPowerState.getColorFadeLevel() == 0.0f) {
// Turn the screen off.
// A black surface is already hiding the contents of the screen.
//设置屏幕状态为Display.STATE_OFF
setScreenState(Display.STATE_OFF);
mPendingScreenOff = false;
mPowerState.dismissColorFadeResources();
} else if (performScreenOffTransition //是否只执行灭屏动画
&& mPowerState.prepareColorFade(mContext,
mColorFadeFadesConfig ?
ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN)
&& mPowerState.getScreenState() != Display.STATE_OFF) {
// Perform the screen off animation.
mColorFadeOffAnimator.start();//开始执行灭屏动画
} else {
// Skip the screen off animation and add a black surface to hide the
// contents of the screen.
mColorFadeOffAnimator.end(); //停止灭屏动画
}
}
}
在这个else中,首先设置mPendingScreenOff为true,表示打算灭屏了,其次如果mColorFadeEnable为false,表示颜色渲染不可以用,则直接将ColorFadeLevel设置为0。接下来,分三种情况进行分析:
1.如果ColorFadeLevel为0了,就可以设置屏幕状态了,因此直接setScreenState(Display.STATE_OFF),这种情况下,只需执行一遍animateScreenStateChanged()方法,就将屏幕状态值设置;
2.如果可以执行灭屏动画且ColorFade已经准备就绪,则开始执行灭屏动画,在灭屏动画结束后,又将异步回调一次该方法,在这次调用时,由于灭屏动画的执行将ColorFadeLevel设置为0,因此执行条件一,从而完成设置屏幕状态;
mColorFadeOffAnimator = ObjectAnimator.ofFloat(
mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f);
mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS);
mColorFadeOffAnimator.addListener(mAnimatorListener);
private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
sendUpdatePowerState();
}
};
3.如果不满足这两个条件,则调用mColorFadeOffAnimate.end()结束灭屏动画(无论是否执行动画),该方法会将动画结束值设置给相关的属性,也就是设置ColorFadeLevel为0,同时触发动画监听事件,如条件二所述,又会异步回调到animateScreenStateChange()方法。
综上所述,在power键灭屏时,在一般情况下和有灭屏动画时,会在第二次执行该方法时设置屏幕状态,如果执行mColorFadeEnable为false,则第一次执行时就会设置。
分析完灭屏后,再以亮屏为例进行下分析,当亮屏时,在该方法中执行如下这段代码:
if (target == Display.STATE_ON) {
//直接设置屏幕状态为Display.State_ON,如果返回false,则说明此时处于阻塞状态,Window中还没有回调,所以直接return
if (!setScreenState(Display.STATE_ON)) {
return; // screen on blocked
}
if (USE_COLOR_FADE_ON_ANIMATION && mColorFadeEnabled &&
mPowerRequest.isBrightOrDim()) {
// Perform screen on animation.
if (mPowerState.getColorFadeLevel() == 1.0f) {
mPowerState.dismissColorFade();
} else if (mPowerState.prepareColorFade(mContext,
mColorFadeFadesConfig ?
ColorFade.MODE_FADE :
ColorFade.MODE_WARM_UP)) {
mColorFadeOnAnimator.start();//开始执行亮屏动画
} else {
mColorFadeOnAnimator.end();//结束亮屏动画
}
} else {
//跳过动画,直接将ColorFadeLevel设置为1.0f
mPowerState.setColorFadeLevel(1.0f);
mPowerState.dismissColorFade();
}
}
在亮屏时,首先会通过setScreenState()设置好屏幕状态,设置完成之后,才会开始执行亮屏动画。至于亮屏设置背光值,则在后面的animateScreenBrightness()结束后。
3.1.1.亮屏动画和灭屏动画
现在分析完了animateScreenStateChange()方法,接下来在分析setScreenState()方法之前,我们先来看看关于设置亮屏、灭屏动画相关的逻辑,这里以灭屏时动画为例,在上面我们分析到了,如果有灭屏动画,则会先执行灭屏动画:
mColorFadeOffAnimator.start();
如果没有灭屏动画,则直接调用如下代码将ColorFadeLevel值设置为0:
mColorFadeOffAnimator.end();
无论是执行灭屏动画还是不执行灭屏动画,最终,ColorFadeLevel的值都会变为0,而当变为0时,动画结束,回调onAnimationEnd()方法,这在前面也分析过了,这里再次说明下:
@Override
public void onAnimationEnd(Animator animation) {
sendUpdatePowerState();
在onAnimationEnd()中,又会通过sendUpdatePowerState()再次调用updatePowerState().再进入animateScreenStateChange()后,将会更新屏幕状态。
除了回调onAnimationEnd()外,还会在DisplayPowerState.setColorFade()中调用:
public void setColorFadeLevel(float level) {
if (mColorFadeLevel != level) {
mColorFadeLevel = level;
//满足该条件,更新背光,这个逻辑说明如果是灭屏,则先在这里将背光设置为0
if (mScreenState != Display.STATE_OFF) {
mScreenReady = false;
scheduleScreenUpdate(); // update backlight brightness
}
if (mColorFadePrepared) {
mColorFadeReady = false;
scheduleColorFadeDraw();
}
}
}
在setColorFadeLevel()方法中,由于此时还没有设置屏幕状态值,所以State !=Display.STATE_OFF,因此进入该方法,通过scheduleScreenUpdate()方法更新背光值。
因此,对于灭屏,先设置其背光值为0,然后设置其屏幕状态为Display.STATE_OFF.
亮屏动画和灭屏动画类似,当结束后,也会回调onAnimationEnd()方法,再一次进入updatePowerState(),这里就不详细分析了。
4.setScreenState()
分析完了animateScreenStateChange()方法后,紧接着开始分析设置屏幕状态的方法——setScreenState().在这个方法中,会调用进入DisplayPoweState中,以及调用Window中的接口,来通知Window进行屏幕状态设置的一些工作,当WindowManager中处理完成后,又会回调DisplayPowerController中的方法。这个方法也是非常的庞大,重要逻辑已经添加注释,方法源码如下:
private boolean setScreenState(int state, boolean reportOnly) {
//是否要进行灭屏
final boolean isOff = (state == Display.STATE_OFF);
if (mPowerState.getScreenState() != state) {//如果当前屏幕状态和将要设置的状态不同,则进入
// If we are trying to turn screen off, give policy a chance to do something before we
// actually turn the screen off.
//灭屏且非PSensor灭屏
if (isOff && !mScreenOffBecauseOfProximity) {
//mReportedScreenStateToPolicy是一个报告屏幕状态的值,记录屏幕状态改变过程
//的状态值,在亮屏完成后,该值为REPORTED_TO_POLICY_SCREEN_ON
//在灭屏完成后,该值为REPORTED_TO_POLICY_SCREEN_OFF
if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON) {
//将方法参数设置为mReportedScreenStateToPolicy值
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_OFF);
//Window管理策略,在没有灭屏完成时,暂时阻塞屏幕灭屏
blockScreenOff();
//通知WindowManager开始灭屏
mWindowManagerPolicy.screenTurningOff(mPendingScreenOffUnblocker);
//取消灭屏阻塞
unblockScreenOff();
} else if (mPendingScreenOffUnblocker != null) {
// Abort doing the state change until screen off is unblocked.
return false;
}
}
if (!reportOnly) {
//将目标状态设置为屏幕状态,同时进入DisplayPowerState中的逻辑
mPowerState.setScreenState(state);
// Tell battery stats about the transition.
try {
mBatteryStats.noteScreenState(state);
} catch (RemoteException ex) {
// same process
}
}
}
// Tell the window manager policy when the screen is turned off or on unless it's due
// to the proximity sensor. We temporarily block turning the screen on until the
// window manager is ready by leaving a black surface covering the screen.
// This surface is essentially the final state of the color fade animation and
// it is only removed once the window manager tells us that the activity has
// finished drawing underneath.
//如果是灭屏且非PSensor灭屏,且屏幕状态报告值为REPORTED_TO_POLICY_SCREEN_OFF,
//进入该if当中
//在按power键灭屏,都会进入该if语句中,当PSensor灭屏后,再按power键,也会进入这个语句
//中,执行灭屏
if (isOff && mReportedScreenStateToPolicy != REPORTED_TO_POLICY_SCREEN_OFF
&& !mScreenOffBecauseOfProximity) {
//设置报告屏幕状态的值
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF);
unblockScreenOn();
//表示Window屏幕完成
mWindowManagerPolicy.screenTurnedOff();
//这种情况说明已经灭屏但是用户改变了(又打算亮屏),这时也应该走完灭屏的流程
} else if (!isOff
&& mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_OFF) {
// We told policy already that screen was turning off, but now we changed our minds.
// Complete the full state transition on -> turningOff -> off.
unblockScreenOff();
mWindowManagerPolicy.screenTurnedOff();
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF);
}
//如果不是灭屏&&屏幕报告值为灭屏(上次是灭屏),则这次为亮屏
if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_ON);
if (mPowerState.getColorFadeLevel() == 0.0f) {
//如果colorFadeLevel为0,说明还没有执行亮屏动画,又由于亮屏动画值设置亮屏状态成
//功后才开始,所以说明这时mPowerState.setScreenState()设置屏幕状态没有完成,需要暂
//时进行阻塞
blockScreenOn();
} else {//亮屏动画已经完成,所以state=Display.STATE_ON也已设置完成,解除阻塞
unblockScreenOn();
}
//调用WindowManager进行亮屏操作
mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);
// Return true if the screen isn't blocked.
//根据返回值来决定是否阻塞
return mPendingScreenOnUnblocker == null;
}
在这个方法中,mReportedScreenStateToPolicy是一个用来表示报告屏幕状态的全局变量,在灭屏或者亮屏时,每当进行到某一步,会将该值设置成对应的值,如果灭屏完成,则设置为0,亮屏完成设置为2.共有四个值:
private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0;//灭屏完成
private static final int REPORTED_TO_POLICY_SCREEN_TURNING_ON = 1;//正在进行亮屏
private static final int REPORTED_TO_POLICY_SCREEN_ON = 2;//亮屏完成
private static final int REPORTED_TO_POLICY_SCREEN_TURNING_OFF = 3;//正在进行灭屏
在这个方法中,首先会判断是否要设置的是灭屏状态且非PSensor灭屏,如果满足条件则会进入if语句中,首先调用 WindManagerPolicy.screenTurningOff()方法,表示让WindowManager中开始灭屏,同时该方法传入的参数是一个WindowManagerPolicy.ScreenOffListener的一个实例,当WindowManagerPolicy中处理完毕后,会通过该接口实例回调到DisplayPowerController中。
接下来,会将state值设置给DisplayPowerState中,关于DisplayPowerState.setState()中的逻辑我们稍后再进行分析,因此不管是何种屏幕状态,都会将状态值设到DisplayPowerState中,对于非PSensor灭屏来说,仅仅是多了一步通知Window开始灭屏的步骤(也就是说,对于PSensor亮灭屏,不会有Window中的处理)。
当屏幕状态值设置后,进入第二个if语句中。对于正常的灭屏流程,肯定会执行进入第二个if中,在这个if中,调用WindowManagerPolicy.screenTurnedOff()方法,给WindowManager通知在DisplayPowerController中的灭屏流程已经结束了,让WindowManager进行收尾工作。所以对于灭屏流程肯定会先后执行WindowManager的screenTurningOff()和screenTurnedOff().
还有一种情况就是,通过PSensor灭屏后,再次点击power键,也会执行第二个if语句流程(因为是GotoSleep嘛)。
接下来,如果isOff为false,说明不是灭屏的流程,此时如果报告屏幕状态的值为灭屏,则会进入最后一个else中,执行亮屏流程,调用WindowManager的screenTurningOn()方法。当然,最终还会在updatePowerState()的结尾处执行一个screenTurnedOn()方法,说明亮屏流程完全完成了。
当以上执行完毕后,根据mPendingScreenOnUnblocker对象是否为空返回true或false,除了屏幕状态设置灭屏外,该方法返回值用于标记屏幕状态是否设置成功,如果返回为false,则将会暂时中断屏幕状态设置时setScreenState()之后的流程。这里举个例子,如在animateScreenStateChange()方法中亮屏时:
if (!setScreenState(Display.STATE_ON)) {
return; // screen on blocked
}
4.1.block()方法和unblock()方法
现在来看看mPendingScreenOnUnblocker对象的控制方法,我们看到在setScreenState()中调用了多次block和unblock的方法,因此接下来我们要开始分析下blockScreen()和unBlockScreenOn()了。
在DisplayPowerController中共有两对block/unblock方法:
blockScreenOn():暂时阻塞DisplayPowerController中进行亮屏的流程;
unBlockScreenOn():取消亮屏阻塞;
blockScreenOff():暂时阻塞DisplayPowerController中的灭屏流程;
unBlockScreeOff():取消灭屏阻塞。
由于在亮屏时,WindowManager中需要进行亮屏相关操作,如果在Window没有处理完成就先亮屏,用户体验不好,因此,在没有会通过blockScreenOn()来阻塞亮屏过程,那么是如何阻塞的呢?我们先看看该方法:
private void blockScreenOn() {
if (mPendingScreenOnUnblocker == null) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
mPendingScreenOnUnblocker = new ScreenOnUnblocker();
mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
}
}
在该方法中,实例化了一个ScreenOnUnblocker类实例,在上面也说过,该类是WindowManagerPolicy.ScreenOnListener的一个子类;然后获取了当前系统时间。
在这里获取的这个mPendingScreenOnUnblocker对象,是不是很眼熟?没错,他就是设置setScreenState()方法返回值时用到的。现在回过头来再看看animateScreenStateChange()方法中设置亮屏时的逻辑:
if (target == Display.STATE_ON) {
//如果返回值为false,则返回,不再执行剩余流程
if (!setScreenState(Display.STATE_ON)) {
return; // screen on blocked
}
if (USE_COLOR_FADE_ON_ANIMATION && mColorFadeEnabled && mPowerRequest.isBrightOrDim()) {
// 亮屏动画
} else {
// Skip screen on animation.
mPowerState.setColorFadeLevel(1.0f);
mPowerState.dismissColorFade();
}
如果setScreenState(Display.STATE_ON)返回值为false,也就是mPendingScreenOnUnblocker != null,说明此时WindowManager中没有处理完成,为避免DisplayController中在没有处理完成的情况下先亮,所以临时阻塞流程。
那么什么时候不阻塞呢?当Window中绘制完成后,将会回调ScreenOnUnblocker类的onScreenOn()方法,方法如下:
private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {
@Override
public void onScreenOn() {
Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKED, this);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
在这个方法中,通过Handler异步执行消息,最调用unblockScreenOn()方法,在unblockScreenOn()方法中:
private void unblockScreenOn() {
if (mPendingScreenOnUnblocker != null) {
mPendingScreenOnUnblocker = null;
long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
}
}
可以看到置空了mPendingScreenOnUnblocker对象,说明取消阻塞,因此再次进入setScreenState(Display.STATE_ON)流程后,由于没有阻塞,从而执行剩余流程。
同样地,blockScreenOff()和unblcokScreenOff()方法也类似,会在灭屏时进行阻塞。
分析完setScreenState()方法后,这里结合animateScreenStateChange()和setScreenState()方法进行一个总结:
对于灭屏(STATE_OFF),首先是设置背光值为0,然后设置屏幕状态,其代码逻辑为:先setColorFadeLevel(0.0f),再setState(Display.STATE_OFF);
对于亮屏(STATE_ON)状态,首先是设置屏幕状态值,然后才会设置背光值,其代码逻辑为:先setState(Display.STATE_ON),再setColorFadeLevel(1.0)。
5.DisplayPowerState.setScreenState()
开始分析下一个方法——在分析setScreenState()方法时,还剩余一个具体设置屏幕状态的方法:
if (!reportOnly) {
mPowerState.setScreenState(state);
// Tell battery stats about the transition.
......
}
}
现在我们开始分析DisplayPowerState中的setScreenState()方法,看看它是如何设置屏幕状态的。直接进入DisplayPowerState中看该方法,其源码如下:
/**
* Sets whether the screen is on, off, or dozing.
*/
public void setScreenState(int state) {
if (mScreenState != state) {
mScreenState = state;
mScreenReady = false;
scheduleScreenUpdate();
}
}
最终,在这个方法中将state设置给了mScreenState,然后执行了一个scheduleScreenUpdate()方法:
private void scheduleScreenUpdate() {
if (!mScreenUpdatePending) {
mScreenUpdatePending = true;
postScreenUpdateThreadSafe();
}
}
在这个方法中又调用了postScreenUpdateThreadSafe(),该方法如下:
private void postScreenUpdateThreadSafe() {
mHandler.removeCallbacks(mScreenUpdateRunnable);
mHandler.post(mScreenUpdateRunnable);
}
最终,会在这个方法中通过Handler.post(mScreenUpdateRunnable)进行了处理。这个mScreenUpdateRunnable非常重要,可以测试下如果注释掉它,那么亮屏、灭屏都会失效。好了,现在直接看mScreenUpdateRunnable这个Runnable,其中必要说明已进行了注释:
private final Runnable mScreenUpdateRunnable = new Runnable() {
@Override
public void run() {
//表示是否打算更新屏幕状态,该值在scheduleScreenUpdate()方法中设置为了true
mScreenUpdatePending = false;
//获取背光亮度值,如果屏幕状态为State_Off的话就是0,其他屏幕状态下都是设置的背光值
int brightness = mScreenState != Display.STATE_OFF
&& mColorFadeLevel > 0f ? mScreenBrightness : 0;
//如果该方法返回false,表示屏幕更新完成,否则表示还没有更新完成
if (mPhotonicModulator.setState(mScreenState, brightness)) {
if (DEBUG) {
Slog.d(TAG, "Screen ready");
}
mScreenReady = true;//标记屏幕状态是否更新完成
invokeCleanListenerIfNeeded();
} else {
if (DEBUG) {
Slog.d(TAG, "Screen not ready");
}
}
}
};
在这个方法中,首先得到背光亮度值brightness,之后将背光亮度值和屏幕状态值传入了mPhotonicModulator.setState()中,并且根据这个方法的返回值来决定是否是屏幕状态更新完成(这里的屏幕状态更新完成是根据方法名直译的,可以理解为屏幕状态是否和其他模块中完成同步,在DisplayPowerState中State已经设置了新的值了)。那么就来看看这个mPhotonicModulator.setState()了。
PhotonicModulator是一个Thread的子类,专门用于更新屏幕和背光亮度值的状态,因此,在DisplayPowerState中,更新屏幕和背光状态是在独立的线程中异步进行的。
现在,先来看看这个线程的setScreen()方法:
public boolean setState(int state, int backlight) {
synchronized (mLock) {
//屏幕状态是否改变,和之前的值做比较
boolean stateChanged = state != mPendingState;
//背光是否改变
boolean backlightChanged = backlight != mPendingBacklight;
//如果有其中之一改变,进入if中
if (stateChanged || backlightChanged) {
if (DEBUG) {
Slog.d(TAG, "Requesting new screen state: state="
+ Display.stateToString(state) + ", backlight=" + backlight);
}
//设置state值
mPendingState = state;
mPendingBacklight = backlight;
//mStateChangeInProgress和mBacklightChangeInProgress分别表示当前屏幕状态和背光值
//正在更新的过程中,changeInProgress表示其中之一是否正在更新的过程中
boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
mStateChangeInProgress = stateChanged || mStateChangeInProgress;
mBacklightChangeInProgress = backlightChanged || mBacklightChangeInProgress;
//如果为false,则唤醒mPhotonicModulator线程,执行它的run()方法
if (!changeInProgress) {
mLock.notifyAll();
}
}
//如果该值为true,说明此时正在进行屏幕状态的改变,没有准备好。因此返回false,反之
return !mStateChangeInProgress;
}
}
这个方法中的逻辑容易理解,其中对mLock.notifyAll()这个逻辑再进行下分析,为何当changeInProgress为false的时候需要mLock.notifyAll()呢?这是因为该线程启动后就是一个死循环,可以无线执行,但在死循环中进行了mLock.wait()操作,这里看看它的run()方法,如下:
@Override
public void run() {
for (;;) {
// Get pending change.
final int state;
final boolean stateChanged;
final int backlight;
final boolean backlightChanged;
synchronized (mLock) {
//通过全局变量给局部变量赋值
state = mPendingState;
//mActualState表示目前实际的状态值
stateChanged = (state != mActualState);
backlight = mPendingBacklight;
//mActualBacklight表示目前实际的亮度值
backlightChanged = (backlight != mActualBacklight);
//stateChange为false表示此时屏幕状态已应用为需要设置的值了(已应用),则再次执行一遍
//postScreenUpdateThreadSafe()方法,这次执行时,PhotonicMudulator.setScreen()将返回
//true,表示屏幕更新完成
//-----------------------------------------------------BEG
if (!stateChanged) {
// State changed applied, notify outer class.
postScreenUpdateThreadSafe();
mStateChangeInProgress = false;//表示更新屏幕已完成
}
//说明背光值也已经应用
if (!backlightChanged) {
//置为false,表示更新背光已完成,没有正在进行的改变操作
mBacklightChangeInProgress = false;
}
//如果屏幕状态和背光值都应用完成,则让该线程进入等待状态
if (!stateChanged && !backlightChanged) {
try {
mLock.wait();
} catch (InterruptedException ex) { }
continue;
}
//-----------------------------------------------------END
//设置实际状态值和背光值
mActualState = state;
mActualBacklight = backlight;
}
// Apply pending change.
if (DEBUG) {
Slog.d(TAG, "Updating screen state: state="
+ Display.stateToString(state) + ", backlight=" + backlight);
}
//调用DisplayBlanker中去请求Display
mBlanker.requestDisplayState(state, backlight);
}
}
在run()方法中,注意我用BEG-END标注的这段,如果在进行状态更新时第一次进入该方法,它肯定不会执行,因为在这段之后才做了mActualState=state等操作,因此,只有在屏幕状态和背光值状态都更新后(应该是在第二次进入后),就会执行到这段代码,从而使得线程进入wait状态。
在这个方法的最后一部分逻辑中,在将mActualState和mActualBacklight赋值之后,调用了mBlanker.requestDisplayState()方法,这个方法非常重要,它直接向DisplayManagerService去请求屏幕状态和亮度值.
Q: screen not ready是指屏幕状态没有设置完成还是屏幕状态+亮度值没有设置完成?
A:在正确流程下,只要state设置后,就会反映出screen ready。
以上DisplayPowerController中的逻辑就到这里结束了,按照流程,我们接下来要分析DisplayBlanker中的相关逻辑了,但由于它是在子线程中进行的,所以我们暂且先不分析DisplayBlanker以及之后的逻辑,而是先看看updatePowerState()方法中剩余的逻辑。
在updatePowerState()中,当执行完毕animateScreenState()后,屏幕状态就设置完成了(如果是灭屏,亮度也已被设置为0),接下来将负责获取亮度值。由于系统中不同场景有不用的亮度值,比如,在用户设置的亮度值、自动调节亮度(LSensor)获取的亮度值、低电量时的亮度值、Dim状态时的亮度值…在这里会做出一个判断具体使用哪个亮度值。这部分代码这里就不贴了,详细的解释已经进行了注释。
当完成亮度值的获取后,开始设置亮度值的设置流程。
6.animateScreenBrightness()
设置背光值用到了animateScreenBrightness()这个方法,这里我们再来看看updatePowerState()中是如何调用该方法的:
if ((state == Display.STATE_ON
&& mSkipRampState == RAMP_STATE_SKIP_NONE
|| state == Display.STATE_DOZE && !mBrightnessBucketsInDozeConfig)
&& !wasOrWillBeInVr) {
//设置亮度坡度变化,slowChange=true仅应用于自动调节亮度,其他条件时为false
animateScreenBrightness(brightness,
slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
} else {
//其他情况下不使用亮度坡度值,一次性设置为最终亮度值
animateScreenBrightness(brightness, 0);
}
在这里,如果是state=Display.STATE_ON,说明此时屏幕状态为亮屏,如满足其他条件,则进入if语句中,给animateScreenBrightness()第二个设置参数为一个大于0的固定值,否则,直接给animateScreenBrightness()第二个参数设置为0。这个参数有何作用呢?先来看该方法代码:
private void animateScreenBrightness(int target, int rate) {
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
Trace.traceCounter(Trace.TRACE_TAG_POWER, "TargetScreenBrightness", target);
try {
mBatteryStats.noteScreenBrightness(target);
} catch (RemoteException ex) {
// same process
}
}
}
在这个方法中,只有调用了一个对象的animateTo()方法,并将其参数传给了animateTo(),其他什么也没有做。在这个方法中,第一个参数是updatePowerState()中获得的最终亮度值,第二个参数则和亮度设置时的动画效果有关系,如果设置为大于0的数,那么会在animateTo()方法中根据这个数逐渐地设置亮度,如果设置为小于等于0,那么则不会有动画效果,直接将亮度值一次性设置。接下来,说说亮度值设置时的动画相关的逻辑。
7.RampAnimator.animateTo()
继续跟着上一段分析,mScreenBrightnessRampAnimator是一个RampAnimator对象,RampAnimator类是一个自定义动画类,专门用于更新亮度,其原理是该类中有一个IntProperty对象作为该类的一个属性:
public RampAnimator(T object, IntProperty
mObject = object;
mProperty = property;
mChoreographer = Choreographer.getInstance();
}
当调用animateTo()时,会调用IntProperty
public boolean animateTo(int target, int rate) {
// Immediately jump to the target the first time.
//如果rate>=0,则直接通过mProperty.setValue(mObject, target)设置为目标亮度
if (mFirstTime || rate <= 0) {
if (mFirstTime || target != mCurrentValue) {
mFirstTime = false;
mRate = 0;
mTargetValue = target;
mCurrentValue = target;
//rate<=0时直接设置
mProperty.setValue(mObject, target);
if (mAnimating) {
mAnimating = false;
cancelAnimationCallback();
}
if (mListener != null) {
mListener.onAnimationEnd();
}
return true;
}
return false;
}
if (!mAnimating
|| rate > mRate
|| (target <= mCurrentValue && mCurrentValue <= mTargetValue)
|| (mTargetValue <= mCurrentValue && mCurrentValue <= target)) {
mRate = rate;
}
final boolean changed = (mTargetValue != target);
mTargetValue = target;
//通过动画设置为目标亮度
// Start animating.
if (!mAnimating && target != mCurrentValue) {
mAnimating = true;
mAnimatedValue = mCurrentValue;
mLastFrameTimeNanos = System.nanoTime();
postAnimationCallback();
}
return changed;
}
这个方法中可以看到,根据传入的第二个参数rate,如果rate<=0,那么直接调用mProperty.setValue(object,target)设置最终的亮度;如果rate>0,那么会进入postAnimationCallback()方法,在这个方法中通过rate计算出每次设置的亮度值进行设置,直到设置到最终亮度为止。
对于postAnimationCallback()方法的代码就不详细说明了。当调用mProperty.setValue(object,target)后,接下来的步骤是哪个呢?我们从该动画对象实例化时就可以知道,其实例化代码如下:
mScreenBrightnessRampAnimator = new RampAnimator
mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
因此当执行mProperty.setValue(object,target)时,执行的是DisplayPowerState.SCREEN_BRIGHTNESS的setValue()方法,进入DisplayPowerState中查看该对象:
public static final IntProperty
new IntProperty
@Override
public void setValue(DisplayPowerState object, int value) {
//设置亮度
object.setScreenBrightness(value);
}
@Override
public Integer get(DisplayPowerState object) {
return object.getScreenBrightness();
}
};
在这里可以看出,当调用setValue()方法后,将调用object.setScreenBrightness(),从实例化流程可知,object对象还是DisplayPowerState对象。继续setScreenBrightness()方法:
public void setScreenBrightness(int brightness) {
if (mScreenBrightness != brightness) {
mScreenBrightness = brightness;
//对于屏幕状态为State_OFF,根据上面内容的分析,在设置屏幕状态之间就会设置将背光设置为0,此处不进行处理
if (mScreenState != Display.STATE_OFF) {
mScreenReady = false;
scheduleScreenUpdate();
}
}
}
在这个方法中,如果当前屏幕状态不为STATE_OFF,即当前不是处于灭屏状态,则开始调用scheduleScreenUpdate()更新背光,这个方法我们在前面已经分析了,可以查看5小节的分析,最终通过DisplayBlanker.requestPowerState()请求设置到新的亮度值。
还有一点需要注意的是,在setScreenBrightness()方法中,对(mScreenState != Display.STATE_OFF)进行了判断,这是因为我们之前分析过,对于灭屏来说,当设置完ColorFadeLevel值为0后,就开始设置背光了,背光设置为0后才会设置屏幕状态为STATE_OFF,因此是不走这个流程的。而其他状态如亮屏,则是先设置背光,后设置屏幕状态为STATE_ON。
8.ready、finish变量决策收尾工作
现在回到updatePowerState()中,当执行完animateScreenBright()后,接下来的逻辑主要是判断屏幕状态和背光值设置是否成功,这里有两个boolean变量:ready和finish分别表示屏幕状态是否设置成功和屏幕状态、亮度值都设置成功,为了易于理解,这里再复制一下相关代码:
//ready表示屏幕状态是否准备完成,mPendingScreenOnUnblocker用于亮屏过程中,
//该值非空表示屏幕目前被阻塞,等待WindowManager回调,回调后将被置为null
//mColorFadeOnAnimator,mColorFadeOffAnimator表示亮屏和灭屏动画
final boolean ready = mPendingScreenOnUnblocker == null &&
(!mColorFadeEnabled ||
(!mColorFadeOnAnimator.isStarted() && !mColorFadeOffAnimator.isStarted()))
&& mPowerState.waitUntilClean(mCleanListener);
//表示屏幕状态准备完成,同时亮度设置也完成
final boolean finished = ready
&& !mScreenBrightnessRampAnimator.isAnimating();
// Notify policy about screen turned on.
//通知Windows进行亮屏处理亮屏
if (ready && state != Display.STATE_OFF
&& mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_ON) {
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_ON);
//通知WindowManager亮屏完成
mWindowManagerPolicy.screenTurnedOn();
}
//如果未完成,需要申请一个Display锁
if (!finished && !mUnfinishedBusiness) {
//申请Display锁
mCallbacks.acquireSuspendBlocker();
mUnfinishedBusiness = true;
}
// Notify the power manager when ready.
//当屏幕准备就绪,通知PMS
if (ready && mustNotify) {
synchronized (mLock) {
if (!mPendingRequestChangedLocked) {
//表示屏幕状态准备就绪,就绪和亮度设置完成无关,只和屏幕状态有关
mDisplayReadyLocked = true;
}
}
//在该方法中回调PMS方法
sendOnStateChangedWithWakelock();
}
// Release the wake lock when we have no unfinished business.
//完成后释放Display锁
if (finished && mUnfinishedBusiness) {
mUnfinishedBusiness = false;
mCallbacks.releaseSuspendBlocker();
}
}
详细说明见注释,从以上代码中看出,当屏幕状态设置完成后,ready为true,因此将mDisplayReadyLock值置为true,然后调用sendOnStateChangedWithWakelock()方法,在这个方法中会通知PMS:Display已经更新完成啦!sendOnStateChangedWithWakelock()方法如下:
private void sendOnStateChangedWithWakelock() {
mCallbacks.acquireSuspendBlocker();
mHandler.post(mOnStateChangedRunnable);
}
private final Runnable mOnStateChangedRunnable = new Runnable() {
@Override
public void run() {
mCallbacks.onStateChanged();//回调PMS中的该方法
mCallbacks.releaseSuspendBlocker();//回调PMS中的该方法,释放Display锁
}
};
在PMS中,onStateChange()方法如下:
@Override
public void onStateChanged() {
synchronized (mLock) {
mDirty |= DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED;
updatePowerStateLocked();
}
}
从而使PMS中通过updatePowerStateLocked()方法重新请求状态。
至此,整个updatePowerState()方法以纵向的形式分析完毕了。在分析进入animateScreenStateChange()、DisplayPowerState.setScreenState()时,在DisplayBlanker.requestPowerState()时停止了,因为这是个异步的操作。接下来我们从这里出发,探究一下屏幕状态和背光最后是如何设置的以及设置到哪里去了。
9.DisplayBlanker.requestPowerState()
DisplayBlanker是一个接口,并且只有一个方法,它专门用来更新实际的屏幕显示状态.在DisplayPowerController中,DisplayBlanker由DisplayManagerService在实例化DisplayPowerController时作为参数传入,DisplayPowerController中在实例化DisplayPowerState时又通过构造函数传给了DisplayPowerState,因此,DisplayBlanker的实现还是在DMS中,我们进入DMS中看DisplayBlanker对象:
public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
SensorManager sensorManager) {
synchronized (mSyncRoot) {
DisplayBlanker blanker = new DisplayBlanker() {
@Override
public void requestDisplayState(int state, int brightness) {
// The order of operations is important for legacy reasons.
//对于灭屏和非灭屏状态,调用callback的顺序不同
if (state == Display.STATE_OFF) {
requestGlobalDisplayStateInternal(state, brightness);
}
//PMS中调用native层方法
callbacks.onDisplayStateChange(state);
if (state != Display.STATE_OFF) {
requestGlobalDisplayStateInternal(state, brightness);
}
}
};
mDisplayPowerController = new DisplayPowerController(
mContext, callbacks, handler, sensorManager, blanker);
}
}
在通过匿名类实例化DisplayBlanker时,重写了requestDisplayState()方法,在这个方法中,callback.OnDisplayStateChange()方法将会回调到PowerManagerService中,用来调用native层方法,从这里可以看到,对于灭屏和其他流程,调用的顺序不同,,如果是灭屏,则会先设置灭屏,再回调PowerManagerService中的onDisplayStateChange()方法,如果是其他操作如亮屏,则会先调用onDisplayStateChange(),然后再调用设置亮屏。我们先进入PMS中看看该方法:
@Override
public void onDisplayStateChange(int state) {
// This method is only needed to support legacy display blanking behavior
// where the display's power state is coupled to suspend or to the power HAL.
// The order of operations matters here.
synchronized (mLock) {
if (mDisplayState != state) {
mDisplayState = state;
if (state == Display.STATE_OFF) {
//该配置值表示是否将交互模式与显示状态分离
if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
//调用native层方法,设置交互模式为false
setHalInteractiveModeLocked(false);
}
//该配置值表示将自动挂起模式与显示状态分离
if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
//调用native层方法,设置自动挂起模式为true
setHalAutoSuspendModeLocked(true);
}
} else {
if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(false);
}
if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
setHalInteractiveModeLocked(true);
}
}
}
}
}
在上述方法中,调用native层代码进入到了libsuspend中,其中的两个配置值表示是否和Display进行解耦,如果设置为true,则不会调用native方法,默认为false,表示Suspend和Display显示不进行解耦。
回到DisplayBlanker.requestDisplayState()方法中,接下来看看requestGlobalDisplayStateInternal()方法:
private void requestGlobalDisplayStateInternal(int state, int brightness) {
//判断状态和亮度
if (state == Display.STATE_UNKNOWN) {
state = Display.STATE_ON;
}
if (state == Display.STATE_OFF) {
brightness = PowerManager.BRIGHTNESS_OFF;
} else if (brightness < 0) {
brightness = PowerManager.BRIGHTNESS_DEFAULT;
} else if (brightness > PowerManager.BRIGHTNESS_ON) {
brightness = PowerManager.BRIGHTNESS_ON;
}
//mTempDisplayStateWorkQueue是一个ArrayList
//作临时列表。仅由requestDisplayState使用
synchronized (mTempDisplayStateWorkQueue) {
try {
// 在mSyncRoot锁内更新屏幕显示状态和亮度
// mGlobalDisplayState表示全局Display状态,即最终的状态
synchronized (mSyncRoot) {
if (mGlobalDisplayState == state
&& mGlobalDisplayBrightness == brightness) {
return; // no change
}
//给代表全局屏幕状态和亮度的变量赋值
mGlobalDisplayState = state;
mGlobalDisplayBrightness = brightness;
// 下一步操作
applyGlobalDisplayStateLocked(mTempDisplayStateWorkQueue);
}
//由于设置屏幕状态需要几百毫秒,因此推迟了工作中最昂贵的部分,直到退出临界部分
//以避免长时间阻塞其他线程。
for (int i = 0; i < mTempDisplayStateWorkQueue.size(); i++) {
mTempDisplayStateWorkQueue.get(i).run();
}
} finally {
mTempDisplayStateWorkQueue.clear();//清空列表
}
}
}
在这个方法中,设置了mGlobalDisplayState和mGlobalDisplayBrightness,这两个全局变量表示整体的显示状态和亮度,然后将这两值传给了下一个方法applyGlobalDisplayStateLocked(),继续分析该方法:
private void applyGlobalDisplayStateLocked(List
//获取显示设备
final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) {
DisplayDevice device = mDisplayDevices.get(i);
//遍历每个显示设备,并更新显示状态
Runnable runnable = updateDisplayStateLocked(device);
if (runnable != null) {
workQueue.add(runnable);
}
}
}
在这个方法中,首先会遍历mDisplayDevices,它是表示当前所有显示设备的集合,然后更新每一个显示设备.什么是显示设备呢?目前有三种DisplayDevice:
1.LocalDisplayDevice:手机屏幕就是一个显示设备;
2.WifiDisplayDevice:无线投射,通过wifi将屏幕投射到其他物理屏幕上如TV上.
3.VirtualDisplayDevice:虚拟设备
这里我们暂且不管WifiDisplayDevice和VirtualDisplayDevice,先看看LocalDisplayDevice。
现在进行下一个方法的分析,看看updateDisplayStateLocked()方法:
private Runnable updateDisplayStateLocked(DisplayDevice device) {
//获取对应显示设备的信息类
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
return device.requestDisplayStateLocked(mGlobalDisplayState, mGlobalDisplayBrightness);
}
return null;
}
在这个方法中,首先根据DisplayDevice对象的getDisplayDeviceInfoLocked()方法获取了DisplayDeviceInfo对象,然后根据DisplayDeviceInfo的flag进行决策,调用下一个方法并返回。DisplayDeviceInfo用于描述显示的物理设备特征,如尺寸、分别率等。
接下来调用了DisplayDevice的requsetDisplayStateLocked()方法,因此我们直接看LocalDisplayDevice中的该方法:
@Override
public Runnable requestDisplayStateLocked(final int state, final int brightness) {
// Assume that the brightness is off if the display is being turned off.
assert state != Display.STATE_OFF || brightness == PowerManager.BRIGHTNESS_OFF;
final boolean stateChanged = (mState != state);
final boolean brightnessChanged = (mBrightness != brightness) && mBacklight != null;
if (stateChanged || brightnessChanged) {
final int displayId = mBuiltInDisplayId;
final IBinder token = getDisplayTokenLocked();
final int oldState = mState;
if (stateChanged) {
mState = state;
updateDeviceInfoLocked();
}
if (brightnessChanged) {
mBrightness = brightness;
}
// Defer actually setting the display state until after we have exited
// the critical section since it can take hundreds of milliseconds
// to complete.
//返回该Runnable
return new Runnable() {
@Override
public void run() {
// Exit a suspended state before making any changes.
int currentState = oldState;
if (Display.isSuspendedState(oldState)
|| oldState == Display.STATE_UNKNOWN) {
if (!Display.isSuspendedState(state)) {
setDisplayState(state);
currentState = state;
} else if (state == Display.STATE_DOZE_SUSPEND
|| oldState == Display.STATE_DOZE_SUSPEND) {
setDisplayState(Display.STATE_DOZE);
currentState = Display.STATE_DOZE;
} else {
return; // old state and new state is off
}
}
// If the state change was from or to VR, then we need to tell the light
// so that it can apply appropriate VR brightness settings. Also, update the
// brightness so the state is propogated to light.
boolean vrModeChange = false;
if ((state == Display.STATE_VR || currentState == Display.STATE_VR) &&
currentState != state) {
setVrMode(state == Display.STATE_VR);
vrModeChange = true;
}
// Apply brightness changes given that we are in a non-suspended state.
if (brightnessChanged || vrModeChange) {
setDisplayBrightness(brightness);
}
// Enter the final desired state, possibly suspended.
if (state != currentState) {
setDisplayState(state);
}
}
private void setVrMode(boolean isVrEnabled) {
mBacklight.setVrMode(isVrEnabled);
}
//设置屏幕状态
private void setDisplayState(int state) {
try {
final int mode = getPowerModeForState(state);
SurfaceControl.setDisplayPowerMode(token, mode);
} finally {
}
}
//设置背光
private void setDisplayBrightness(int brightness) {
try {
mBacklight.setBrightness(brightness);
} finally {
}
}
};
}
return null;
}
最终会在这个方法中设置好屏幕状态和亮度值。
关于后面这一块分析的不是很详细,但这其中涉及到Display中比较多的内容,因此这里仅仅将涉及到亮灭屏过程的部分进行了分析。
以上就是DisplayPowerController中涉及到的亮灭屏流程。灭屏和亮屏时序图如下:
灭屏时序图: