Preface
Getting started with Android PowerManagerService Power Saving ModeLet us have a preliminary understanding of the concept of power saving mode.
Android PowerManagerService Turn on power saving modeThe code that turns on power saving mode was analyzed.
With the basis of the previous two articles, we are now beginning to analyze how to control the power saving mode strategy. Please be careful.
The documents involved in this article are as follows:
- frameworks/base/services/core/java/com/android/server/power/batterysaver/
- frameworks/base/services/core/java/com/android/server/power/batterysaver/
Listening policy changes
// public void systemReady() { (TAG, mLock); // 1. Listen to Global data // When the data changes, callback onChange() (( .BATTERY_SAVER_CONSTANTS), false, this); (( .BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS), false, this); // Accessibility mode related final AccessibilityManager acm = (); (enabled -> (enabled)); (()); // Car related UiModeManager uiModeManager = (); (UiModeManager.PROJECTION_TYPE_AUTOMOTIVE, (), mOnProjectionStateChangedListener); ( () != UiModeManager.PROJECTION_TYPE_NONE); // 2. Listen to all data under the namespace DeviceConfig.NAMESPACE_BATTERY_SAVER in the Config table // When the data changes, callback onPropertiesChanged() (DeviceConfig.NAMESPACE_BATTERY_SAVER, (), this); // 3. Read all data under the namespace DeviceConfig.NAMESPACE_BATTERY_SAVER in the Config table mLastDeviceConfigProperties = (DeviceConfig.NAMESPACE_BATTERY_SAVER); // 4. Get the data in the Global table and perform the update operation onChange(true, null); }
The first two steps are to monitor the data, but the callback methods are different, but in the end, they are updated according to the data and then notified the listener.
Therefore, this article only analyzes one of the callbacks.onChange(), and another callbackonPropertiesChanged()Please analyze it yourself.
DeviceConfig is to getSettingsProviderThe data in the Config table, the KEY of these data starts with the namespace, and then encapsulate all of this data into oneObject.
The last two steps are to actively obtain data once and then trigger it once.onChange()Callback.
// public void onChange(boolean selfChange, Uri uri) { refreshSettings(); } private void refreshSettings() { synchronized (mLock) { // 1. Obtain the power saving mode policy that is independent of the device // For example, vibration_disabled=true,adjust_brightness_factor=0.5 final String setting = getGlobalSetting(.BATTERY_SAVER_CONSTANTS); // 2. Obtain the power saving mode strategy related to the device // The format is, cpufreq-i=core-number:frequency/...,cpufreq-n=core-number:frequency/... String deviceSpecificSetting = getGlobalSetting( .BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS); // Save the KEY value of the power saving mode strategy related to the device mDeviceSpecificSettingsSource = .BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS; // 3. If the power saving policy related to the device is empty, then the configuration in the framework-res loaded config_batterySaverDeviceSpecificConfig if ((deviceSpecificSetting) || "null".equals(deviceSpecificSetting)) { // The configuration is also empty by default deviceSpecificSetting = (getDeviceSpecificConfigResId()); // means it is configured from the configuration file mDeviceSpecificSettingsSource = "(overlay)"; } // 4. Update policy if (!updateConstantsLocked(setting, deviceSpecificSetting)) { // No changes will be made, so the following operations to notify the listener will not be executed return; } } // 5. If the policy changes, notify the listener maybeNotifyListenersOfPolicyChange(); }
.BATTERY_SAVER_CONSTANTSWhat is saved is a power saving strategy that is not related to the device. For example, the value of this field can bevibration_disabled=true,adjust_brightness_factor=0.5
, different strategies are separated by commas. From the name, we can guess that the previous power saving strategy means turning off vibration, and the latter power saving strategy means the screen brightness is reduced by half.
What is a device-independent strategy? If this power saving strategy does not vary depending on the device, then this strategy is not related to the device, but the device-related strategy is not related to the device.
.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTSWhat is saved is a point-saving strategy related to the device, and currently only the CPU frequency limiting strategy is saved. The value of this field may becpufreq-i=core-number:frequency,cpufreq-n=core-number:frequency
,incpufreq-iIndicates the CPU frequency limiting strategy in interactive state,cpufreq-nRepresents the CPU frequency limiting strategy in non-interactive state.core-numberIndicates CPU number,frequencyIndicates the frequency to which it needs to be limited. The frequency limiting strategies for interactive and non-interactive states are separated by commas.
Of course, in power saving mode, it does not necessarily limit the frequency of only one CPU, we can use/To separate different CPU frequency limiting strategies, such ascpufreq-i=core-number:frequency/core-number:frequency/core-number:frequency
.
Usually, the interactive mode is in the light screen state and the non-interactive mode is in the shutdown state.
As can be seen from the third step, it can beframework-resModularConfigure the CPU frequency limiting policy. Remember here, don’t read my series of power saving mode articles. In the end, the CPU frequency limiting strategy will not be configured!
The fourth step is to update the power saving mode strategy based on these data. Moreover, if the power saving mode strategy changes, then the fifth step will be performed to notify the listener.
Below, focus on the analysis of steps 4 and 5.
Update policy
Now, assuming.BATTERY_SAVER_CONSTANTSand.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS The saved data has changed,Then it will be called updateConstantsLocked()Update power saving mode strategy
// boolean updateConstantsLocked(String setting, String deviceSpecificSetting) { // If it is null, return "" setting = (setting); deviceSpecificSetting = (deviceSpecificSetting); // No changes, return directly if ((mSettings) && (mDeviceSpecificSettings)) { return false; } // 1. Save settings mSettings = setting; mDeviceSpecificSettings = deviceSpecificSetting; // 2. Create a new policy according to the configuration Poilcy p = (setting, deviceSpecificSetting, mLastDeviceConfigProperties, null, DEFAULT_FULL_POLICY); // 3. Update the default power saving mode policy boolean changed = maybeUpdateDefaultFullPolicy(p); // Ignore adaptive battery save function mDefaultAdaptivePolicy = ("", "", mLastDeviceConfigProperties, KEY_SUFFIX_ADAPTIVE, DEFAULT_ADAPTIVE_POLICY); if (mPolicyLevel == POLICY_LEVEL_ADAPTIVE && !(mDefaultAdaptivePolicy)) { // adaptive policy changed changed = true; } mAdaptivePolicy = mDefaultAdaptivePolicy; // 4. Update effective power saving mode strategy updatePolicyDependenciesLocked(); // 5. Return to the status, indicating whether the power saving mode policy has changed return changed; }
The second step is to create a policy based on the configured data and pay attention to the last parameter.DEFAULT_FULL_POLICY, which represents the default power saving mode policy
// private static Policy fromSettings(String settings, String deviceSpecificSettings, properties, String configSuffix, Policy defaultPolicy) { // parse strings with commas as delimiter final KeyValueListParser parser = new KeyValueListParser(','); configSuffix = (configSuffix); // 1. First analyze the device-related policy parameters try { (deviceSpecificSettings == null ? "" : deviceSpecificSettings); } catch (IllegalArgumentException e) { (TAG, "Bad device specific battery saver constants: " + deviceSpecificSettings); } // The format of the read value is core-number:frequency/core-number:frequency/... final String cpuFreqInteractive = (KEY_CPU_FREQ_INTERACTIVE, ""); final String cpuFreqNoninteractive = (KEY_CPU_FREQ_NONINTERACTIVE, ""); // 2. Re-parse device-independent policy parameters try { (settings == null ? "" : settings); } catch (IllegalArgumentException e) { (TAG, "Bad battery saver constants: " + settings); } // The priority of the policy parameter value is: Settings > DeviceConfig > Default power saving policy final float adjustBrightnessFactor = (KEY_ADJUST_BRIGHTNESS_FACTOR, (KEY_ADJUST_BRIGHTNESS_FACTOR + configSuffix, )); final boolean advertiseIsEnabled = (KEY_ADVERTISE_IS_ENABLED, (KEY_ADVERTISE_IS_ENABLED + configSuffix, )); final boolean deferFullBackup = (KEY_DEFER_FULL_BACKUP, (KEY_DEFER_FULL_BACKUP + configSuffix, )); final boolean deferKeyValueBackup = (KEY_DEFER_KEYVALUE_BACKUP, (KEY_DEFER_KEYVALUE_BACKUP + configSuffix, )); final boolean disableAnimation = (KEY_DISABLE_ANIMATION, (KEY_DISABLE_ANIMATION + configSuffix, )); final boolean disableAod = (KEY_DISABLE_AOD, (KEY_DISABLE_AOD + configSuffix, )); final boolean disableLaunchBoost = (KEY_DISABLE_LAUNCH_BOOST, (KEY_DISABLE_LAUNCH_BOOST + configSuffix, )); final boolean disableOptionalSensors = (KEY_DISABLE_OPTIONAL_SENSORS, (KEY_DISABLE_OPTIONAL_SENSORS + configSuffix, )); final boolean disableVibrationConfig = (KEY_DISABLE_VIBRATION, (KEY_DISABLE_VIBRATION + configSuffix, )); final boolean enableBrightnessAdjustment = ( KEY_ENABLE_BRIGHTNESS_ADJUSTMENT, (KEY_ENABLE_BRIGHTNESS_ADJUSTMENT + configSuffix, )); final boolean enableDataSaver = (KEY_ENABLE_DATASAVER, (KEY_ENABLE_DATASAVER + configSuffix, )); final boolean enableFirewall = (KEY_ENABLE_FIREWALL, (KEY_ENABLE_FIREWALL + configSuffix, )); final boolean enableNightMode = (KEY_ENABLE_NIGHT_MODE, (KEY_ENABLE_NIGHT_MODE + configSuffix, )); final boolean enableQuickDoze = (KEY_ENABLE_QUICK_DOZE, (KEY_ENABLE_QUICK_DOZE + configSuffix, )); final boolean forceAllAppsStandby = (KEY_FORCE_ALL_APPS_STANDBY, (KEY_FORCE_ALL_APPS_STANDBY + configSuffix, )); final boolean forceBackgroundCheck = (KEY_FORCE_BACKGROUND_CHECK, (KEY_FORCE_BACKGROUND_CHECK + configSuffix, )); final int locationMode = (KEY_LOCATION_MODE, (KEY_LOCATION_MODE + configSuffix, )); final int soundTriggerMode = (KEY_SOUNDTRIGGER_MODE, (KEY_SOUNDTRIGGER_MODE + configSuffix, )); // 3. Create a new policy 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 ); }
The power saving strategy related to the device, that is, the CPU frequency limiting strategy, will not be replaced by any configuration if it is vacant.
Power saving strategies that are not related to the equipment, if a certain vacancy is vacant, they will be successivelyDeviceConfigand the default power saving strategyDEFAULT_FULL_POLICYReplace.
Finally, through the parsed data, create a strategyPolicyObject.
A new policy has been created and then calledmaybeUpdateDefaultFullPolicy()Update the default power saving strategy.
// private boolean maybeUpdateDefaultFullPolicy(Policy p) { boolean fullPolicyChanged = false; if (!(p)) { // mFullPolicy will be modified by setFullPolicyLocked() // If mFullPolicy is different from mDefaultFullPolicy, then mFullPolicy is overwritten // If the same means that it is not overwritten boolean isDefaultFullPolicyOverridden = !(mFullPolicy); if (!isDefaultFullPolicyOverridden) { // mFullPolicy is not overwritten, so it needs to be updated synchronously mFullPolicy = p; // Now in power saving mode, you need to notify the listener fullPolicyChanged = (mPolicyLevel == POLICY_LEVEL_FULL); } // Update the default power saving mode policy mDefaultFullPolicy = p; } return fullPolicyChanged; }
mDefaultFullPolicyIt represents the default power saving strategy, and it will be updated here, but at the same time, ifmFullPolicyNot beingsetFullPolicyLocked()Modify (called overridden in source code design), and then it will be updated simultaneously.
The default point-saving policy has been updated now, but the final strategy to be applied is not it, and it needs to be calledupdatePolicyDependenciesLocked()To update an effective point-saving strategy based on the situation
// private void updatePolicyDependenciesLocked() { final Policy rawPolicy = getCurrentRawPolicyLocked(); final int locationMode; invalidatePowerSaveModeCaches(); if (() && != PowerManager.LOCATION_MODE_NO_CHANGE && != PowerManager.LOCATION_MODE_FOREGROUND_ONLY) { // If car projection is enabled, ensure that navigation works. locationMode = PowerManager.LOCATION_MODE_FOREGROUND_ONLY; } else { locationMode = ; } mEffectivePolicyRaw = new Policy( , , , , , , , , , , // Don't disable vibration when accessibility is on. && !(), , , , // Don't force night mode when car projection is enabled. && !(), , , , locationMode, ); // ... }
It's very simple. Update the effective power saving mode strategy based on whether it is an on-board project and whether it is a barrier-free mode.mEffectivePolicyRaw。
Notify the listener
Now the power saving strategy has been updated. If the policy has changed, the listener needs to be notified.
// private void maybeNotifyListenersOfPolicyChange() { final BatterySaverPolicyListener[] listeners; synchronized (mLock) { if (mPolicyLevel == POLICY_LEVEL_OFF) { // Power saving mode is not turned on return; } // Don't call out to listeners with the lock held. listeners = (new BatterySaverPolicyListener[()]); } (() -> { for (BatterySaverPolicyListener listener : listeners) { // Notify the listener (this); } }); }
At present, there is only one monitor for power saving strategyBatterySaverController
// public void onBatterySaverPolicyChanged(BatterySaverPolicy policy) { if (!isPolicyEnabled()) { return; // No need to send it if not enabled. } (/*sendBroadcast=*/ true, REASON_POLICY_CHANGED); }
Will call it eventuallyhandleBatterySaverStateChanged()
// 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 = (new LowPowerModeListener[0]); mIsInteractive = isInteractive; // 1. Obtain the CPU frequency limiting policy if (enabled) { fileValues = (isInteractive); } else { fileValues = null; } } final PowerManagerInternal pmi = (); if (pmi != null) { (Mode.LOW_POWER, isEnabled()); } updateBatterySavingStats(); // 2. Apply CPU frequency limiting strategy if ((fileValues)) { // If the policy is empty, it must be turned off the power saving mode. At this time, you need to restore the normal CPU frequency. (); } else { // The policy is not empty. First save the original value in the node to /data/system/battery-saver/, and then write the value to the node. (fileValues); } if (sendBroadcast) { // 3. Send broadcast Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); (Intent.FLAG_RECEIVER_REGISTERED_ONLY); (intent, ); // 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); (intent, ); } // Send internal version that requires signature permission. intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL); (Intent.FLAG_RECEIVER_REGISTERED_ONLY); (intent, , .DEVICE_POWER); // 4. Notify the monitor that the power saving strategy has changed for (LowPowerModeListener listener : listeners) { final PowerSaveState result = (()); (result); } } }
In this code, I only analyze how to apply power saving strategies.
The first step is to obtain the CPU frequency limiting strategy, representing it as a Map, where KEY is the node path for the CPU frequency limiting and VALUE is the limited frequency.
Then the second step is to apply this CPU frequency limiting strategy, which is actually writing values to the node. However, before writing the value, the original value in the node will be saved first./data/system/battery-saver/In the file, the function of this file is that when power saving mode is turned off, the original CPU frequency will be restored.
Finally, notify the listener that the strategy has changed and you need to adapt accordingly. These listeners are system services, e.g.WindowManagerServiceIt is a monitor, which will decide whether to turn off the animation based on the power saving mode strategy.The key code is as follows:
case NEW_ANIMATOR_SCALE: { // In power saving mode, scale is 0 float scale = getCurrentAnimatorScale(); // Close the animation of the system_server process (scale); Session session = (Session); if (session != null) { try { (scale); } catch (RemoteException e) { } } else { ArrayList<IWindowSessionCallback> callbacks = new ArrayList<IWindowSessionCallback>(); synchronized (mGlobalLock) { for (int i=0; i<(); i++) { ((i).mCallback); } } for (int i=0; i<(); i++) { try { // Close the animation of the app process (i).onAnimatorScaleChanged(scale); } catch (RemoteException e) { } } } break; }
How to configure policies
After reading the source code analysis of strategy control, we will summarize how to control the strategy
- Revise.BATTERY_SAVER_CONSTANTSField value, the word you can set refers to the comment document, or refer to the parsing part of the source code. For example
vibration_disabled=true,adjust_brightness_factor=0.5
- Revise.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTSField value, but this can only modify the CPU frequency limiting policy. For example
cpufreq-i=0:1804810/1:1804900,cpufreq-n=0:1804700/1:1804600
。 - Can be passedframework-resofofconfig_batterySaverDeviceSpecificConfigConfigure the default CPU frequency limiting policy. But this will be.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTScover, in case of value.
Finish
The article on power saving mode is over here. I was originally planning to analyze the functions affected by the power saving mode, but since there are a lot of functions affected, I cannot master all the functions, so I will not be ugly to analyze them.
At work, if you are familiar with a functional module, for exampleWindowManagerService, It is affected by the power saving mode, I believe that if you read my article, you should be able to analyze the affected functions by yourself.
This is the article about the policy control of Android PowerManagerService power saving mode. For more related content on Android PowerManagerService, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!