概要
PowerManagerService之省电模式(1): 初步认识 对省电模式进行了一个初步认识,介绍了一些概念,以及对省电模式环境初始化的代码进行了简单分析。读者需要仔细阅读第一篇文章,再来看这一篇文章。
打开省电模式,有三种方式
- 手动模式,也就是用户手动打开省电模式。
- 自动模式,用户设置一个电量百分比阈值,当电量低于这个阈值,自动触发省电模式。
- 动态模式,这种模式其实就是自动模式。根据文档,这个模式是提供给应用,根据情况自动调整触发省电模式的阈值。
本文只关注如下内容
- 省电模式的打开过程。
- 什么是 battery saver sticky 模式。
只要掌握了上面2点内容,自动模式、动态模式,都可以自行分析。
本文分析的代码涉及的文件路径如下
frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
本文分析的代码基于 Android 12
打开省电模式
现在以手动打开省电模式为例,分析省电模式的打开过程。
从 PowerManagerService之省电模式(1): 初步认识 可知,在 Settings->Battery->Battery Saver 界面,可以手动打开省电模式,调用代码如下
context.getSystemService(PowerManager.class).setPowerSaveModeEnabled(true);
最终会调用 PowerManagerService 对应的方法
// PowerManagerService.java
public boolean setPowerSaveModeEnabled(boolean enabled) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER)
!= PackageManager.PERMISSION_GRANTED) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
}
final long ident = Binder.clearCallingIdentity();
try {
return setLowPowerModeInternal(enabled);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private boolean setLowPowerModeInternal(boolean enabled) {
synchronized (mLock) {
// 充电状态下,不允许打开/关闭省电模式
if (mIsPowered) {
return false;
}
mBatterySaverStateMachine.setBatterySaverEnabledManually(enabled);
return true;
}
}
在 AOSP 的设计中,省电模式和充电状态是冲突的。如果设备处于省电模式状态,此时插入充电器,那么一定会关闭省电模式。如果设备处于充电状态,那么是不允许打开省电模式的。
说实话,我不是很认同这种设计。我认为省电模式是用户的强烈个人意愿,只能由用户自己决定打开或者关闭。
BatterySaverStateMachine状态管理
从上面代码可知,打开省电模式时,通过 BatterySaverStateMachine#setBatterySaverEnabledManually() 方法,把指令传给状态机
// BatterySaverStateMachine.java
public void setBatterySaverEnabledManually(boolean enabled) {
synchronized (mLock) {
updateStateLocked(true, enabled);
}
}
状态机通过 updateStateLocked() 更新内部状态,然后根据状态执行相应的操作。 注意,这里的第一个参数表示是否是用户手动打开省电模式,值为 true,第二个参数表示是否打开省电模式,根据我们分析的例子,这里的值为 true。
// BatterySaverStateMachine.java
private void updateStateLocked(boolean manual, boolean enable) {
if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
return; // Not fully initialized yet.
}
switch (mState) {
case STATE_OFF: {
if (!mIsPowered) { // 非充电模式,才允许操作省电模式
if (manual) { // 手动操作
if (!enable) {
return;
}
// 用户手动打开省电模式
enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
BatterySaverController.REASON_MANUAL_ON);
hideStickyDisabledNotification();
// 状态切换为 STATE_MANUAL_ON
mState = STATE_MANUAL_ON;
} else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) {
// ... 自动模式
} else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) {
// ... 动态模式
}
}
break;
}
// ...
}
}
状态机里的默认状态是 STATE_OFF,表示省电模式默认关闭。
通过 enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, BatterySaverController.REASON_MANUAL_ON); 打开省电模式,然后把状态切换为 STATE_MANUAL_ON。对于每一次状态切换,我们都要注意,因此这会影响下一次状态切换。
// BatterySaverStateMachine.java
private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason) {
enableBatterySaverLocked(enable, manual, intReason, reasonToString(intReason));
}
private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason,
String strReason) {
final boolean wasEnabled = mBatterySaverController.isFullEnabled();
// 已经处于省电模式状态
if (wasEnabled == enable) {
return;
}
// 充电中,是不允许打开省电模式的
if (enable && mIsPowered) {
return;
}
mLastChangedIntReason = intReason;
mLastChangedStrReason = strReason;
mSettingBatterySaverEnabled = enable;
// 1. 保存省电模式的状态
putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0);
// 2. 打开 battery saver sticky 模式
if (manual) { // 用户手动操作省电模式
// mBatterySaverStickyBehaviourDisabled 默认为 false,表示支持 battery saver sticky 模式
setStickyActive(!mBatterySaverStickyBehaviourDisabled && enable);
}
// 3. 通过 BatterySaverController 打开省电模式
mBatterySaverController.enableBatterySaver(enable, intReason);
// 动态省电模式相关
if (intReason == BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON) {
triggerDynamicModeNotification();
} else if (!enable) {
hideDynamicModeNotification();
}
}
在打开省电模式之前,首先把数据库 Settings.Global.LOW_POWER_MODE 字段的值保存为 1。
low power 应该翻译为低功耗,俗称省电模式,而 low battery 才应该翻译为低电量,不要混淆了。 源码中 BatteryManagerService#getBatteryLevelLow() 表示电量是否低于自动省电模式的电量百分比,这个函数的命名非常差劲,一度让我误以为是低电量(电量低于15%),其实它表示是否触发了自动省电模式。
第二步,我们要注意了,这里涉及了 battery saver sticky 功能。根据判断条件可知,只有在用户手动操作省电模式的情况下,才会触发 battery saver sticky 功能,来看下 setStickyActive()
// BatterySaverStateMachine.java
private void setStickyActive(boolean active) {
// 表示 battery saver sticky 模式已经打开
mSettingBatterySaverEnabledSticky = active;
// Settings.Global.LOW_POWER_MODE_STICKY 代表 battery saver sticky功能的状态
putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY,
mSettingBatterySaverEnabledSticky ? 1 : 0);
}
很简单,就是保存状态,表示 battery saver sticky 功能已经打开。
第三步,把打开省电模式的实际操作,交给了省电模式控制器 BatterySaverController。
BatterySaverController切换省电模式
现在来看下 BatterySaverController#enableBatterySaver() 如何打开省电模式
//BatterySaverController.java
public void enableBatterySaver(boolean enable, int reason) {
synchronized (mLock) {
if (getFullEnabledLocked() == enable) {
return;
}
// 1. 保存省电模式的状态
setFullEnabledLocked(enable);
// 2. 更新省电模式策略
if (updatePolicyLevelLocked()) {
// 3. 处理省电模式状态的改变
mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
}
}
}
private boolean getFullEnabledLocked() {
return mFullEnabledRaw;
}
private void setFullEnabledLocked(boolean value) {
if (mFullEnabledRaw == value) {
return;
}
// 刷新省电模式的缓存,客户端可以通过 PowerManager 获取省电模式状态
PowerManager.invalidatePowerSaveModeCaches();
mFullEnabledRaw = value;
}
首先使用 mFullEnabledRaw 保存省电模式状态。
然后,更新省电模式的策略。省电模式会影响很多模块的功能,例如,最直观的就是影响屏幕亮度。因此打开省电模式,必须得有一个策略,这些策略影响某些模块的功能。
最后,处理省电模式状态的改变。其中包括切换省电模式,通知省电模式的监听者。
mFullEnabledRaw 表示 full battery saver,其实就是用户用到的省电模式。其实还有一种省电模式 adaptive battery saver,这种省电模式,是通过命令行设置的,应该是与测试相关,执行
adb shell power set-adaptive-power-saver-enabled true来开启,具体可以参考 PowerManagerShellCommand 类。
BattterySaverPolicy控制省电策略
现在来看下 BatterySaverController#updatePolicyLevelLocked() 如何更新省电模式策略
//BatterySaverController.java
private boolean updatePolicyLevelLocked() {
if (getFullEnabledLocked()) {
// 设置省电模式 policy level
return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_FULL);
} else if (getAdaptiveEnabledLocked()) {
return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_ADAPTIVE);
} else {
return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_OFF);
}
}
原来是给 BatterySaverPolicy 设置了 policy level,值为 BatterySaverPolicy.POLICY_LEVEL_FULL。
// BatterySaverPolicy.java
boolean setPolicyLevel(@PolicyLevel int level) {
synchronized (mLock) {
if (mPolicyLevel == level) {
return false;
}
if (mPolicyLevel == POLICY_LEVEL_FULL) {
mFullPolicy = mDefaultFullPolicy;
}
switch (level) {
case POLICY_LEVEL_FULL:
case POLICY_LEVEL_ADAPTIVE:
case POLICY_LEVEL_OFF:
// 1. 保存 level
mPolicyLevel = level;
break;
default:
Slog.wtf(TAG, "setPolicyLevel invalid level given: " + level);
return false;
}
// 2. 根据 level,更新有效的 policy
updatePolicyDependenciesLocked();
return true;
}
}
BatterSaverPolicy 保存了 policy level,并且调用 updatePolicyDependenciesLocked() 来更新有效的 battery saver policy。
// BatterySaverPolicy.java
private void updatePolicyDependenciesLocked() {
// 1. 根据 policy level, 获取对应的 policy
final Policy rawPolicy = getCurrentRawPolicyLocked();
// 刷新省电模式缓存
invalidatePowerSaveModeCaches();
// 车载
final int locationMode;
if (mAutomotiveProjectionActive.get()
&& rawPolicy.locationMode != PowerManager.LOCATION_MODE_NO_CHANGE
&& rawPolicy.locationMode != PowerManager.LOCATION_MODE_FOREGROUND_ONLY) {
// If car projection is enabled, ensure that navigation works.
locationMode = PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
} else {
locationMode = rawPolicy.locationMode;
}
// 2. 根据获取的策略,来更新有效的策略
// mEffectivePolicyRaw 表示实际生效的 policy
// mEffectivePolicyRaw 的数据,基本上都是从 rawPolicy 中复制过来的
// 只有几项是需要调整的,例如 车载 或者 无障碍,这两个特殊的情况,在使用时注意下即可
mEffectivePolicyRaw = new Policy(
rawPolicy.adjustBrightnessFactor,
rawPolicy.advertiseIsEnabled,
rawPolicy.cpuFrequenciesForInteractive,
rawPolicy.cpuFrequenciesForNoninteractive,
rawPolicy.deferFullBackup,
rawPolicy.deferKeyValueBackup,
rawPolicy.disableAnimation,
rawPolicy.disableAod,
rawPolicy.disableLaunchBoost,
rawPolicy.disableOptionalSensors,
// Don't disable vibration when accessibility is on.
rawPolicy.disableVibration && !mAccessibilityEnabled.get(),
rawPolicy.enableAdjustBrightness,
rawPolicy.enableDataSaver,
rawPolicy.enableFirewall,
// Don't force night mode when car projection is enabled.
rawPolicy.enableNightMode && !mAutomotiveProjectionActive.get(),
rawPolicy.enableQuickDoze,
rawPolicy.forceAllAppsStandby,
rawPolicy.forceBackgroundCheck,
locationMode,
rawPolicy.soundTriggerMode
);
// ...
}
// 默认省电模式策略
private Policy mFullPolicy = DEFAULT_FULL_POLICY;
private Policy getCurrentRawPolicyLocked() {
switch (mPolicyLevel) {
case POLICY_LEVEL_FULL:
return mFullPolicy;
case POLICY_LEVEL_ADAPTIVE:
return mAdaptivePolicy;
case POLICY_LEVEL_OFF:
default:
return OFF_POLICY;
}
}
getCurrentRawPolicyLocked() 会获取默认的省电模式策略 DEFAULT_FULL_POLICY,然后根据一些情况调整省电模式策略,最后形成有效的省电模式策略 mEffectivePolicyRaw。
现在让我们看看这个默认的省电策略 DEFAULT_FULL_POLICY 到底是何方神圣
// BatterySaverPolicy.java
private static final Policy DEFAULT_FULL_POLICY = new Policy(
0.5f, /* adjustBrightnessFactor */
true, /* advertiseIsEnabled */
new CpuFrequencies(), /* cpuFrequenciesForInteractive */
new CpuFrequencies(), /* cpuFrequenciesForNoninteractive */
true, /* deferFullBackup */
true, /* deferKeyValueBackup */
false, /* disableAnimation */
true, /* disableAod */
true, /* disableLaunchBoost */
true, /* disableOptionalSensors */
true, /* disableVibration */
false, /* enableAdjustBrightness */
false, /* enableDataSaver */
true, /* enableFirewall */
true, /* enableNightMode */
true, /* enableQuickDoze */
true, /* forceAllAppsStandby */
true, /* forceBackgroundCheck */
PowerManager.LOCATION_MODE_FOREGROUND_ONLY, /* locationMode */
PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY /* soundTriggerMode */
);
Policy 就是一个数据封装类,看下它构造函数的参数,我们就能大致猜测出省电模式影响哪些模块的功能。
这里注意下第三个和第四个参数,它表示省电模式下,需要限制频率的 CPU 的编号以及限制的频率值,这里默认是空,后面会用到。
处理省电模式状态改变
现在让我们回到打开省电模式的代码
// BatterySaverController.java
public void enableBatterySaver(boolean enable, int reason) {
synchronized (mLock) {
if (getFullEnabledLocked() == enable) {
return;
}
// 1. 保存省电模式的状态
setFullEnabledLocked(enable);
// 2. 更新省电模式策略
if (updatePolicyLevelLocked()) {
// 3. 处理省电模式状态的改变
mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
}
}
}
前两步已经分析完毕,现在来看看第三步,它最终会调用 BatterySaverController#handleBatterySaverStateChanged() 来处理省电模式状态改变
// BatterySaverController.java
void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) {
final LowPowerModeListener[] listeners;
final boolean enabled;
// 获取设备是否处于交互状态
// 一般来说,如果屏幕熄灭,设备处于非交互状态,屏幕电量,设备处于交互状态
final boolean isInteractive = getPowerManager().isInteractive();
final ArrayMap<String, String> fileValues;
synchronized (mLock) {
// 获取省电模式的状态
enabled = getFullEnabledLocked() || getAdaptiveEnabledLocked();
// 保存前一个 full battery saver状态
mFullPreviouslyEnabled = getFullEnabledLocked();
// 保存前一个adaptive battery saver状态
mAdaptivePreviouslyEnabled = getAdaptiveEnabledLocked();
listeners = mListeners.toArray(new LowPowerModeListener[0]);
mIsInteractive = isInteractive;
if (enabled) {
// 1. 打开省电模式情况下,获取频率受限的CPU的编号以及受限的值
fileValues = mBatterySaverPolicy.getFileValues(isInteractive);
} else {
fileValues = null;
}
}
// 2. 通过 PowerManagerService 向底层设置省电模式
final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
if (pmi != null) {
pmi.setPowerMode(Mode.LOW_POWER, isEnabled());
}
// 用 BatterySavingStats 记录数据
updateBatterySavingStats();
// 3. 根据策略,限制或恢复CPU频率
if (ArrayUtils.isEmpty(fileValues)) {
// CPU 策略为空,表示需要恢复 CPU 之前的频率
mFileUpdater.restoreDefault();
} else {
// CPU 频率策略不为空,表示需要限制 CPU 频率
mFileUpdater.writeFiles(fileValues);
}
if (sendBroadcast) {
// 4. 发送广播
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
// 可以在 frameworks-res 的配置文件中配置一个应用的包名
// 这个应用可以在manifest.xml中注册广播接收器,接收省电模式状态改变
if (getPowerSaveModeChangedListenerPackage().isPresent()) {
intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)
.setPackage(getPowerSaveModeChangedListenerPackage().get())
.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
| Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
}
// 发送一个内部版本的广播,但是接收者需要权限
intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
Manifest.permission.DEVICE_POWER);
// 5. 通知监听者
for (LowPowerModeListener listener : listeners) {
final PowerSaveState result =
mBatterySaverPolicy.getBatterySaverPolicy(listener.getServiceType());
listener.onLowPowerModeChanged(result);
}
}
}
第一步和第三步,是在省电模式下限制 CPU 频率的。根据前面分析可知,目前默认策略是没有配置CPU频率的,因此这两步不分析了。我将在后面的文章中,分析如何控制省电模式策略,到时候再来分析这里的代码逻辑。
第二步,通过 PowerManagerService 向底层设置省电模式,底层称之为低功耗模式(low power mode)。
第四步,发送省电模式状态改变的广播。
第五步,通知监听者。谁会是监听者呢?当然是那些受省电模式影响的模块。
让我们看下返回给监听者的数据到底是什么?看下mBatterySaverPolicy.getBatterySaverPolicy(listener.getServiceType())
// BatterySaverPolicy.java
public PowerSaveState getBatterySaverPolicy(@ServiceType int type) {
synchronized (mLock) {
final Policy currPolicy = getCurrentPolicyLocked();
final PowerSaveState.Builder builder = new PowerSaveState.Builder()
.setGlobalBatterySaverEnabled(currPolicy.advertiseIsEnabled);
switch (type) {
case ServiceType.LOCATION:
boolean isEnabled = currPolicy.advertiseIsEnabled
|| currPolicy.locationMode != PowerManager.LOCATION_MODE_NO_CHANGE;
return builder.setBatterySaverEnabled(isEnabled)
.setLocationMode(currPolicy.locationMode)
.build();
case ServiceType.ANIMATION:
return builder.setBatterySaverEnabled(currPolicy.disableAnimation)
.build();
// ...
case ServiceType.VIBRATION:
return builder.setBatterySaverEnabled(currPolicy.disableVibration)
.build();
case ServiceType.FORCE_ALL_APPS_STANDBY:
return builder.setBatterySaverEnabled(currPolicy.forceAllAppsStandby)
.build();
case ServiceType.FORCE_BACKGROUND_CHECK:
return builder.setBatterySaverEnabled(currPolicy.forceBackgroundCheck)
.build();
// ...
default:
return builder.setBatterySaverEnabled(currPolicy.advertiseIsEnabled)
.build();
}
}
}
原来,根据监听者的类型,返回一个 PowerSaveState 对象,这个对象中只包含了监听者关心的数据。
从这里,我们应该有所领悟,如果我们自己开发了一个功能模块
- 如果受省电模式策略影响,必须注册一个监听器,获取省电模式下策略,然后调整模块的功能。
- 如果这个模块是个耗电大户,那么必须监听省电模式,在省电模式下执行相应的操作。
现在很多项目都关注电量消耗问题,省电模式到底能让手机待机多长时间,也是一个考核的指标。
battery saver sticky 模式
根据前面的分析,只有在用户手动操作省电模式的时候,才会相应的打开或者关闭 battery saver sticky 模式。
我先总结下什么是 battery saver sticky 模式? 当手机已经处于省电模式,插入电源,系统会默认关闭省电模式,如果此时拔掉电源或者手机重启,当 battery saver sticky 功能已经打开的情况下,系统会重新打开省电模式。
现在让我们从代码角度分析,继续使用上面的例子分析,假如现在已经打开了省电模式,此时插入了电源,来看下状态机的切换动作 BatterySaverStateMachine#updateStateLocked()
//BatterySaverStateMachine.java
private void updateStateLocked(boolean manual, boolean enable) {
if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
return; // Not fully initialized yet.
}
switch (mState) {
case STATE_OFF: {
if (!mIsPowered) { // 充电状态下,不允许打开省电模式
if (manual) { // 手动模式
if (!enable) {
Slog.e(TAG, "Tried to disable BS when it's already OFF");
return;
}
enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
BatterySaverController.REASON_MANUAL_ON);
hideStickyDisabledNotification();
// 1. 用户打开省电模式,状态切换为 STATE_MANUAL_ON
mState = STATE_MANUAL_ON;
} else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) {
// 自动模式 ...
} else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) {
// 动态模式 ...
}
}
break;
}
case STATE_MANUAL_ON: {
if (manual) {
// ...
} else if (mIsPowered) { // 2. 插入电源
// 关闭省电模式
enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
BatterySaverController.REASON_PLUGGED_IN);
// 手动打开省电模式时,mSettingBatterySaverEnabledSticky 设置为 true
// mBatterySaverStickyBehaviourDisabled 默认为 false,表示支持这个 feature
if (mSettingBatterySaverEnabledSticky
&& !mBatterySaverStickyBehaviourDisabled) {
// 插入电源,状态切换为 STATE_PENDING_STICKY_ON
mState = STATE_PENDING_STICKY_ON;
} else {
mState = STATE_OFF;
}
}
break;
}
// ...
case STATE_PENDING_STICKY_ON: { // 3. battery saver sticky 模式操作
if (manual) {
return;
}
// mSettingBatterySaverStickyAutoDisableEnabled 对应 Battery Saver界面下的 Turn off when charging 开关
// mSettingBatterySaverStickyAutoDisableThreshold 默认值为 90
final boolean shouldTurnOffSticky = mSettingBatterySaverStickyAutoDisableEnabled
&& mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold;
// 手动打开省电模式,再插入电源,此时 isStickyDisabled 值为 false
final boolean isStickyDisabled =
mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky;
if (isStickyDisabled || shouldTurnOffSticky) {
// 3.2 如果Turn off when charging 开关被打开,并且电量大于90%,那么不会重新打开省电模式
mState = STATE_OFF;
setStickyActive(false);
triggerStickyDisabledNotification();
} else if (!mIsPowered) {
// Re-enable BS.
// 3.1 断开电源,重新打开省电模式
enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
BatterySaverController.REASON_STICKY_RESTORE);
mState = STATE_MANUAL_ON;
}
break;
}
// ...
}
}
首先看下第一步,它打开了省电模式,并且状态切换为 STATE_MANUAL_ON。
如果此时,插入电源,那么会进入第二步, 关闭省电模式, 并把状态切换为 STATE_PENDING_STICKY_ON。
如果关闭了设置中 Battery Saver 界面的 Turn off when Charging 开关,此时拔掉电源,那么进入 3.1 步,又会再次打开省电模式,这就是 battery saver sticky 功能。
如果打开了设置中 Battery Saver 界面的 Turn off when Charging 开关,并且电量大于 90%, 那么进入 3.2 步,不会再次打开省电模式,这就是 battery saver sticky auto disable 功能。
结束
我通读了整个省电模式的代码,给我的感觉是很多功能都非常鸡肋,限于篇幅原因,我只分析了核心的代码,剩下的其他功能,留给读者自行分析。
下一篇文章,我们来分析下,如何控制省电模式策略。