前面的博客中,我们已经分析过,当Android中的进程要使用电量时,需要向PMS申请WakeLock;当进程完成工作后,需要释放对应的WakeLock。
PMS收到申请和释放WakeLock的请求后,均需要调用updatePowerStateLocked来更新电源的状态,该函数是PMS的核心方法。
接下来,我们就结合代码,看一下updatePowerStateLocked的工作流程。
/**
* Updates the global power state based on dirty bits recorded in mDirty.
*
* This is the main function that performs power state transitions.
* We centralize them here so that we can recompute the power state completely
* each time something important changes, and ensure that we do it the same
* way each time. The point is to gather all of the transition logic here.
*/
private void updatePowerStateLocked() {
if (!mSystemReady || mDirty == 0) {
return;
}
..........
try {
updateIsPoweredLocked(mDirty);
updateStayOnLocked(mDirty);
updateScreenBrightnessBoostLocked(mDirty);
final long now = SystemClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
updateDreamLocked(dirtyPhase2, displayBecameReady);
finishWakefulnessChangeIfNeededLocked();
updateSuspendBlockerLocked();
} finally {
..........
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
在PMS中有个很重要的变量mDirty,该变量按位存储PMS中的各种变化状态。
例如,之前介绍PMS的acquire WakeLock流程时,就进行了以下操作:
.........
mDirty |= DIRTY_WAKE_LOCKS;
........
每当PMS检测到一些重要事件发生时,就会更新mDirty的相应的位。
从updatePowerStateLocked的代码可以看出,它将根据mDirty中的信息,来更新手机中的电源状态。
根据Android源码中的注释,可以看出updatePowerStateLocked的工作主要分为几个步骤,接下来我们一个一个步骤的来进行分析。
一、更新基本状态信息
1、updateIsPoweredLocked
我们先来看看updateIsPoweredLocked函数:
private void updateIsPoweredLocked(int dirty) {
if ((dirty & DIRTY_BATTERY_STATE) != 0) {
final boolean wasPowered = mIsPowered;
final int oldPlugType = mPlugType;
final boolean oldLevelLow = mBatteryLevelLow;
mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
mPlugType = mBatteryManagerInternal.getPlugType();
mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();
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
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
从以上代码可以看出updateIsPoweredLocked主要用于:
更新PMS中的一些变量,包括记录终端是否在充电、充电的类型、电池的电量及电池电量是否处于低电状态;
当电源的充电状态,或者充电类型发生变化,判断出现插拔充电器等操作时,是否需要点亮或熄灭屏幕;
当电源充电状态发生变化,或者终端是否处于低电量的标志发生变化的时候,终端调用updateLowPowerModeLocked()更新低电模式相关的操作。
我们跟进一下updateLowPowerModeLocked函数:
private void updateLowPowerModeLocked() {
if (mIsPowered && mLowPowerModeSetting) {
........
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE, 0);
mLowPowerModeSetting = false;
}
final boolean autoLowPowerModeEnabled = !mIsPowered && mAutoLowPowerModeConfigured
&& !mAutoLowPowerModeSnoozing && mBatteryLevelLow;
final boolean lowPowerModeEnabled = mLowPowerModeSetting || autoLowPowerModeEnabled;
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
powerHintInternal(POWER_HINT_LOW_POWER, lowPowerModeEnabled ? 1 : 0);
postAfterBootCompleted(new Runnable() {
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
.putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, mLowPowerModeEnabled)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcast(intent);
synchronized (mLock) {
listeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(
mLowPowerModeListeners);
}
for (int i=0; i<listeners.size(); i++) {
listeners.get(i).onLowPowerModeChanged(lowPowerModeEnabled);
}
intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcast(intent);
mContext.sendBroadcastAsUser(new Intent(
PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL), UserHandle.ALL,
Manifest.permission.DEVICE_POWER);
});
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
从上面的代码可以看出updateLowPowerModeLocked函数,
首先判断手机是否在充电,如果手机在充电,退出LowPowerMode模式,同时更新数据库;
当手机的低电量模式发生了变化,就发送广播进行通知,并回调关于监听该模式变化的观察者的接口。
例如:UI对应的APK收到低电量省电模式的广播,就会弹出低电量省电模式的提醒界面。
可以看出这一部分除了更新PMS中的一些变量外,关注的重点还是集中在:
充电状态是否改变;
充电状态的改变,将引出对充电器插拔是否需要亮屏的考虑;
同样,充电状态的改变,将引出对终端的低电模式是否发生改变的考虑。
从这个角度来看,updateIsPoweredLocked函数的命名是实至名归的。
2、updateStayOnLocked
现在我们看看基本状态更新第二部分的updateStayOnLocked函数:
/**
* Updates the value of mStayOn.
* Sets DIRTY_STAY_ON if a change occurred.
*/
private void updateStayOnLocked(int dirty) {
if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) {
final boolean wasStayOn = mStayOn;
if (mStayOnWhilePluggedInSetting != 0
&& !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
mStayOn = mBatteryManagerInternal.isPowered(mStayOnWhilePluggedInSetting);
} else {
mStayOn = false;
}
if (mStayOn != wasStayOn) {
mDirty |= DIRTY_STAY_ON;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
这一部分的代码功能比较单一,主要用于更新变量mStayOn的值。
如果mStayOn如果为true,则屏幕保持长亮的状态。
3、updateScreenBrightnessBoostLocked
Android手机定义了一个最大屏幕亮度,用户可以手动或者让终端自动确定最大的屏幕亮度。
updateScreenBrightnessBoostLocked函数主要用于:更新终端可处于最大屏幕亮度的时间。
为了比较好的理解updateScreenBrightnessBoostLocked函数,
我们可以先分析一下与之相关的,PMS提供的对外的接口boostScreenBrightness。
该方法的作用是让屏幕在一段时间内保持最大的亮度,使屏幕在强光下有更好的可读性。
public void boostScreenBrightness(long eventTime) {
..........
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
boostScreenBrightnessInternal(eventTime, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void boostScreenBrightnessInternal(long eventTime, int uid) {
synchronized (mLock) {
if (!mSystemReady || mWakefulness == WAKEFULNESS_ASLEEP
|| eventTime < mLastScreenBrightnessBoostTime) {
return;
}
..............
mLastScreenBrightnessBoostTime = eventTime;
if (!mScreenBrightnessBoostInProgress) {
mScreenBrightnessBoostInProgress = true;
mNotifier.onScreenBrightnessBoostChanged();
}
mDirty |= DIRTY_SCREEN_BRIGHTNESS_BOOST;
userActivityNoUpdateLocked(eventTime,
PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
updatePowerStateLocked();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
从上面的代码可以看出,该函数:
首先,使用mLastScreenBrightnessBoostTime变量记录了终端处于最大屏幕亮度的起始时间;
然后,将最大屏幕亮度的标志位置为true,并修改mDirty标志位,以表示最大屏幕亮度的状态发生了变化;
最后,调用updatePowerStateLocked方法更新电源状态信息。
我们已经知道,updatePowerStateLocked将会调用到updateScreenBrightnessBoostLocked。
接下来,我们看看updateScreenBrightnessBoostLocked对应的代码:
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
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
至此,PMS第一阶段更新基本状态信息的流程结束。
二、更新wakelock和用户活动
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
1、updateWakeLockSummaryLocked
updateWakeLockSummaryLocked函数根据PMS当前持有的所有WakeLock,得到当前终端整体的信息,保存到mWakeLockSummary变量中。
/**
* Updates the value of mWakeLockSummary to summarize the state of all active wake locks.
* Note that most wake-locks are ignored when the system is asleep.
*/
private void updateWakeLockSummaryLocked(int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
mWakeLockSummary = 0;
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) {
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;
}
}
if (mWakefulness != WAKEFULNESS_DOZING) {
mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
}
if (mWakefulness == WAKEFULNESS_ASLEEP
|| (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
| WAKE_LOCK_BUTTON_BRIGHT);
if (mWakefulness == WAKEFULNESS_ASLEEP) {
mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
}
}
if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
if (mWakefulness == WAKEFULNESS_AWAKE) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
} else if (mWakefulness == WAKEFULNESS_DREAMING) {
mWakeLockSummary |= WAKE_LOCK_CPU;
}
}
if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
mWakeLockSummary |= WAKE_LOCK_CPU;
}
...................
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
结合每个WakeLock level的注释信息,以上代码还是比较好理解的。
这里唯一需要说明的是,Android定义一个mWakeLockSummary变量的原因是:
PMS将WakeLock定义为不同进程的请求信息,这些请求信息对CPU、屏幕和键盘有不同的需求。
对于每一种资源而言,只要有一个申请满足获取条件,PMS就需要为终端分配该申请对应的资源。
例如:假设PMS有20个WakeLock,只有1个申请亮屏,另外19个只申请CPU唤醒,PMS仍然需要保持终端亮屏。
因此,mWakeLockSummary就提供了一种整合多个WakeLock请求的功能,方便PMS进行集中的控制。
2、updateUserActivitySummaryLocked
updateUserActivitySummaryLocked主要根据用户最后的活动来决定当前屏幕的状态。
/**
* Updates the value of mUserActivitySummary to summarize the user requested
* state of the system such as whether the screen should be bright or dim.
* Note that user activity is ignored when the system is asleep.
*/
private void updateUserActivitySummaryLocked(long now, int dirty) {
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();
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
mUserActivitySummary = 0;
if (mLastUserActivityTime >= mLastWakeTime) {
nextTimeout = mLastUserActivityTime
+ screenOffTimeout - screenDimDuration;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else {
nextTimeout = mLastUserActivityTime + screenOffTimeout;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
if (mUserActivitySummary == 0
&& mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
if (now < nextTimeout) {
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT) {
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;
}
}
if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
if ((mUserActivitySummary &
(USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {
if (nextTimeout >= now && mOverriddenTimeout == -1) {
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;
}
..........
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
从上面的代码可以看出,在该函数中用mUserActivitySummary变量存储当前屏幕的状态。
一共有3中基本状态:
* USER_ACTIVITY_SCREEN_BRIGHT 点亮屏幕
* USER_ACTIVITY_SCREEN_DIM 屏幕变暗
* USER_ACTIVITY_SCREEN_DREAM 屏保状态
从代码可以看出,屏幕变化和userActivity活动有关,它根据最后的userActivity活动的时间决定点亮屏幕、调暗屏幕或熄灭屏幕。
之前的很多方法中都会调用userActivityNoUpdateLocked方法。该方法将触发一次用户活动,以更新用户活动的时间,这样屏幕变暗和熄灭时间就会重新进行计算。
这也就是为什么用户一直操作手机,屏幕不会熄灭或者变暗的原因。
大图地址
整体来讲,个人感觉这个函数的代码写的还是挺绕的,因此还是作一个图记录一下。
大家有兴趣可以看一下。
3、updateWakefulnessLocked
从之前的代码可以看出,updateWakefulnessLocked将决定第二阶段的电源状态更新是否结束。
我们看一下updateWakefulnessLocked函数:
/**
* Updates the wakefulness of the device.
*
* This is the function that decides whether the device should start dreaming
* based on the current wake locks and user activity state. It may modify mDirty
* if the wakefulness changes.
*
* Returns true if the wakefulness changed and we need to restart power state calculation.
*/
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) {
if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
................
final long time = SystemClock.uptimeMillis();
if (shouldNapAtBedTimeLocked()) {
changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
} else {
changed = goToSleepNoUpdateLocked(time,
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
}
}
}
return changed;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
从上面的代码可以看出,如果终端可以一直保持唤醒状态,或一开始就是非唤醒态,
那么mWakefulness不会发生改变,第二阶段的for循环将会break;
如果终端要从唤醒态变为非唤醒态,那么for循环将再运行一次,即重新计算一次mWakeLockSummary和mUserActivitySummary。
这么做的原因是:updateWakeLockSummaryLocked和updateUserActivitySummaryLocked函数的一些计算,与终端是否处于唤醒状态,即mWakefulness的值有关。
由于这两个函数并不会修改mWakefulness,因此在这一次运行时,updateWakefulnessLocked将返回false,即第二阶段结束。
因此,我们可以得出结论:更新电源状态的第二阶段,正常情况下最多运行两次。
在第二阶段的最后,我们看一下isItBedTimeYetLocked函数:
/**
* Returns true if the device should go to sleep now.
* Also used when exiting a dream to determine whether we should go back
* to being fully awake or else go to sleep for good.
*/
private boolean isItBedTimeYetLocked() {
return mBootCompleted && !isBeingKeptAwakeLocked();
}
/**
* Returns true if the device is being kept awake by a wake lock, user activity
* or the stay on while powered setting. We also keep the phone awake when
* the proximity sensor returns a positive result so that the device does not
* lock while in a phone call. This function only controls whether the device
* will go to sleep or dream which is independent of whether it will be allowed
* to suspend.
*/
private boolean isBeingKeptAwakeLocked() {
return mStayOn
|| mProximityPositive
|| (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM)) != 0
|| mScreenBrightnessBoostInProgress;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
参考原生代码的注释,这一部分代码还是比较好理解的。
三、更新display power state
第三阶段将负责更新屏幕的显示状态。
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)) != 0) {
mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
.................
...................
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
...................
}
return mDisplayReady && !oldDisplayReady;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
我们跟进一下DisplayPowerController的requestPowerState函数:
/**
* Requests a new power state.
* The controller makes a copy of the provided object and then
* begins adjusting the power state to match what was requested.
*/
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;
} else if (!mPendingRequestLocked.equals(request)) {
mPendingRequestLocked.copyFrom(request);
changed = true;
}
if (changed) {
mDisplayReadyLocked = false;
}
if (changed && !mPendingRequestChangedLocked) {
mPendingRequestChangedLocked = true;
sendUpdatePowerStateLocked();
}
return mDisplayReadyLocked;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
根据requestPowerState的代码,我们知道:
当PMS传入一个新的mDisplayPowerRequest时,requestPowerState应该返回为false;当DisplayPowerController按照mDisplayPowerRequest修改完屏幕状态,再次进入回到updateDisplayPowerStateLocked函数,调用requestPowerState时才会返回true。
整体的代码流程大概可以抽象成下图:
这一阶段的代码,我们只是分析了整个过程的冰山一角,并没有分析更新屏幕状态的实际操作。
但从现有的代码可以看出,PMS的作用仅仅是维护终端电源相关状态,实际的工作还是通过类似发送Request的方式,让其它的服务协助完成。
例如:在整个阶段,PMS根据之前得到信息,构造出DisplayPowerRequest,然后发送给DisplayPowerController进行实际的处理。
当DisplayPowerController完成实际的工作(部分工作还依赖于PhoneWindowManager)后,再通知PMS进行复查。
因此PMS的定位,确实可以用一个”Manager”来形容;
负责整个终端信息的搜集和维护,然后将相应的工作指派给具体的“员工”执行;
“员工”执行完毕后,向”Manager”汇报;
“Manager”检查工作的完成情况后,然后做出下一步的指示。
四、更新dream state
updateDreamLocked函数主要用于更新屏保状态,当设备进入或者退出屏保的时候都会触发这个方法:
private void updateDreamLocked(int dirty, boolean displayBecameReady) {
if ((dirty & (DIRTY_WAKEFULNESS
| DIRTY_USER_ACTIVITY
| DIRTY_WAKE_LOCKS
| DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS
| DIRTY_IS_POWERED
| DIRTY_STAY_ON
| DIRTY_PROXIMITY_POSITIVE
| DIRTY_BATTERY_STATE)) != 0 || displayBecameReady) {
if (mDisplayReady) {
scheduleSandmanLocked();
}
}
private void scheduleSandmanLocked() {
if (!mSandmanScheduled) {
mSandmanScheduled = true;
Message msg = mHandler.obtainMessage(MSG_SANDMAN);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
handleSandman函数比较复杂,主要用于决定设备是否应该停留在dreaming或dozing状态。
我们分段介绍该函数的功能。
1、决定是否可以进入屏保状态
/**
* Called when the device enters or exits a dreaming or dozing state.
*/
private void handleSandman() {
final boolean startDreaming;
final int wakefulness;
synchronized (mLock) {
mSandmanScheduled = false;
wakefulness = mWakefulness;
if (mSandmanSummoned && mDisplayReady) {
startDreaming = canDreamLocked() || canDozeLocked();
mSandmanSummoned = false;
} else {
startDreaming = false;
}
}
..........
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
这段代码主要用于确定,设备是否可以看是dreaming。
除去前置条件的限制外,此处的结果主要由canDreamLocked和canDozeLocked决定。
我们分别看看这两个函数:
/**
* Returns true if the device is allowed to dream in its current state.
*/
private boolean canDreamLocked() {
if (mWakefulness != WAKEFULNESS_DREAMING
|| !mDreamsSupportedConfig
|| !mDreamsEnabledSetting
|| !mDisplayPowerRequest.isBrightOrDim()
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM | USER_ACTIVITY_SCREEN_DREAM)) == 0
|| !mBootCompleted) {
return false;
}
if (!isBeingKeptAwakeLocked()) {
if (!mIsPowered && !mDreamsEnabledOnBatteryConfig) {
return false;
}
if (!mIsPowered
&& mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0
&& mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) {
return false;
}
if (mIsPowered
&& mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0
&& mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) {
return false;
}
}
return true;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
从上面的代码可以看出,dreaming除了对终端当前的状态、配置项有关外,在非唤醒状态下还与当前的电池电量有关系。
canDozeLocked函数相对简单:
private boolean canDozeLocked() {
return mWakefulness == WAKEFULNESS_DOZING;
}
2、在必要时,进入屏保状态
final boolean isDreaming;
if (mDreamManager != null) {
if (startDreaming) {
mDreamManager.stopDream(false );
mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);
}
isDreaming = mDreamManager.isDreaming();
} else {
isDreaming = false;
}
决定了是否可以进入屏保状态后,这一部分就开始进行实际的工作。
mDreamManager为DreamManagerService的Binder代理。
我们重点看看DreamManagerService的startDream函数,stopDream的工作内容与startDream相反,不做细致分析:
public void startDream(boolean doze) {
startDreamInternal(doze);
}
private void startDreamInternal(boolean doze) {
final int userId = ActivityManager.getCurrentUser();
final ComponentName dream = chooseDreamForUser(doze, userId);
if (dream != null) {
synchronized (mLock) {
startDreamLocked(dream, false , doze, userId);
}
}
}
private void startDreamLocked(final ComponentName name,
final boolean isTest, final boolean canDoze, final int userId) {
if (Objects.equal(mCurrentDreamName, name)
&& mCurrentDreamIsTest == isTest
&& mCurrentDreamCanDoze == canDoze
&& mCurrentDreamUserId == userId) {
return;
}
stopDreamLocked(true );
final Binder newToken = new Binder();
mCurrentDreamToken = newToken;
mCurrentDreamName = name;
mCurrentDreamIsTest = isTest;
mCurrentDreamCanDoze = canDoze;
mCurrentDreamUserId = userId;
mHandler.post(new Runnable() {
@Override
public void run() {
mController.startDream(newToken, name, isTest, canDoze, userId);
}
});
}
public void startDream(Binder token, ComponentName name,
boolean isTest, boolean canDoze, int userId) {
stopDream(true );
.........
try {
..............
mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
mDreamStartTime = SystemClock.elapsedRealtime();
..............
try {
mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
} catch (RemoteException ex) {
Slog.e(TAG, "Unable to add window token for dream.", ex);
stopDream(true );
return;
}
Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
intent.setComponent(name);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
try {
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 );
return;
} catch (SecurityException ex) {
............
stopDream(true );
return;
}
mCurrentDream.mBound = true;
mHandler.postDelayed(mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT);
} finally {
........
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
从这部分代码我们知道了,所谓的屏保其实就是拉起一个特殊的服务。
3、更新屏保状态
synchronized (mLock) {
if (startDreaming && isDreaming) {
mBatteryLevelWhenDreamStarted = mBatteryLevel;
................
}
if (mSandmanSummoned || mWakefulness != wakefulness) {
return;
}
.............
if (wakefulness == WAKEFULNESS_DREAMING) {
if (isDreaming && canDreamLocked()) {
if (mDreamsBatteryLevelDrainCutoffConfig >= 0
&& mBatteryLevel < mBatteryLevelWhenDreamStarted
- mDreamsBatteryLevelDrainCutoffConfig
&& !isBeingKeptAwakeLocked()) {
} else {
return;
}
}
if (isItBedTimeYetLocked()) {
goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
updatePowerStateLocked();
} else {
wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), "android.server.power:DREAM",
Process.SYSTEM_UID, mContext.getOpPackageName(), Process.SYSTEM_UID);
updatePowerStateLocked();
}
} else if (wakefulness == WAKEFULNESS_DOZING) {
if (isDreaming) {
return;
}
reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);
updatePowerStateLocked();
}
}
if (isDreaming) {
mDreamManager.stopDream(false );
}
...........
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
以上是PMS更新屏保状态的基本流程,整体来看相当的繁琐。
我们还是用一个图来整体整理一下:
大图链接
这部分代码最后太乱,每次更新状态后都会重新调用updatePowerStateLocked,然后再次进入到handleSandman函数中。
这种反复地递归调用,比较难以把控。
五、更新suspend blocker
updateSuspendBlockerLocked函数主要根据之前流程的执行结果,持有或者释放CPU和屏幕的锁。
我们一起来看看对应的函数:
private void updateSuspendBlockerLocked() {
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
final boolean autoSuspend = !needDisplaySuspendBlocker;
final boolean interactive = mDisplayPowerRequest.isBrightOrDim();
if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(false);
}
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.acquire();
mHoldingWakeLockSuspendBlocker = true;
}
if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.acquire();
mHoldingDisplaySuspendBlocker = true;
}
if (mDecoupleHalInteractiveModeFromDisplayConfig) {
if (interactive || mDisplayReady) {
setHalInteractiveModeLocked(interactive);
}
}
if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.release();
mHoldingWakeLockSuspendBlocker = false;
}
if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(true);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
从上面的代码可以看出PMS是非常依赖于native层的,真实的持锁、释放锁、设置交互状态等工作,均是移交到native层进行操作。
我们以mWakeLockSuspendBlocker的处理流程为例,看看native的调用过程:
..........
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
.........
之前的博客也提到过,PMS在其构造函数中调用createSuspendBlockerLocked函数,创建出了mWakeLockSuspendBlocker:
private SuspendBlocker createSuspendBlockerLocked(String name) {
SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);
mSuspendBlockers.add(suspendBlocker);
return suspendBlocker;
}
从上面的代码,我们知道当PMS需要获取底层锁时,调用的是SuspendBlockerImpl的acquire函数:
public void acquire() {
synchronized (this) {
mReferenceCount += 1;
if (mReferenceCount == 1) {
.......
nativeAcquireSuspendBlocker(mName);
}
}
}
在native层的com_android_server_power_PowerManagerService.cpp中,对应的native函数为:
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
ScopedUtfChars name(env, nameStr);
acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}
从这里的代码我们不难发现,尽管PMS定义了不同的WakeLock等级,但当通过PMS的native函数调用HAL层函数acquire_wake_lock时,使用的都是PARTIAL_WAKE_LOCK。
个人觉得这是可以理解的,当其它进程向PMS申请保持屏幕唤醒的Framework层WakeLock后,PMS在Framework层就进行了对应的处理,例如将请求信息等地交给DisplayPowerController等处理。因此,对于底层的HAL层而言,只需要关注CPU是否需要保持唤醒即可。
HAL层函数acquire_wake_lock,最后会向/sys/power/wake_lock节点进行write操作。
总结
至此,updatePowerStateLocked的基本流程介绍完毕,大体上如下图所示:
通过其中的源码,我们也能看出仅管理当前的状态,涉及的细节就非常的琐碎。
而屏幕和CPU的实际控制,还牵扯到大量其它对象和HAL层代码。
Android电源的管理实际上是基于Linux电源管理策略的,因此若要真正掌握,还需要对Linux的电源管理策略作进一步的了解。
由于个人水平有限,目前还无法高屋建瓴地整体分析宏观的电源管理架构,细节也有一些遗漏。
后续争取以此博客为基础,不断迭代,以求更进一步地了解PMS的知识。
原文地址: http://blog.csdn.net/gaugamela/article/details/52838654