Android PowerManagerService省电模式策略控制

作者:大胃粥 时间:2023-11-25 02:46:53 

前言

初识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

监听策略改变

// BatterySaverPolicy.java

public void systemReady() {
       ConcurrentUtils.wtfIfLockHeld(TAG, mLock);

// 1. 监听 Global 数据
       // 当数据改变,回调 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);

// 无障碍模式相关
       final AccessibilityManager acm = mContext.getSystemService(AccessibilityManager.class);
       acm.addAccessibilityStateChangeListener(enabled -> mAccessibilityEnabled.update(enabled));
       mAccessibilityEnabled.initialize(acm.isEnabled());

// 车载相关
       UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
       uiModeManager.addOnProjectionStateChangedListener(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE,
               mContext.getMainExecutor(), mOnProjectionStateChangedListener);
       mAutomotiveProjectionActive.initialize(
               uiModeManager.getActiveProjectionTypes() != UiModeManager.PROJECTION_TYPE_NONE);

// 2. 监听 Config 表中,命名空间DeviceConfig.NAMESPACE_BATTERY_SAVER下的所有数据
       // 当数据改变时,回调 onPropertiesChanged()
       DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_BATTERY_SAVER,
               mContext.getMainExecutor(), this);

// 3. 读取 Config 表中,命名空间DeviceConfig.NAMESPACE_BATTERY_SAVER下的所有数据
       mLastDeviceConfigProperties =
               DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BATTERY_SAVER);

// 4. 获取 Global 表中的数据,并执行更新操作
       onChange(true, null);
   }

前两步是监听数据,只不过回调的方式不同,但是最终都是根据数据更新省电模式策略,然后通知监听者。

因此本文只分析其中一个回调 onChange(),而另外一个回调 onPropertiesChanged() 请读者自行分析。

DeviceConfig 就是获取 SettingsProvider 中 Config 表中的数据,这些数据的 KEY 以命名空间开头,然后把所有这些数据封装成一个 DeviceConfig.Properties 对象。

后两步,是主动获取一次数据,然后主动触发一次 onChange() 回调。

// BatterySaverPolicy.java

public void onChange(boolean selfChange, Uri uri) {
       refreshSettings();
   }
   private void refreshSettings() {
       synchronized (mLock) {
           // 1. 获取与设备无关的省电模式策略
           // 例如,vibration_disabled=true,adjust_brightness_factor=0.5
           final String setting = getGlobalSetting(Settings.Global.BATTERY_SAVER_CONSTANTS);

// 2. 获取与设备相关的省电模式策略
           // 格式为, cpufreq-i=core-number:frequency/...,cpufreq-n=core-number:frequency/...
           String deviceSpecificSetting = getGlobalSetting(
                   Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS);

// 保存与设备相关的省电模式策略的KEY值
           mDeviceSpecificSettingsSource =
                   Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS;

// 3. 如果与设备相关的省电策略为空,那么加载 framework-res 的 config.xml 中的配置 config_batterySaverDeviceSpecificConfig
           if (TextUtils.isEmpty(deviceSpecificSetting) || "null".equals(deviceSpecificSetting)) {
               // 配置默认也为空
               deviceSpecificSetting =
                       mContext.getString(getDeviceSpecificConfigResId());
               // 表示是从配置文件中配置的
               mDeviceSpecificSettingsSource = "(overlay)";
           }

// 4. 更新策略
           if (!updateConstantsLocked(setting, deviceSpecificSetting)) {
               // 没有变化,就不去执行后面的通知监听者的操作
               return;
           }
       }

// 5. 如果策略改变,通知监听者
       maybeNotifyListenersOfPolicyChange();
   }

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() 更新省电模式策略

// 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. 根据配置,创建新的策略
       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. 返回状态,表示省电模式策略是否改变
       return changed;
   }

第二步,根据配置的数据创建一个策略,注意最后一个参数 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. 首先解析设备相关的策略参数
           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. 再解析设备无关的策略参数
           try {
               parser.setString(settings == null ? "" : settings);
           } catch (IllegalArgumentException e) {
               Slog.wtf(TAG, "Bad battery saver constants: " + settings);
           }

// 策略参数取值的优先级为: 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. 创建一个新的策略
           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
           );
       }

与设备相关的省电策略,也就是 CPU 限频策略,如果空缺,也不会被任何配置取代。

与设备无关的省电策略,如果某一项空缺,会依次被 DeviceConfig 和 默认的省电策略 DEFAULT_FULL_POLICY 取代。

最终通过解析的数据,创建一个策略 Policy 对象。

新的策略已经创建出来,之后调用 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;
               // 现在处于省电模式中,需要通知监听者
               fullPolicyChanged = (mPolicyLevel == POLICY_LEVEL_FULL);
           }
           // 更新默认的省电模式策略
           mDefaultFullPolicy = p;
       }

return fullPolicyChanged;
   }

mDefaultFullPolicy 代表的就是默认的省电策略,这里会更新它,但是同时,如果 mFullPolicy 没有被 setFullPolicyLocked() 修改(源码设计中称之为 overridden),那么也会同步更新它。

现在默认的省点策略已经更新,但是要应用的最终策略还不是它,需要调用 updatePolicyDependenciesLocked() 来根据情况,更新一个有效的省点策略

// 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
       );
       // ...
   }

很简单,根据是否是车载项目,以及是否打开无障碍模式,更新有效的省电模式策略 mEffectivePolicyRaw

通知监听者

现在省电策略已经更新完毕,如果策略改变了,那么需要通知监听者

// BatterySaverPolicy.java

private void maybeNotifyListenersOfPolicyChange() {
       final BatterySaverPolicyListener[] listeners;
       synchronized (mLock) {
           if (mPolicyLevel == POLICY_LEVEL_OFF) {
               // 省电模式没有打开
               return;
           }
           // Don't call out to listeners with the lock held.
           listeners = mListeners.toArray(new BatterySaverPolicyListener[mListeners.size()]);
       }

mHandler.post(() -> {
           for (BatterySaverPolicyListener listener : listeners) {
               // 通知监听者
               listener.onBatterySaverPolicyChanged(this);
           }
       });
   }

目前,省电策略的监听者只有一个 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);
   }

最终会调用 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)) {
           // 如果策略为空,那肯定是关闭了省电模式,此时需要恢复正常的CPU频率
           mFileUpdater.restoreDefault();
       } else {
           // 策略不为空,首先保存节点中原本的值到 /data/system/battery-saver/default-values.xml,然后向节点写值
           mFileUpdater.writeFiles(fileValues);
       }

if (sendBroadcast) {
           // 3. 发送广播
           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. 通知监听者,省电策略已经改变
           for (LowPowerModeListener listener : listeners) {
               final PowerSaveState result =
                       mBatterySaverPolicy.getBatterySaverPolicy(listener.getServiceType());
               listener.onLowPowerModeChanged(result);
           }
       }
   }

这段代码,我只分析如何应用省电策略。

第一步,是获取 CPU 限频策略,以一个 Map 表示,其中 KEY 为 CPU 限频的节点路径,VALUE 为被限制的频率。

然后第二步是应用这个 CPU 限频策略,其实就是向节点写值。 不过在写值之前,会先保存节点中原本的值到 /data/system/battery-saver/default-values.xml 文件中,这个文件的作用是,当关闭省电模式,会恢复 CPU 原本的频率。

最后,通知监听者,策略已经改变,你们需要做相应的适配。这些监听者都是系统服务,例如WindowManagerService 就是一个监听者,它会根据省电模式策略,决定是否关闭动画,关键代码如下:

case NEW_ANIMATOR_SCALE: {
                   // 省电模式下,scale 为 0
                   float scale = getCurrentAnimatorScale();
                   // 关闭 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 {
                               // 关闭 app 进程的动画
                               callbacks.get(i).onAnimatorScaleChanged(scale);
                           } catch (RemoteException e) {
                           }
                       }
                   }
                   break;
               }

如何配置策略

看完了策略控制的源码分析,总结下如何控制策略

  • 修改 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,它受省电模式影响,我相信,如果你看完我的文章,应该能自行分析受影响的功能。

来源:https://juejin.cn/post/7135053176109006862

标签:Android,PowerManagerService,省电,模式,策略,控制
0
投稿

猜你喜欢

  • C# ListBox中的Item拖拽代码分享

    2022-04-12 14:06:41
  • maven引入本地jar包运行报错java.lang.NoClassDefFoundError解决

    2022-10-15 01:42:24
  • 如何基于FTP4J实现FTPS连接过程解析

    2022-09-19 21:51:35
  • Java监听器ActionListener与MouseListener的执行顺序说明

    2022-02-04 20:08:23
  • Android Fragment的回退栈示例详细介绍

    2023-06-21 12:30:55
  • springmvc参数为对象,数组的操作

    2022-04-20 07:38:03
  • Android不规则封闭区域填充色彩的实例代码

    2022-10-17 08:33:05
  • 登陆验证码kaptcha结合spring boot的用法详解

    2023-02-19 15:56:32
  • 详解Java编程中线程同步以及定时启动线程的方法

    2021-08-31 10:59:20
  • Android中的LeakCanary的原理详解

    2021-06-18 09:16:40
  • 解决fastjson从1.1.41升级到1.2.28后报错问题详解

    2021-12-30 21:55:35
  • java三个环境变量配置简单教程

    2023-11-28 20:45:30
  • Java实现抠图片文字或签名的完整代码

    2023-04-18 00:04:44
  • C#对XML文件的各种操作实现方法

    2023-01-21 06:14:40
  • Java关键字instanceof的两种用法实例

    2023-07-31 06:24:50
  • JAVA ArrayList详细介绍(示例)

    2023-02-18 22:30:56
  • C#多态的三种实现方式(小结)

    2022-12-29 18:10:57
  • C# DataTable 转换为 实体类对象实例

    2021-12-25 02:14:51
  • Unity实现简易日志输出功能

    2023-07-25 22:59:44
  • 一篇文章带你了解JVM垃圾回收

    2023-08-06 23:42:20
  • asp之家 软件编程 m.aspxhome.com