Android PowerManagerService省電模式策略控制
前言
初識Android PowerManagerService省電模式 讓我們省電模式的概念有了初步的認識,
Android PowerManagerService 打開省電模式 對打開省電模式的代碼進行了分析。
有了前面兩篇文章的基礎(chǔ),現(xiàn)在我們開始分析如何控制省電模式策略,請讀者務必仔細。
本文涉及的文件如下:
- frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
- frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
監(jiān)聽策略改變
// BatterySaverPolicy.java
public void systemReady() {
ConcurrentUtils.wtfIfLockHeld(TAG, mLock);
// 1. 監(jiān)聽 Global 數(shù)據(jù)
// 當數(shù)據(jù)改變,回調(diào) onChange()
mContentResolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.BATTERY_SAVER_CONSTANTS), false, this);
mContentResolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS), false, this);
// 無障礙模式相關(guān)
final AccessibilityManager acm = mContext.getSystemService(AccessibilityManager.class);
acm.addAccessibilityStateChangeListener(enabled -> mAccessibilityEnabled.update(enabled));
mAccessibilityEnabled.initialize(acm.isEnabled());
// 車載相關(guān)
UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
uiModeManager.addOnProjectionStateChangedListener(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE,
mContext.getMainExecutor(), mOnProjectionStateChangedListener);
mAutomotiveProjectionActive.initialize(
uiModeManager.getActiveProjectionTypes() != UiModeManager.PROJECTION_TYPE_NONE);
// 2. 監(jiān)聽 Config 表中,命名空間DeviceConfig.NAMESPACE_BATTERY_SAVER下的所有數(shù)據(jù)
// 當數(shù)據(jù)改變時,回調(diào) onPropertiesChanged()
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_BATTERY_SAVER,
mContext.getMainExecutor(), this);
// 3. 讀取 Config 表中,命名空間DeviceConfig.NAMESPACE_BATTERY_SAVER下的所有數(shù)據(jù)
mLastDeviceConfigProperties =
DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BATTERY_SAVER);
// 4. 獲取 Global 表中的數(shù)據(jù),并執(zhí)行更新操作
onChange(true, null);
}前兩步是監(jiān)聽數(shù)據(jù),只不過回調(diào)的方式不同,但是最終都是根據(jù)數(shù)據(jù)更新省電模式策略,然后通知監(jiān)聽者。
因此本文只分析其中一個回調(diào) onChange(),而另外一個回調(diào) onPropertiesChanged() 請讀者自行分析。
DeviceConfig 就是獲取 SettingsProvider 中 Config 表中的數(shù)據(jù),這些數(shù)據(jù)的 KEY 以命名空間開頭,然后把所有這些數(shù)據(jù)封裝成一個 DeviceConfig.Properties 對象。
后兩步,是主動獲取一次數(shù)據(jù),然后主動觸發(fā)一次 onChange() 回調(diào)。
// BatterySaverPolicy.java
public void onChange(boolean selfChange, Uri uri) {
refreshSettings();
}
private void refreshSettings() {
synchronized (mLock) {
// 1. 獲取與設備無關(guān)的省電模式策略
// 例如,vibration_disabled=true,adjust_brightness_factor=0.5
final String setting = getGlobalSetting(Settings.Global.BATTERY_SAVER_CONSTANTS);
// 2. 獲取與設備相關(guān)的省電模式策略
// 格式為, cpufreq-i=core-number:frequency/...,cpufreq-n=core-number:frequency/...
String deviceSpecificSetting = getGlobalSetting(
Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS);
// 保存與設備相關(guān)的省電模式策略的KEY值
mDeviceSpecificSettingsSource =
Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS;
// 3. 如果與設備相關(guān)的省電策略為空,那么加載 framework-res 的 config.xml 中的配置 config_batterySaverDeviceSpecificConfig
if (TextUtils.isEmpty(deviceSpecificSetting) || "null".equals(deviceSpecificSetting)) {
// 配置默認也為空
deviceSpecificSetting =
mContext.getString(getDeviceSpecificConfigResId());
// 表示是從配置文件中配置的
mDeviceSpecificSettingsSource = "(overlay)";
}
// 4. 更新策略
if (!updateConstantsLocked(setting, deviceSpecificSetting)) {
// 沒有變化,就不去執(zhí)行后面的通知監(jiān)聽者的操作
return;
}
}
// 5. 如果策略改變,通知監(jiān)聽者
maybeNotifyListenersOfPolicyChange();
}Settings.Global.BATTERY_SAVER_CONSTANTS 保存的是與設備無關(guān)的省電策略。例如,這個字段的值可以為 vibration_disabled=true,adjust_brightness_factor=0.5,不同的策略通過逗號進行分隔。從名字可以猜測出,前一個省電策略表示關(guān)閉振動,后一個省電策略表示屏幕亮度降低一半。
什么叫與設備無關(guān)策略?如果這個省電策略不會因設備不同而不同的話,那這個策略就是與設備無關(guān),反之就是與設備有關(guān)策略。
Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS 保存的是與設備相關(guān)的省點策略,目前只保存 CPU 限頻策略。 這個字段的值可能為 cpufreq-i=core-number:frequency,cpufreq-n=core-number:frequency,其中 cpufreq-i 表示交互狀態(tài)下的CPU限頻策略,cpufreq-n 表示非交互狀態(tài)下的CPU限頻策略,core-number 表示 CPU 編號,frequency 表示需要限制的頻率。交互狀態(tài)和非交互狀態(tài)的限頻策略以逗號進行分隔。
當然,在省電模式下,不一定只限制一個CPU的頻率,我們可以使用 / 來分隔不同的 CPU 限頻策略,例如 cpufreq-i=core-number:frequency/core-number:frequency/core-number:frequency.
通常,亮屏狀態(tài)下為交互模式,滅屏狀態(tài)下為非交互模式。
從第三步中可以看出,可以在 framework-res 模塊的 config.xml 中配置 CPU 限頻策略。記住這里,不要看完了我一系列的省電模式的文章,最終連 CPU 限頻策略還不會配置哦!
第四步,會根據(jù)這些數(shù)據(jù)來更新省電模式策略。并且,如果省電模式策略改變了,那么還會執(zhí)行第五步,通知監(jiān)聽者。
下面,重點分析第四步和第五步。
更新策略
現(xiàn)在,假設 Settings.Global.BATTERY_SAVER_CONSTANTS 和 Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS 保存的數(shù)據(jù)改變了,那么會調(diào)用 updateConstantsLocked() 更新省電模式策略
// BatterySaverPolicy.java
boolean updateConstantsLocked(String setting, String deviceSpecificSetting) {
// 如果是null,返回""
setting = TextUtils.emptyIfNull(setting);
deviceSpecificSetting = TextUtils.emptyIfNull(deviceSpecificSetting);
// 沒有變化,直接返回
if (setting.equals(mSettings)
&& deviceSpecificSetting.equals(mDeviceSpecificSettings)) {
return false;
}
// 1. 保存設置
mSettings = setting;
mDeviceSpecificSettings = deviceSpecificSetting;
// 2. 根據(jù)配置,創(chuàng)建新的策略
Poilcy p = Policy.fromSettings(setting, deviceSpecificSetting, mLastDeviceConfigProperties, null, DEFAULT_FULL_POLICY);
// 3. 更新默認的省電模式策略
boolean changed = maybeUpdateDefaultFullPolicy(p);
// 忽略 adaptive battery save 功能
mDefaultAdaptivePolicy = Policy.fromSettings("", "",
mLastDeviceConfigProperties, KEY_SUFFIX_ADAPTIVE, DEFAULT_ADAPTIVE_POLICY);
if (mPolicyLevel == POLICY_LEVEL_ADAPTIVE
&& !mAdaptivePolicy.equals(mDefaultAdaptivePolicy)) {
// adaptive policy changed
changed = true;
}
mAdaptivePolicy = mDefaultAdaptivePolicy;
// 4. 更新有效的省電模式策略
updatePolicyDependenciesLocked();
// 5. 返回狀態(tài),表示省電模式策略是否改變
return changed;
}第二步,根據(jù)配置的數(shù)據(jù)創(chuàng)建一個策略,注意最后一個參數(shù) DEFAULT_FULL_POLICY,它表示默認的省電模式策略
// BatterySaverPolicy.java
private static Policy fromSettings(String settings, String deviceSpecificSettings,
DeviceConfig.Properties properties, String configSuffix, Policy defaultPolicy) {
// 以逗號為分隔符解析字符串
final KeyValueListParser parser = new KeyValueListParser(',');
configSuffix = TextUtils.emptyIfNull(configSuffix);
// 1. 首先解析設備相關(guān)的策略參數(shù)
try {
parser.setString(deviceSpecificSettings == null ? "" : deviceSpecificSettings);
} catch (IllegalArgumentException e) {
Slog.wtf(TAG, "Bad device specific battery saver constants: "
+ deviceSpecificSettings);
}
// 讀取的值的格式為 core-number:frequency/core-number:frequency/...
final String cpuFreqInteractive = parser.getString(KEY_CPU_FREQ_INTERACTIVE, "");
final String cpuFreqNoninteractive = parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "");
// 2. 再解析設備無關(guān)的策略參數(shù)
try {
parser.setString(settings == null ? "" : settings);
} catch (IllegalArgumentException e) {
Slog.wtf(TAG, "Bad battery saver constants: " + settings);
}
// 策略參數(shù)取值的優(yōu)先級為: Settings > DeviceConfig > 默認省電策略
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));
// 3. 創(chuàng)建一個新的策略
return new Policy(
adjustBrightnessFactor,
advertiseIsEnabled,
(new CpuFrequencies()).parseString(cpuFreqInteractive),
(new CpuFrequencies()).parseString(cpuFreqNoninteractive),
deferFullBackup,
deferKeyValueBackup,
disableAnimation,
disableAod,
disableLaunchBoost,
disableOptionalSensors,
/* disableVibration */
disableVibrationConfig,
enableBrightnessAdjustment,
enableDataSaver,
enableFirewall,
enableNightMode,
enableQuickDoze,
forceAllAppsStandby,
forceBackgroundCheck,
locationMode,
soundTriggerMode
);
}與設備相關(guān)的省電策略,也就是 CPU 限頻策略,如果空缺,也不會被任何配置取代。
與設備無關(guān)的省電策略,如果某一項空缺,會依次被 DeviceConfig 和 默認的省電策略 DEFAULT_FULL_POLICY 取代。
最終通過解析的數(shù)據(jù),創(chuàng)建一個策略 Policy 對象。
新的策略已經(jīng)創(chuàng)建出來,之后調(diào)用 maybeUpdateDefaultFullPolicy() 更新默認的省電策略。
// BatterySaverPolicy.java
private boolean maybeUpdateDefaultFullPolicy(Policy p) {
boolean fullPolicyChanged = false;
if (!mDefaultFullPolicy.equals(p)) {
// mFullPolicy 會被 setFullPolicyLocked() 修改
// 如果 mFullPolicy 與 mDefaultFullPolicy 不同, 那么表示 mFullPolicy 被覆蓋
// 如果相同,表示沒有被覆蓋
boolean isDefaultFullPolicyOverridden = !mDefaultFullPolicy.equals(mFullPolicy);
if (!isDefaultFullPolicyOverridden) {
// mFullPolicy 沒有被覆蓋,就要同步進行更新
mFullPolicy = p;
// 現(xiàn)在處于省電模式中,需要通知監(jiān)聽者
fullPolicyChanged = (mPolicyLevel == POLICY_LEVEL_FULL);
}
// 更新默認的省電模式策略
mDefaultFullPolicy = p;
}
return fullPolicyChanged;
}mDefaultFullPolicy 代表的就是默認的省電策略,這里會更新它,但是同時,如果 mFullPolicy 沒有被 setFullPolicyLocked() 修改(源碼設計中稱之為 overridden),那么也會同步更新它。
現(xiàn)在默認的省點策略已經(jīng)更新,但是要應用的最終策略還不是它,需要調(diào)用 updatePolicyDependenciesLocked() 來根據(jù)情況,更新一個有效的省點策略
// BatterySaverPolicy.java
private void updatePolicyDependenciesLocked() {
final Policy rawPolicy = getCurrentRawPolicyLocked();
final int locationMode;
invalidatePowerSaveModeCaches();
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;
}
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
);
// ...
}很簡單,根據(jù)是否是車載項目,以及是否打開無障礙模式,更新有效的省電模式策略 mEffectivePolicyRaw。
通知監(jiān)聽者
現(xiàn)在省電策略已經(jīng)更新完畢,如果策略改變了,那么需要通知監(jiān)聽者
// BatterySaverPolicy.java
private void maybeNotifyListenersOfPolicyChange() {
final BatterySaverPolicyListener[] listeners;
synchronized (mLock) {
if (mPolicyLevel == POLICY_LEVEL_OFF) {
// 省電模式?jīng)]有打開
return;
}
// Don't call out to listeners with the lock held.
listeners = mListeners.toArray(new BatterySaverPolicyListener[mListeners.size()]);
}
mHandler.post(() -> {
for (BatterySaverPolicyListener listener : listeners) {
// 通知監(jiān)聽者
listener.onBatterySaverPolicyChanged(this);
}
});
}目前,省電策略的監(jiān)聽者只有一個 BatterySaverController
// BatterySaverController.java
public void onBatterySaverPolicyChanged(BatterySaverPolicy policy) {
if (!isPolicyEnabled()) {
return; // No need to send it if not enabled.
}
mHandler.postStateChanged(/*sendBroadcast=*/ true, REASON_POLICY_CHANGED);
}最終會調(diào)用 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();
mFullPreviouslyEnabled = getFullEnabledLocked();
mAdaptivePreviouslyEnabled = getAdaptiveEnabledLocked();
listeners = mListeners.toArray(new LowPowerModeListener[0]);
mIsInteractive = isInteractive;
// 1. 獲取CPU限頻策略
if (enabled) {
fileValues = mBatterySaverPolicy.getFileValues(isInteractive);
} else {
fileValues = null;
}
}
final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
if (pmi != null) {
pmi.setPowerMode(Mode.LOW_POWER, isEnabled());
}
updateBatterySavingStats();
// 2. 應用CPU限頻策略
if (ArrayUtils.isEmpty(fileValues)) {
// 如果策略為空,那肯定是關(guān)閉了省電模式,此時需要恢復正常的CPU頻率
mFileUpdater.restoreDefault();
} else {
// 策略不為空,首先保存節(jié)點中原本的值到 /data/system/battery-saver/default-values.xml,然后向節(jié)點寫值
mFileUpdater.writeFiles(fileValues);
}
if (sendBroadcast) {
// 3. 發(fā)送廣播
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
// Send the broadcast to a manifest-registered receiver that is specified in the config.
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);
}
// Send internal version that requires signature permission.
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);
// 4. 通知監(jiān)聽者,省電策略已經(jīng)改變
for (LowPowerModeListener listener : listeners) {
final PowerSaveState result =
mBatterySaverPolicy.getBatterySaverPolicy(listener.getServiceType());
listener.onLowPowerModeChanged(result);
}
}
}這段代碼,我只分析如何應用省電策略。
第一步,是獲取 CPU 限頻策略,以一個 Map 表示,其中 KEY 為 CPU 限頻的節(jié)點路徑,VALUE 為被限制的頻率。
然后第二步是應用這個 CPU 限頻策略,其實就是向節(jié)點寫值。 不過在寫值之前,會先保存節(jié)點中原本的值到 /data/system/battery-saver/default-values.xml 文件中,這個文件的作用是,當關(guān)閉省電模式,會恢復 CPU 原本的頻率。
最后,通知監(jiān)聽者,策略已經(jīng)改變,你們需要做相應的適配。這些監(jiān)聽者都是系統(tǒng)服務,例如WindowManagerService 就是一個監(jiān)聽者,它會根據(jù)省電模式策略,決定是否關(guān)閉動畫,關(guān)鍵代碼如下:
case NEW_ANIMATOR_SCALE: {
// 省電模式下,scale 為 0
float scale = getCurrentAnimatorScale();
// 關(guān)閉 system_server 進程的動畫
ValueAnimator.setDurationScale(scale);
Session session = (Session)msg.obj;
if (session != null) {
try {
session.mCallback.onAnimatorScaleChanged(scale);
} catch (RemoteException e) {
}
} else {
ArrayList<IWindowSessionCallback> callbacks
= new ArrayList<IWindowSessionCallback>();
synchronized (mGlobalLock) {
for (int i=0; i<mSessions.size(); i++) {
callbacks.add(mSessions.valueAt(i).mCallback);
}
}
for (int i=0; i<callbacks.size(); i++) {
try {
// 關(guān)閉 app 進程的動畫
callbacks.get(i).onAnimatorScaleChanged(scale);
} catch (RemoteException e) {
}
}
}
break;
}如何配置策略
看完了策略控制的源碼分析,總結(jié)下如何控制策略
- 修改 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 覆蓋,在有值的情況下。
結(jié)束
省電模式的文章,到此就結(jié)束了。本來我還準備分析省電模式影響的功能,但是由于影響的功能有點多,但是我又無法精通所有的功能,因此我就不獻丑了去分析了。
在工作中,如果你熟悉的某個功能模塊,例如 WindowManagerService,它受省電模式影響,我相信,如果你看完我的文章,應該能自行分析受影響的功能。
到此這篇關(guān)于Android PowerManagerService省電模式策略控制的文章就介紹到這了,更多相關(guān)Android PowerManagerService 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android開發(fā)Kotlin語言協(xié)程中的并發(fā)問題和互斥鎖
Android開發(fā)Kotlin語言提供了多種機制來處理并發(fā)和同步,其中包括高層次和低層次的工具,對于常規(guī)的并發(fā)任務,可以利用 Kotlin 協(xié)程提供的結(jié)構(gòu)化并發(fā)方式,而對于需要更低層次的鎖定機制,可以使用Mutex(互斥鎖)來實現(xiàn)對共享資源的線程安全訪問2024-06-06
Android中RecyclerView實現(xiàn)分頁滾動的方法詳解
RecyclerView實現(xiàn)滾動相信對大家來說都不陌生,但是本文主要給大家介紹了利用Android中RecyclerView實現(xiàn)分頁滾動的思路和方法,可以實現(xiàn)翻頁功能,一次翻一頁,也可以實現(xiàn)翻至某一頁功能。文中給出了詳細的示例代碼,需要的朋友可以參考借鑒,下面來一起看看吧。2017-04-04
Android RecyclerView多類型布局卡片解決方案
這篇文章主要介紹了Android RecyclerView多類型布局卡片解決方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03

