1.2.updatePowerStateLocked方法详解
接着上文分析,在systemReady()方法的最后,调用了updatePowerStateLocked()方法:
public void systemReady(IAppOpsService appOps) {synchronized (mLock) {
mSystemReady = true;
........
mDirty |= DIRTY_BATTERY_STATE;
updatePowerStateLocked();
}
updatePowerStateLocked()方法是整个PMS中的核心方法,也是整个PMS中最重要的一个方法,在执行完申请锁,释放锁,用户事件,强制唤醒/睡眠等操作都需要调用它,用来更新整个电源状态的改变,并进行重新计算。PMS中使用一个int值mDirty作为标志位判断电源状态是否发生变化,当电源状态发生改变时,如亮灭屏、电池状态改变、暗屏…都会调用该方法,在该方法中调用了其他同级方法进行更新,下面逐个进行分析,先看其代码:
private void updatePowerStateLocked() {
if (!mSystemReady || mDirty == 0) {
return;
} try { // Phase 0: Basic state updates.
//更新电池信息
updateIsPoweredLocked(mDirty); //更新屏幕保持唤醒标识值mStayOn
updateStayOnLocked(mDirty); //亮度增强相关
updateScreenBrightnessBoostLocked(mDirty);
final long now = SystemClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0; //更新统计wakelock的标记值mWakeLockSummary
updateWakeLockSummaryLocked(dirtyPhase1);//更新统计userActivity的标记值mUserActivitySummary和休眠到达时间
updateUserActivitySummaryLocked(now, dirtyPhase1);
//用来更新屏幕唤醒状态,状态改变返回true
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
// Phase 2: Update display power state.
//和Display交互,请求Display状态
boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2); // Phase 3: Update dream state (depends on display ready signal).
//更新屏保
updateDreamLocked(dirtyPhase2, displayBecameReady); // Phase 4: Send notifications, if needed.
//如果wakefulness改变,做最后的收尾工作
finishWakefulnessChangeIfNeededLocked(); // Phase 5: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make
//surewe finished everything else first!
//更新Suspend锁
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
在整个方法中,当系统没有准备就绪或者mDirty没有进行置位时,不会执行后续步骤,直接return;接下来对该方法中的内容进行分析,由于此方法非常重要,因此这里将所有的方法都贴出来。
1.2.1.updateIsPoweredLocker()
这个方法主要功能有两个:
1.USB插播亮屏入口点;
2.更新低电量模式;
该方法如下:
/**
* Updates the value of mIsPowered.
* Sets DIRTY_IS_POWERED if a change occurred.
*/
private void updateIsPoweredLocked(int dirty) {
if ((dirty & DIRTY_BATTERY_STATE) != 0) {
//是否充电
final boolean wasPowered = mIsPowered;
final int oldPlugType = mPlugType;//充电类型
final boolean oldLevelLow = mBatteryLevelLow;
//是否处于低电量/*---------------------BatteryService交互Begin-----------------------------*/
mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
mPlugType = mBatteryManagerInternal.getPlugType();
mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();
/*---------------------BatteryService交互 End-----------------------------*///充电状态改变
if (wasPowered != mIsPowered || oldPlugType != mPlugType) {
mDirty |= DIRTY_IS_POWERED; //是否连接无线充电
final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
mIsPowered, mPlugType, mBatteryLevel);
final long now = SystemClock.uptimeMillis();
//插拔充电线是否唤醒屏幕
if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered,
oldPlugType, dockedOnWirelessCharger)) { //屏幕唤醒
wakeUpNoUpdateLocked(now,
"android.server.power:POWER", Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
} //更新用户活动
userActivityNoUpdateLocked(
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0,
Process.SYSTEM_UID);
if (dockedOnWirelessCharger) {
mNotifier.onWirelessChargingStarted();
}
}//上次是否充电和当前是否充电不同||上次电量是否处于低电量和当前是否处于//低电量不同
if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) { //上次处于低电量&&当前不处于低电量
if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) { //当电池处于低电量模式触发值时,用户是否关闭了低电量模式
mAutoLowPowerModeSnoozing = false;
} //更新低电量模式
updateLowPowerModeLocked();
}
}
}
1.2.2.updateStayOnLocked()
这个方法主要用于判断系统是否在Settings中设置了充电时保持屏幕亮屏后,根据是否充电来决定亮屏与否。方法如下:
private void updateStayOnLocked(int dirty) {
if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) {
final boolean wasStayOn = mStayOn; //充电时亮屏&&DevicePolicyManager中未设置最大关闭时间
if (mStayOnWhilePluggedInSetting != 0 &&
!isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) { //保持亮屏取决于是否充电
mStayOn =
mBatteryManagerInternal.isPowered(mStayOnWhilePluggedInSetting);
} else {
mStayOn = false;
} if (mStayOn != wasStayOn) { //如果mStayOn值改变,mDirty置位
mDirty |= DIRTY_STAY_ON;
}
}
}
在该方法中,用bool值mStayOn作为标志,mStayOnWhilePluggedInSetting是从SettingsProvider中读取的值,表示是否设置了充电时保持屏幕常亮,若要使mStayOn为true,其先决条件是mStayOnWhilePluggedInSetting为true,同时DevicePolicyManager没有进行最大超时时间的约束,如果符合这个条件,则当设备在充电时mStayOn为true.其他情况下都为false.mStayOn在进入Dream相关从操作时作为判断条件用到。
1.2.3.updateScreenBrightnessBoostLocked()
这部分代码在PhoneWindowManager中触发的,具体没有研究,和亮度增强有关系。
private void updateScreenBrightnessBoostLocked(int dirty) {
if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) {
if (mScreenBrightnessBoostInProgress) {
final long now = SystemClock.uptimeMillis();
mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
if (mLastScreenBrightnessBoostTime > mLastSleepTime) {
final long boostTimeout = mLastScreenBrightnessBoostTime +
SCREEN_BRIGHTNESS_BOOST_TIMEOUT;
if (boostTimeout > now) {
Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, boostTimeout); return;
}
}
mScreenBrightnessBoostInProgress = false;
mNotifier.onScreenBrightnessBoostChanged();
userActivityNoUpdateLocked(now,
PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
}
}
}
1.2.4.updateWakeLockSummaryLocked()
在这个方法中,会对当前所有的WakeLock锁进行统计,过滤所有的wakelock锁状态(wakelock锁机制在后续进行分析),并更新mWakeLockSummary的值以汇总所有活动的唤醒锁的状态。mWakeLockSummary是一个用来记录所有WakeLock锁状态的标识值,该值在请求Display状时会用到。当系统处于睡眠状态时,大多数唤醒锁都将被忽略,比如系统在处于唤醒状态(awake)时,会忽略PowerManager.DOZE_WAKE_LOCK类型的唤醒锁,系统在处于睡眠状态(asleep)或者Doze状态时,会忽略PowerManager.SCREEN_BRIGHT类型的锁等等。该方法如下:
private void updateWakeLockSummaryLocked(int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
mWakeLockSummary = 0; //在waklock集合中遍历wakelock
final int numWakeLocks = mWakeLocks.size();
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.PARTIAL_WAKE_LOCK:
if (!wakeLock.mDisabled) { // We only respect this if the wake lock is not disabled.
//如果存在PARTIAL_WAKE_LOCK并且该wakelock可用,
//通过置位进行记录,下同
mWakeLockSummary |= WAKE_LOCK_CPU;
}
break;
case PowerManager.FULL_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT |
WAKE_LOCK_BUTTON_BRIGHT;
break;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;
break;
case PowerManager.SCREEN_DIM_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;
break;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
mWakeLockSummary |=
WAKE_LOCK_PROXIMITY_SCREEN_OFF;
break;
case PowerManager.DOZE_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_DOZE;
break;
case PowerManager.DRAW_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_DRAW;
break;
}
} // Cancel wake locks that make no sense based on the current state.
//下面就是移除在特定状态下,没有意义的WakeLock
if (mWakefulness != WAKEFULNESS_DOZING) {
//如果不是Dozing状态,移除相应的wakeLock标志位
mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
}
if (mWakefulness == WAKEFULNESS_ASLEEP
|| (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
//如果当前为Asleep或者有Doze的wakeLock锁的时候,应该移除掉屏幕亮度相关的wakeLock锁
mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT |
WAKE_LOCK_SCREEN_DIM| WAKE_LOCK_BUTTON_BRIGHT);
if (mWakefulness == WAKEFULNESS_ASLEEP) {
//休眠时,sensor不再需要监听终端是否靠近物体,以触发亮灭屏
mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
}
}
// Infer implied wake locks where necessary based on the current state.
//根据当前的状态,及PMS持有的WakeLock,推断出隐含的持锁需求
//例如:当PMS持有亮屏锁WAKE_LOCK_SCREEN_BRIGHT时,若当前终端为唤醒态
//那么CPU显然也需要处于唤醒态
if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT |
WAKE_LOCK_SCREEN_DIM)) != 0) { //处于awake状态,WAKE_LOCK_STAY_AWAKE只用于awake状态时
if (mWakefulness == WAKEFULNESS_AWAKE) {
mWakeLockSummary |= WAKE_LOCK_CPU |
WAKE_LOCK_STAY_AWAKE; //处于屏保状态(dream)
} else if (mWakefulness == WAKEFULNESS_DREAMING) {
mWakeLockSummary |= WAKE_LOCK_CPU;
}
} if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
mWakeLockSummary |= WAKE_LOCK_CPU;
}
}
}
结合每个WakeLock level的注释信息,以上代码还是比较好理解的。
这里唯一需要说明的是,Android定义一个mWakeLockSummary变量的原因是:
PMS将WakeLock定义为不同进程的请求信息,这些请求信息对CPU、屏幕和键盘有不同的需求。
对于每一种资源而言,只要有一个申请满足获取条件,PMS就需要为终端分配该申请对应的资源。
例如:假设PMS有20个WakeLock,只有1个申请亮屏,另外19个只申请CPU唤醒,PMS仍然需要保持终端亮屏。
因此,mWakeLockSummary就提供了一种整合多个WakeLock请求的功能,方便PMS进行集中的控制。
1.2.5 updateUserActivitySummaryLocked
updateUserActivitySummaryLocked主要根据用户最后的活动来决定当前屏幕的状态。
该方法用来更新用户活动时间,当设备和用户有交互时,都会根据当前时间和休眠时长、Dim时长、所处状态而计算下次休眠的时间,从而完成用户活动超时时的操作。如由亮屏进入Dim的时长、Dim到灭屏的时长、亮屏到屏保的时长,就是在这里计算的。进行关键代码如下(有删减):
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) {
//设备完全进入休眠所需时间,该值为-1表示禁用此值,默认-1
final int sleepTimeout = getSleepTimeoutLocked();
//用户超时时间,既经过一段时间不活动进入休眠或屏保的时间,特殊情况外,该值为Settings中的休眠时长
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
//Dim时长,即亮屏不操作,变暗多久休眠
final int screenDimDuration =
getScreenDimDurationLocked(screenOffTimeout); //通过WindowManager的用户交互
final boolean userInactiveOverride =
mUserInactiveOverrideFromWindowManager;
mUserActivitySummary = 0; //1.亮屏;2.亮屏后进行用户活动
if (mLastUserActivityTime >= mLastWakeTime) {
//下次睡眠时间=上次用户活动时间+休眠时间-Dim时间
nextTimeout = mLastUserActivityTime
+ screenOffTimeout - screenDimDuration; //如果满足当前时间<下次屏幕超时时间,说明此时设备为亮屏状态,则将用户活动状态置为表示亮屏的USER_ACTIVITY_SCREEN_BRIGHT
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else { //如果当前时间>下次活动时间,此时应有两种情况:已经休眠和Dim
nextTimeout = mLastUserActivityTime + screenOffTimeout; //如果当前时间<上次活动时间+屏幕超时时间,这个值约为3s,说明此时设备为Dim状态,则将用户活动状态置为表示Dim的USER_ACTIVITY_SCREEN_DIM
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
........................................................... //发送定时Handler,到达时间后再次进行updatePowerStateLocked()
if (mUserActivitySummary != 0 && nextTimeout >= 0) {
Message msg =
mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextTimeout);
}
} else {
mUserActivitySummary = 0;
}
}
}
在获取用户活动超时时长时,不仅仅是由用户在设置中设置的休眠时长所决定,还有比如带有PowerManager.ON_AFTER_RELEASE标记的wakelock锁在释放时也会影响用户超时时间。上述代码中只列出了最常见的一种,即由用户亮屏到到达时间休眠的代码逻辑。这里举个例子,假设设备设定休眠时间为15s,Dim时长为3s,我在9:20:01时按power键唤醒设备,因此,执行到该方法时有:
mLastUserActivity=mLastWakeTime=9:20:01,now=9:20:01+0.02ms,screenOffTimeout=15s,screenDimDuration=3s,所以nextTimeout为9:20:01+15s-3s=9:20:13
因此会通过Handler发送一个定时消息,13秒后会进入Dim…
现在时间到9:20:13,执行Handler中的消息,这个消息中又调用了一次updatePowerState()方法,所以又会执行到这个方法,此时:只有now发生改变为9:20:13+0.02ms(调用方法消耗的时间),因此now>nextTimeout,进入else语句,进入else后:
nextTimeout = mLastUserActivity + screenOffTimeout =9:20:01+15s=9:20:16 > now
因此判断当前因为Dim状态,同时nextTimeout发生改变,并且再次通过Handler设置定时消息,…,3s后,又回到了该方法中进行了处理,这次处理,会通过判断将nextTimeout设为-1,从而不再发送Handler,通过updatePowerStateLocked()中的其他方法进行休眠。
在计算完成nextTimeout后,会通过Handler发送一个延时消息,到达nextTimeout后,再次更新整个电源状态:
private final class PowerManagerHandler extends Handler {
public PowerManagerHandler(Looper looper) {
super(looper, null, true /*async*/);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_USER_ACTIVITY_TIMEOUT:
handleUserActivityTimeout();
break;
......
private void handleUserActivityTimeout() {
// runs on handler thread
synchronized (mLock) {
if (DEBUG_SPEW) {
Slog.d(TAG, "handleUserActivityTimeout");
}
mDirty |= DIRTY_USER_ACTIVITY;
updatePowerStateLocked();
}
}
此外,这里还有一点需要注意的地方,在计算灭屏超时时间时,有两个值:
final int sleepTimeout = getSleepTimeoutLocked();
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
这两个方法和休眠时间相关,在PMS中,定义了两个相关值:
mSleepTimeoutSetting = Settings.Secure.getIntForUser(resolver,
Settings.Secure.SLEEP_TIMEOUT, DEFAULT_SLEEP_TIMEOUT,
UserHandle.USER_CURRENT);
mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
UserHandle.USER_CURRENT);
其中 Settings.Secure.SLEEP_TIMEOUT表示设备在经过一段不活动后完全进入睡眠后屏保的时间,该值可以理解为保持唤醒或屏保的最大值或上限,并且该值要大于Settings.System.SCREEN_OFF_TIMEOUT,默认为-1,表示禁用此项功能。Settings.System.SCREEN_OFF_TIMEOUT表示设备在经过一段不活动后进入睡眠或屏保的时间,也称为用户活动超时时间,但屏幕到期时不一定关闭。该值可以在设置-休眠中设置。
1.2.6.for(;;)循环和updateWakefulnessLocked()
在updatePowerStateLocked()方法中,设置了一个死循环,并且上述分析的两个方法都在死循环中执行,为何设计一个死循环与它循环内部的实现有关系。接下来逐一分析其内容。for循环代码如下:
for (;;) { int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
//汇总wakelock
updateWakeLockSummaryLocked(dirtyPhase1);
//汇总useractivity
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
其中汇总wakelock和useractivity方法在前面已经进行了分析,因此这里主要有一个关键方法:updateWakefulnessLocked(),这个方法是退出循环的关键。如果这个方法返回false,则循环结束,如果返回true,则进行下一次循环,那么这个方法返回值有何含义呢?我们继续看看这个方法:
private boolean updateWakefulnessLocked(int dirty) {
boolean changed = false;
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY |
DIRTY_BOOT_COMPLETED
| DIRTY_WAKEFULNESS | DIRTY_STAY_ON |
DIRTY_PROXIMITY_POSITIVE
| DIRTY_DOCK_STATE)) != 0) { //当前屏幕保持唤醒&&设备将要退出唤醒状态(睡眠or屏保)
if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
final long time = SystemClock.uptimeMillis(); //是否在休眠时启用屏保
if (shouldNapAtBedTimeLocked()) { //进入屏保,返回true
changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
} else { //进入睡眠,返回true
changed = goToSleepNoUpdateLocked(time,
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0,
Process.SYSTEM_UID);
}
}
} return changed;
}
第一个if非常用以满足,第二个条件要求mWakefulness为WAKEFULNESS_AWAKE,且isItBedTimeYetLocked()为true,此函数官方解释为当系统马上要进入睡眠状态时会返回true,也就是当系统一直处于活跃状态,则其返回false所以,updateWakefulnessLocked()方法返回值为false,那么这个死循环只用执行一次就跳出了,这里假定系统一段时间未被操作,即将接下来就要调用进入睡眠状态,则isItBedTimeYetLocked()函数返回true,接下来就该调用shouldNapAtBedTimeLocked()方法了,该方法检查又没有设置睡眠之前启动动态屏保或者插在座充上启动屏保,如果设置了,调用napNoUpdateLocked(),没有设置则调用gotoSleepNoUpdateLocked()。
private boolean napNoUpdateLocked(long eventTime, int uid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid);
}
if (eventTime < mLastWakeTime || mWakefulness != WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "nap");
try {
Slog.i(TAG, "Nap time (uid " + uid +")...");
mSandmanSummoned = true;
setWakefulnessLocked(WAKEFULNESS_DREAMING, 0);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
如果if语句中有一项成立则返回false,则跳出死循环,当时如果第一次调用该方法,正常情况下当为false,如果第二次调用到此肯定会返回false,因为第二次调用时mWakefulness 为,WAKEFULNESS_DREAMING。
updateWakefulnessLocked这个方法用于更新设备的wakefulness,同时,这个方法是亮屏->屏保/睡眠的决策点。wakefulness是用来表示当前设备状态的一个值,系统定义的wakefulness值共有四种,分别表示不同的状态:
//睡眠状态,此时灭屏
public static final int WAKEFULNESS_ASLEEP = 0;
//屏幕亮
public static final int WAKEFULNESS_AWAKE = 1;
//屏保
public static final int WAKEFULNESS_DREAMING = 2;
//处于DOZE模式时
public static final int WAKEFULNESS_DOZING = 3;
如果当前设备处于唤醒状态(awake),并且将要退出唤醒状态,也就是进入睡眠状态(sleep)或者屏保状态(dreaming),如果设备开启了屏保,进入屏保状态,否则直接进入睡眠状态。这种情况下,wakefulness发生改变,因此返回值为true,需要通过下一次循环重新统计wakelockSummary和userActivitySummary。如果不是以上情况,则不会进入if语句,说明不需要改变wakefulness值,返回false,则循环体只执行一次便退出。因此,该循环只有在一段时间不活动到达用户超时时间后进入屏保或者进入睡眠时,会执行两次,其他情况下只执行一次便退出,比如按power键灭屏等只会执行一次,因为当power键灭屏时,wakefulness值已经由唤醒状态变为SLEEP状态,因此不满足执行条件。
知道updatefulnessLocked()方法的主要功能后,现在来看看其中和休眠、屏保相关的方法。首先来看isItBedTimeYetLocked()方法,该方法判断当前设备是否将要进入睡眠状态,返回值为对isBeKeptAwakeLocke()方法返回值取反,由mStayOn(是否屏幕常亮)、wakelockSummary、userActivitySummary、mProximityPositive等决定,只要满足其中之一为ture,则说明无法进入睡眠,也就说,要满足进入睡眠,相关属性值都为false。isBeKeptAwakeLocke()如下:
private boolean isBeingKeptAwakeLocked() {
return mStayOn//屏幕是否保持常亮
|| mProximityPositive//接近传感器接近屏幕时为true
//处于awake状态
|| (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
//屏幕处于亮屏或者dim状态
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM)) != 0
|| mScreenBrightnessBoostInProgress;//处于亮度增强中}
接下来看看shoudNapAtBedTimeLocked()方法。这个方法用来判断设备是否进入屏保模式:
private boolean shouldNapAtBedTimeLocked() {//屏保是否开启return mDreamsActivateOnSleepSetting
|| (mDreamsActivateOnDockSetting //插入基座时是否开启屏保
&& mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED);
}
除了以上方法外,还有napNoUpdateLocked()和goToSleepNoUpdateLocked()方法,这两个方法分别用于控制设备进入屏保或者休眠,将在特定场景下进行分析。
结合上述三个方法的分析,之所以把updateWakeLockSummaryLocked()、updateUserActivitySummaryLocked()、updateWakefulnessLocked()这三个方法放在for(;;)循环中调用,是因为它们共同决定了设备的状态,前两个方法是汇总状态,后一个方法是根据前两个方法汇总的值而进行判断是否要改变当前的设备唤醒状态,汇总状态会受mWakefulness的影响,因此会进行循环处理。同时,也仅仅会在超时灭屏进入睡眠或屏保时,for循环会执行两次,其他情况下,只会执行一次。