初識Android?PowerManagerService省電模式
前言
最近遇到一些關(guān)于省電模式、電量消耗、Doze模式,等等相關(guān)問題。于是,我決定對它們進行徹底分析,那就先從省電模式開啟。
功能介紹
可以在 Settings->Battery->Battery Saver 界面進行省電模式的操作,如下圖:
界面中有三個開關(guān),它們的意思如下:
- Use Battery Saver : 打開/關(guān)閉省電模式。
- Set a Schedule : 設(shè)置一個電量百分比閾值,當電量低于這個閾值的時候,就會觸發(fā)省電模式。設(shè)置閾值的界面如下圖
- Turn off when charging : 這個開關(guān)的意思不能按表面意思理解,它真正的意思是,省電模式被打開的情況下,拔掉充電器或者重啟,如果電量百分比大于90%,那么不會再次開啟省電模式。
由于省電模式的功能涉及的代碼比較多,本文只分析省電模式環(huán)境的初始化,涉及的文件路徑如下
- frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
- frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
- frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
- frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
環(huán)境
省電模式屬于 PowerManagerService 的一部分功能,下面列出與省電模式環(huán)境相關(guān)的代碼:
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); // ... }
與省電模式相關(guān)的類有三個,BatterySaverPolicy, BatterySaverController, BatterySaverStateMachine。
介紹下三個類的作用:
- BatterySaverPolicy : 省電模式的策略。
- BatterySaverController : 控制省電模式的打開/關(guān)閉,并根據(jù)省電模式策略,控制某些功能,例如控制 CPU 頻率。
- BatterySaverStateMachine : 一個狀態(tài)機,管理著省電模式相關(guān)的狀態(tài),并通過 BatterySaverController 控制省電模式的開啟/關(guān)閉。
這里創(chuàng)建三個類對象的方式,就是調(diào)用構(gòu)造函數(shù),下面大致看下這幾個構(gòu)造函數(shù)
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; // 注意,監(jiān)聽了 policy change mBatterySaverPolicy.addListener(this); // FileUpdater 負責向底層文件節(jié)點寫值,例如向CPU頻率的節(jié)點寫值,控制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 的構(gòu)造函數(shù),只需要注意一點,那就是它監(jiān)聽了省電模式策略的改變,因為這個策略會影響省電模式。
BatterySaverStateMachine 的構(gòu)造函數(shù),需要注意 mBatterySaverStickyBehaviourDisabled,它表示是否支持 battery saver sticky 功能。注意了,它的值 false,但是表示支持這個功能,而不是不支持。mDynamicPowerSavingsDefaultDisableThreshold 是與動態(tài)省電模式相關(guān),讀者可自行分析。
繼續(xù)看 PowerManagerService 對省電模式環(huán)境的初始化代碼
public void systemReady(IAppOpsService appOps) { synchronized (mLock) { // ... mBatterySaverController.systemReady(); mBatterySaverPolicy.systemReady(); // ... } }
首先看看 BatterySaverController#systemRead()
public void systemReady() { // 監(jiān)聽這些東西,來控制 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 保存的數(shù)據(jù),否則刪除這個文件。 mFileUpdater.systemReady(LocalServices.getService(ActivityManagerInternal.class) .isRuntimeRestarted()); // 這里的處理邏輯為空 mHandler.postSystemReady(); }
BatterySaverController 會監(jiān)聽屏幕亮滅以及 Doze 模式的廣播。
不過只有屏幕亮滅,會實際地影響省電模式,因為屏幕的亮滅會影響交互模式,而省電模式策略會根據(jù)手機是否處于交互模式而配置不同的策略。目前,在策略中,只有 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); // 無障礙相關(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); // 監(jiān)聽 SettingProvider 的 config 表中,關(guān)于 battery_saver 命名空間下的所有字段值。 // 目前,這些字段都為空,但是這些字段會影響省電模式策略,進而控制省電模式 DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_BATTERY_SAVER, mContext.getMainExecutor(), this); mLastDeviceConfigProperties = DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BATTERY_SAVER); onChange(true, null); }
BatterySaverPolicy 本身有一個默認的策略,但是可以通過 SettingsProvider 中的一些字段來控制策略,從而控制省電模式影響的功能。但是目前,這些字段的值都為空,因此并不影響分析,后面或許我另寫一篇文章,分析如何控制省電模式策略。
繼續(xù)看 PowerManagerService 對省電模式環(huán)境的初始化代碼
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(() -> { // 監(jiān)聽數(shù)據(jù)庫字段 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 代表觸發(fā)省電模式的電量百分比 cr.registerContentObserver(Settings.Global.getUriFor( Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL), false, mSettingsObserver, UserHandle.USER_SYSTEM); // Settings.Global.AUTOMATIC_POWER_SAVE_MODE 代表自動省電模式的類型 // 類型有三個,根據(jù)電量百分比觸發(fā),動態(tài)省電模式模式,或者none cr.registerContentObserver(Settings.Global.getUriFor( Settings.Global.AUTOMATIC_POWER_SAVE_MODE), false, mSettingsObserver, UserHandle.USER_SYSTEM); // Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED 代表是否打開動態(tài)省電模式 cr.registerContentObserver(Settings.Global.getUriFor( Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED), false, mSettingsObserver, UserHandle.USER_SYSTEM); // Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD 代表動態(tài)省電模式關(guān)閉的閾值 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 // 對應(yīng)于 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; // 讀取數(shù)據(jù)庫字段,并根據(jù)情況,打開/關(guān)閉省電模式 refreshSettingsLocked(); // 自動打開/關(guān)閉省電模式 doAutoBatterySaverLocked(); } }); }
這里主要是監(jiān)聽并讀取與省電模式相關(guān)的數(shù)據(jù)庫字段,由于現(xiàn)在是分析初始化環(huán)境,因此這里不分析觸發(fā)省電模式的代碼。這些字段值是什么意思,請注意看注釋。
至此,省電模式環(huán)境的初始化代碼已經(jīng)分析完畢,你可能對代碼中提到的一些概念非常迷惑,我剛開啟接觸的時候也是一樣。為了后面代碼分析的順利進行,現(xiàn)在預備幾個知識
- 當省電模式開啟后,只要插入了充電器,系統(tǒng)會自動關(guān)閉省電模式。
- 當處于充電模式,系統(tǒng)是禁止開啟省電模式。
- Battery Saver Sticky : 在省電模式開啟的情況下,拔掉充電器,或者系統(tǒng)重啟,這個 Battery Saver Sticky 模式就會起效,它會再次開啟省電模式。
- Battery Saver Sticky Auto Disable : 從字面理解意思,就是自動關(guān)閉 Battery Saver Sticky 功能。當電量百分比大于某個閾值,默認是90%,在省電模式開啟的情況狂下,拔掉充電器或者重啟,那么不會再次開啟省電模式。
結(jié)束
到此這篇關(guān)于初識Android PowerManagerService省電模式的文章就介紹到這了,更多相關(guān)Andorra PowerManagerService內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
最好用的Android省市區(qū)三級聯(lián)動選擇效果
這篇文章主要為大家詳細介紹了最好用的Android省市區(qū)三級聯(lián)動選擇效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-02-02關(guān)于WebView 重定向行為導致的多次加載的問題
這篇文章主要介紹了關(guān)于WebView 重定向行為導致的多次加載的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03Android有效獲取狀態(tài)欄(StatusBar)高度的方法
這篇文章主要介紹了Android有效獲取狀態(tài)欄(StatusBar)高度的方法,涉及Android針對狀態(tài)欄(StatusBar)屬性操作的相關(guān)技巧,需要的朋友可以參考下2016-08-08android實現(xiàn)藍牙文件發(fā)送的實例代碼,支持多種機型
這篇文章主要介紹了android實現(xiàn)藍牙文件發(fā)送的實例代碼,有需要的朋友可以參考一下2014-01-01Android自定義processor實現(xiàn)bindView功能的實例
下面小編就為大家分享一篇Android自定義processor實現(xiàn)bindView功能的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12Android AIDL實現(xiàn)跨進程通信的示例代碼
本篇文章主要介紹了Android AIDL實現(xiàn)跨進程通信的示例代碼,具有一定的參考價值,有興趣的可以了解一下2017-08-08Android中判斷手機是否聯(lián)網(wǎng)實例
這篇文章主要介紹了Android中判斷手機是否聯(lián)網(wǎng)實例,包括xml配置文件及功能代碼的實現(xiàn),需要的朋友可以參考下2014-10-10Android利用ContentProvider初始化組件的踩坑記錄
做Android SDK開發(fā)的時候,一般我們會將初始化的方法封裝,然后讓調(diào)用SDK的開發(fā)者在Application的onCreate方法中進行初始化,下面這篇文章主要給大家介紹了關(guān)于Android利用ContentProvider初始化組件的踩坑記錄,需要的朋友可以參考下2022-04-04