目录
前言
初识Android PowerManagerService省电模式 让我们省电模式的概念有了初步的认识,
Android PowerManagerService 打开省电模式 对打开省电模式的代码进行了分析。
有了前面两篇文章的基础,现在我们开始分析如何控制省电模式策略,请读者务必仔细。
本文涉及的文件如下:
- frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
- frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
监听策略改变
前两步是监听数据,只不过回调的方式不同,但是最终都是根据数据更新省电模式策略,然后通知监听者。
因此本文只分析其中一个回调 onChange(),而另外一个回调 onPropertiesChanged() 请读者自行分析。
DeviceConfig 就是获取 SettingsProvider 中 Config 表中的数据,这些数据的 KEY 以命名空间开头,然后把所有这些数据封装成一个 DeviceConfig.Properties 对象。
后两步,是主动获取一次数据,然后主动触发一次 onChange() 回调。
Settings.Global.BATTERY_SAVER_CONSTANTS 保存的是与设备无关的省电策略。例如,这个字段的值可以为 vibration_disabled=true,adjust_brightness_factor=0.5
,不同的策略通过逗号进行分隔。从名字可以猜测出,前一个省电策略表示关闭振动,后一个省电策略表示屏幕亮度降低一半。
什么叫与设备无关策略?如果这个省电策略不会因设备不同而不同的话,那这个策略就是与设备无关,反之就是与设备有关策略。
Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS 保存的是与设备相关的省点策略,目前只保存 CPU 限频策略。 这个字段的值可能为 cpufreq-i=core-number:frequency,cpufreq-n=core-number:frequency
,其中 cpufreq-i 表示交互状态下的CPU限频策略,cpufreq-n 表示非交互状态下的CPU限频策略,core-number 表示 CPU 编号,frequency 表示需要限制的频率。交互状态和非交互状态的限频策略以逗号进行分隔。
当然,在省电模式下,不一定只限制一个CPU的频率,我们可以使用 / 来分隔不同的 CPU 限频策略,例如 cpufreq-i=core-number:frequency/core-number:frequency/core-number:frequency
.
通常,亮屏状态下为交互模式,灭屏状态下为非交互模式。
从第三步中可以看出,可以在 framework-res 模块的 config.xml 中配置 CPU 限频策略。记住这里,不要看完了我一系列的省电模式的文章,最终连 CPU 限频策略还不会配置哦!
第四步,会根据这些数据来更新省电模式策略。并且,如果省电模式策略改变了,那么还会执行第五步,通知监听者。
下面,重点分析第四步和第五步。
更新策略
现在,假设 Settings.Global.BATTERY_SAVER_CONSTANTS 和 Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS 保存的数据改变了,那么会调用 updateConstantsLocked() 更新省电模式策略
第二步,根据配置的数据创建一个策略,注意最后一个参数 DEFAULT_FULL_POLICY,它表示默认的省电模式策略
private static Policy fromSettings(String settings, String deviceSpecificSettings,
DeviceConfig.Properties properties, String configSuffix, Policy defaultPolicy) {
final KeyValueListParser parser = new KeyValueListParser(',');
configSuffix = TextUtils.emptyIfNull(configSuffix);
try {
parser.setString(deviceSpecificSettings == null ? "" : deviceSpecificSettings);
} catch (IllegalArgumentException e) {
Slog.wtf(TAG, "Bad device specific battery saver constants: "
+ deviceSpecificSettings);
}
final String cpuFreqInteractive = parser.getString(KEY_CPU_FREQ_INTERACTIVE, "");
final String cpuFreqNoninteractive = parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "");
try {
parser.setString(settings == null ? "" : settings);
} catch (IllegalArgumentException e) {
Slog.wtf(TAG, "Bad battery saver constants: " + settings);
}
final float adjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR,
properties.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR + configSuffix,
defaultPolicy.adjustBrightnessFactor));
final boolean advertiseIsEnabled = parser.getBoolean(KEY_ADVERTISE_IS_ENABLED,
properties.getBoolean(KEY_ADVERTISE_IS_ENABLED + configSuffix,
defaultPolicy.advertiseIsEnabled));
final boolean deferFullBackup = parser.getBoolean(KEY_DEFER_FULL_BACKUP,
properties.getBoolean(KEY_DEFER_FULL_BACKUP + configSuffix,
defaultPolicy.deferFullBackup));
final boolean deferKeyValueBackup = parser.getBoolean(KEY_DEFER_KEYVALUE_BACKUP,
properties.getBoolean(KEY_DEFER_KEYVALUE_BACKUP + configSuffix,
defaultPolicy.deferKeyValueBackup));
final boolean disableAnimation = parser.getBoolean(KEY_DISABLE_ANIMATION,
properties.getBoolean(KEY_DISABLE_ANIMATION + configSuffix,
defaultPolicy.disableAnimation));
final boolean disableAod = parser.getBoolean(KEY_DISABLE_AOD,
properties.getBoolean(KEY_DISABLE_AOD + configSuffix,
defaultPolicy.disableAod));
final boolean disableLaunchBoost = parser.getBoolean(KEY_DISABLE_LAUNCH_BOOST,
properties.getBoolean(KEY_DISABLE_LAUNCH_BOOST + configSuffix,
defaultPolicy.disableLaunchBoost));
final boolean disableOptionalSensors = parser.getBoolean(KEY_DISABLE_OPTIONAL_SENSORS,
properties.getBoolean(KEY_DISABLE_OPTIONAL_SENSORS + configSuffix,
defaultPolicy.disableOptionalSensors));
final boolean disableVibrationConfig = parser.getBoolean(KEY_DISABLE_VIBRATION,
properties.getBoolean(KEY_DISABLE_VIBRATION + configSuffix,
defaultPolicy.disableVibration));
final boolean enableBrightnessAdjustment = parser.getBoolean(
KEY_ENABLE_BRIGHTNESS_ADJUSTMENT,
properties.getBoolean(KEY_ENABLE_BRIGHTNESS_ADJUSTMENT + configSuffix,
defaultPolicy.enableAdjustBrightness));
final boolean enableDataSaver = parser.getBoolean(KEY_ENABLE_DATASAVER,
properties.getBoolean(KEY_ENABLE_DATASAVER + configSuffix,
defaultPolicy.enableDataSaver));
final boolean enableFirewall = parser.getBoolean(KEY_ENABLE_FIREWALL,
properties.getBoolean(KEY_ENABLE_FIREWALL + configSuffix,
defaultPolicy.enableFirewall));
final boolean enableNightMode = parser.getBoolean(KEY_ENABLE_NIGHT_MODE,
properties.getBoolean(KEY_ENABLE_NIGHT_MODE + configSuffix,
defaultPolicy.enableNightMode));
final boolean enableQuickDoze = parser.getBoolean(KEY_ENABLE_QUICK_DOZE,
properties.getBoolean(KEY_ENABLE_QUICK_DOZE + configSuffix,
defaultPolicy.enableQuickDoze));
final boolean forceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY,
properties.getBoolean(KEY_FORCE_ALL_APPS_STANDBY + configSuffix,
defaultPolicy.forceAllAppsStandby));
final boolean forceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK,
properties.getBoolean(KEY_FORCE_BACKGROUND_CHECK + configSuffix,
defaultPolicy.forceBackgroundCheck));
final int locationMode = parser.getInt(KEY_LOCATION_MODE,
properties.getInt(KEY_LOCATION_MODE + configSuffix,
defaultPolicy.locationMode));
final int soundTriggerMode = parser.getInt(KEY_SOUNDTRIGGER_MODE,
properties.getInt(KEY_SOUNDTRIGGER_MODE + configSuffix,
defaultPolicy.soundTriggerMode));
return new Policy(
adjustBrightnessFactor,
advertiseIsEnabled,
(new CpuFrequencies()).parseString(cpuFreqInteractive),
(new CpuFrequencies()).parseString(cpuFreqNoninteractive),
deferFullBackup,
deferKeyValueBackup,
disableAnimation,
disableAod,
disableLaunchBoost,
disableOptionalSensors,
disableVibrationConfig,
enableBrightnessAdjustment,
enableDataSaver,
enableFirewall,
enableNightMode,
enableQuickDoze,
forceAllAppsStandby,
forceBackgroundCheck,
locationMode,
soundTriggerMode
);
}
与设备相关的省电策略,也就是 CPU 限频策略,如果空缺,也不会被任何配置取代。
与设备无关的省电策略,如果某一项空缺,会依次被 DeviceConfig 和 默认的省电策略 DEFAULT_FULL_POLICY 取代。
最终通过解析的数据,创建一个策略 Policy 对象。
新的策略已经创建出来,之后调用 maybeUpdateDefaultFullPolicy() 更新默认的省电策略。
mDefaultFullPolicy 代表的就是默认的省电策略,这里会更新它,但是同时,如果 mFullPolicy 没有被 setFullPolicyLocked() 修改(源码设计中称之为 overridden),那么也会同步更新它。
现在默认的省点策略已经更新,但是要应用的最终策略还不是它,需要调用 updatePolicyDependenciesLocked() 来根据情况,更新一个有效的省点策略
很简单,根据是否是车载项目,以及是否打开无障碍模式,更新有效的省电模式策略 mEffectivePolicyRaw。
通知监听者
现在省电策略已经更新完毕,如果策略改变了,那么需要通知监听者
目前,省电策略的监听者只有一个 BatterySaverController
最终会调用 handleBatterySaverStateChanged()
这段代码,我只分析如何应用省电策略。
第一步,是获取 CPU 限频策略,以一个 Map 表示,其中 KEY 为 CPU 限频的节点路径,VALUE 为被限制的频率。
然后第二步是应用这个 CPU 限频策略,其实就是向节点写值。 不过在写值之前,会先保存节点中原本的值到 /data/system/battery-saver/default-values.xml 文件中,这个文件的作用是,当关闭省电模式,会恢复 CPU 原本的频率。
最后,通知监听者,策略已经改变,你们需要做相应的适配。这些监听者都是系统服务,例如WindowManagerService 就是一个监听者,它会根据省电模式策略,决定是否关闭动画,关键代码如下:
如何配置策略
看完了策略控制的源码分析,总结下如何控制策略
- 修改 Settings.Global.BATTERY_SAVER_CONSTANTS 字段值,可以设置的字参考注释文档,或者参考源码的解析部分。例如
vibration_disabled=true,adjust_brightness_factor=0.5
- 修改 Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS字段值,但是这个只能修改 CPU 限频策略。例如
cpufreq-i=0:1804810/1:1804900,cpufreq-n=0:1804700/1:1804600
。
- 可以通过 framework-res 的 config.xml 的config_batterySaverDeviceSpecificConfig 配置默认的 CPU 限频策略。但是这个会被 Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS 覆盖,在有值的情况下。
结束
省电模式的文章,到此就结束了。本来我还准备分析省电模式影响的功能,但是由于影响的功能有点多,但是我又无法精通所有的功能,因此我就不献丑了去分析了。
在工作中,如果你熟悉的某个功能模块,例如 WindowManagerService,它受省电模式影响,我相信,如果你看完我的文章,应该能自行分析受影响的功能。
到此这篇关于Android PowerManagerService省电模式策略控制的文章就介绍到这了,更多相关Android PowerManagerService 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!