初识Android PowerManagerService省电模式

2022-08-24 11:44:00
目录
前言功能介绍环境结束

前言

最近遇到一些关于省电模式、电量消耗、Doze模式,等等相关问题。于是,我决定对它们进行彻底分析,那就先从省电模式开启。

功能介绍

可以在>

界面中有三个开关,它们的意思如下:

    Use Battery Saver : 打开/关闭省电模式。Set a Schedule : 设置一个电量百分比阈值,当电量低于这个阈值的时候,就会触发省电模式。设置阈值的界面如下图

      Turn off when charging : 这个开关的意思不能按表面意思理解,它真正的意思是,省电模式被打开的情况下,拔掉充电器或者重启,如果电量百分比大于90%,那么不会再次开启省电模式。

      由于省电模式的功能涉及的代码比较多,本文只分析省电模式环境的初始化,涉及的文件路径如下

        frameworks/base/services/core/java/com/android/server/power/PowerManagerService.javaframeworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.javaframeworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverController.javaframeworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java

        环境

        省电模式属于 PowerManagerService 的一部分功能,下面列出与省电模式环境相关的代码:

        PowerManagerService(Context context, Injector injector) {
            super(context);
            // ...
        
            // Class to decide whether to turn on battery saver mode for specific services.
            mBatterySaverPolicy =
                    mInjector.createBatterySaverPolicy(mLock, mContext, mBatterySavingStats);
        
            // Responsible for battery saver mode transition logic.
            mBatterySaverController = mInjector.createBatterySaverController(mLock, mContext,
                    mBatterySaverPolicy, mBatterySavingStats);
        
            //  Decides when to enable / disable battery saver.
            mBatterySaverStateMachine = mInjector.createBatterySaverStateMachine(mLock, mContext,
                    mBatterySaverController);
           
            // ...
        }

        与省电模式相关的类有三个,BatterySaverPolicy, BatterySaverController, BatterySaverStateMachine。

        介绍下三个类的作用:

          BatterySaverPolicy : 省电模式的策略。BatterySaverController : 控制省电模式的打开/关闭,并根据省电模式策略,控制某些功能,例如控制 CPU 频率。BatterySaverStateMachine : 一个状态机,管理着省电模式相关的状态,并通过 BatterySaverController 控制省电模式的开启/关闭。

          这里创建三个类对象的方式,就是调用构造函数,下面大致看下这几个构造函数

          public BatterySaverPolicy(Object lock, Context context, BatterySavingStats batterySavingStats) {
              super(BackgroundThread.getHandler());
              mLock = lock;
              mHandler = BackgroundThread.getHandler();
              mContext = context;
              mContentResolver = context.getContentResolver();
              mBatterySavingStats = batterySavingStats;
          }
          public BatterySaverController(Object lock, Context context, Looper looper,
                  BatterySaverPolicy policy, BatterySavingStats batterySavingStats) {
              mLock = lock;
              mContext = context;
              mHandler = new MyHandler(looper);
              mBatterySaverPolicy = policy;
              // 注意,监听了 policy change
              mBatterySaverPolicy.addListener(this);
              
              // FileUpdater 负责向底层文件节点写值,例如向CPU频率的节点写值,控制CPU频率
              mFileUpdater = new FileUpdater(context);
              
              mBatterySavingStats = batterySavingStats;
          
              // 刷新获取省电模式的缓存
              PowerManager.invalidatePowerSaveModeCaches();
          }
          public BatterySaverStateMachine(Object lock,
                  Context context, BatterySaverController batterySaverController) {
              mLock = lock;
              mContext = context;
              mBatterySaverController = batterySaverController;
              mState = STATE_OFF;
              // Whether or not battery saver should be "sticky" when manually enabled.
              // false
              // 注意了,值为 false,表明这个 battery saver sticky 功能是打开的
              mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean(
                      com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled);
                      
              //  Config flag to track default disable threshold for Dynamic power savings enabled battery saver.
              // 80
              mDynamicPowerSavingsDefaultDisableThreshold = mContext.getResources().getInteger(
                      com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold);
          }

          BatterySaverController 的构造函数,只需要注意一点,那就是它监听了省电模式策略的改变,因为这个策略会影响省电模式。

          BatterySaverStateMachine 的构造函数,需要注意 mBatterySaverStickyBehaviourDisabled,它表示是否支持 battery saver sticky 功能。注意了,它的值 false,但是表示支持这个功能,而不是不支持。mDynamicPowerSavingsDefaultDisableThreshold 是与动态省电模式相关,读者可自行分析。

          继续看 PowerManagerService 对省电模式环境的初始化代码

          public void systemReady(IAppOpsService appOps) {
              synchronized (mLock) {
                  // ...
                  mBatterySaverController.systemReady();
                  mBatterySaverPolicy.systemReady();
                  
                  // ...
              }   
          }

          首先看看 BatterySaverController#systemRead()

          public void systemReady() {
              // 监听这些东西,来控制 battery saver
              final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
              filter.addAction(Intent.ACTION_SCREEN_OFF);
              filter.addAction(Intent.ACTION_BATTERY_CHANGED);
              filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
              filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
              mContext.registerReceiver(mReceiver, filter);
          
              // 如果 Runtime 重启,那么读取 /data/system/battery-saver/default-values.xml 保存的数据,否则删除这个文件。
              mFileUpdater.systemReady(LocalServices.getService(ActivityManagerInternal.class)
                      .isRuntimeRestarted());
              // 这里的处理逻辑为空
              mHandler.postSystemReady();
          }

          BatterySaverController 会监听屏幕亮灭以及 Doze 模式的广播。

          不过只有屏幕亮灭,会实际地影响省电模式,因为屏幕的亮灭会影响交互模式,而省电模式策略会根据手机是否处于交互模式而配置不同的策略。目前,在策略中,只有 CPU 频率受影响。

          再来看看 BatterySaverPolicy#systemReady()

          public void systemReady() {
              ConcurrentUtils.wtfIfLockHeld(TAG, mLock);
          
              // 下面两个字段,目前没有值,但是会控制省电模式策略,进而影响省电模式
              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);
          
              // 监听 SettingProvider 的 config 表中,关于 battery_saver 命名空间下的所有字段值。
              // 目前,这些字段都为空,但是这些字段会影响省电模式策略,进而控制省电模式
              DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_BATTERY_SAVER,
                      mContext.getMainExecutor(), this);
              mLastDeviceConfigProperties =
                      DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BATTERY_SAVER);
              onChange(true, null);
          }

          BatterySaverPolicy 本身有一个默认的策略,但是可以通过 SettingsProvider 中的一些字段来控制策略,从而控制省电模式影响的功能。但是目前,这些字段的值都为空,因此并不影响分析,后面或许我另写一篇文章,分析如何控制省电模式策略。

          继续看 PowerManagerService 对省电模式环境的初始化代码

          public void onBootPhase(int phase) {
              synchronized (mLock) {
                  if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
                      incrementBootCount();
          
                  } else if (phase == PHASE_BOOT_COMPLETED) {
                      // ...
          
                      mBatterySaverStateMachine.onBootCompleted();
                      
                      // ...
                  }
              }
          }

          BatterySaverStateMachine.onBootCompleted() 代码如下:

          public void onBootCompleted() {
              putGlobalSetting(Settings.Global.LOW_POWER_MODE, 0);
              runOnBgThread(() -> {
          
                  // 监听数据库字段
                  final ContentResolver cr = mContext.getContentResolver();
                  // Settings.Global.LOW_POWER_MODE 代表省电模式是否打开
                  cr.registerContentObserver(Settings.Global.getUriFor(
                          Settings.Global.LOW_POWER_MODE),
                          false, mSettingsObserver, UserHandle.USER_SYSTEM);
                  // Settings.Global.LOW_POWER_MODE_STICKY 代表 battery saver sticky 功能是否打开
                  cr.registerContentObserver(Settings.Global.getUriFor(
                          Settings.Global.LOW_POWER_MODE_STICKY),
                          false, mSettingsObserver, UserHandle.USER_SYSTEM);
                  // Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL 代表触发省电模式的电量百分比
                  cr.registerContentObserver(Settings.Global.getUriFor(
                          Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
                          false, mSettingsObserver, UserHandle.USER_SYSTEM);
                  // Settings.Global.AUTOMATIC_POWER_SAVE_MODE 代表自动省电模式的类型
                  // 类型有三个,根据电量百分比触发,动态省电模式模式,或者none
                  cr.registerContentObserver(Settings.Global.getUriFor(
                          Settings.Global.AUTOMATIC_POWER_SAVE_MODE),
                          false, mSettingsObserver, UserHandle.USER_SYSTEM);
                  // Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED 代表是否打开动态省电模式
                  cr.registerContentObserver(Settings.Global.getUriFor(
                          Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED),
                          false, mSettingsObserver, UserHandle.USER_SYSTEM);
                  // Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD 代表动态省电模式关闭的阈值
                  cr.registerContentObserver(Settings.Global.getUriFor(
                          Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD),
                          false, mSettingsObserver, UserHandle.USER_SYSTEM);
                  // Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED 表示是否打开了 battery saver sticky auto disable
                  // 对应于 Settings->Battery->Battery Saver->Turn off when charging
                  cr.registerContentObserver(Settings.Global.getUriFor(
                          Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED),
                          false, mSettingsObserver, UserHandle.USER_SYSTEM);
                  // Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL 表示  battery saver sticky auto disable 的阈值
                  cr.registerContentObserver(Settings.Global.getUriFor(
                          Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL),
                          false, mSettingsObserver, UserHandle.USER_SYSTEM);
          
          
                  synchronized (mLock) {
                      /**
                       * If 1, battery saver ({@link #LOW_POWER_MODE}) will be re-activated after the device
                       * is unplugged from a charger or rebooted.
                       */
                      // battery saver sticky 功能是否被打开
                      final boolean lowPowerModeEnabledSticky = getGlobalSetting(
                              Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0;
                      if (lowPowerModeEnabledSticky) {
                          mState = STATE_PENDING_STICKY_ON;
                      }
          
                      mBootCompleted = true;
          
                      // 读取数据库字段,并根据情况,打开/关闭省电模式
                      refreshSettingsLocked();
          
                      // 自动打开/关闭省电模式
                      doAutoBatterySaverLocked();
                  }
              });
          }

          这里主要是监听并读取与省电模式相关的数据库字段,由于现在是分析初始化环境,因此这里不分析触发省电模式的代码。这些字段值是什么意思,请注意看注释。

          至此,省电模式环境的初始化代码已经分析完毕,你可能对代码中提到的一些概念非常迷惑,我刚开启接触的时候也是一样。为了后面代码分析的顺利进行,现在预备几个知识

            当省电模式开启后,只要插入了充电器,系统会自动关闭省电模式。当处于充电模式,系统是禁止开启省电模式。Battery Saver Sticky : 在省电模式开启的情况下,拔掉充电器,或者系统重启,这个 Battery Saver Sticky 模式就会起效,它会再次开启省电模式。Battery Saver Sticky Auto Disable : 从字面理解意思,就是自动关闭 Battery Saver Sticky 功能。当电量百分比大于某个阈值,默认是90%,在省电模式开启的情况狂下,拔掉充电器或者重启,那么不会再次开启省电模式。

            结束

            到此这篇关于初识Android >