1. 程式人生 > >Android5.1--電源管理之省電模式分析

Android5.1--電源管理之省電模式分析

 一、如何開啟5.0省電模式

開啟安卓5.0裝置的設定選項,然後前往電池選單,點選選單鍵,彈出並選擇“節電助手”,隨後點選頂部的開關便可。

此外,要是使用者執行的是原生版安卓,可以下拉安卓通知中心,然後點選電池按鈕,便可進入電池介面,找到“省電模式”。

開啟此模式後,螢幕亮度會調低,後臺資料(大部分)關閉,動畫全部取消,震動關閉,基本上和廠商們的省電模式行為差不多,都是以犧牲可用性來換取使用時間

不同的是,開啟此模式後,Android 5.0除了一個通知圖示之外,還會用無處不在的亮橙色來提醒你:頂部狀態列、底部通知欄全部變為橙色,很多圖示等素材資源增加橙色,甚至一些應用的頂部欄裡也會變色。

二、相關程式碼

設定應用入口檔案:

./packages/apps/Settings/src/com/android/settings/fuelgauge/BatterySaverSettings.java

托盤顯示:

./frameworks/base/packages/SystemUI/src/com/android/systemui/power/PowerUI.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java

托盤中callback回撥函式onPowerSaveChanged():

./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java

onPowerSaveChanged():(systemui內部處理)

./frameworks/base/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/doze/DozeService.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java

GPS根據mode 更新處理:

./frameworks/base/services/core/java/com/android/server/location/GpsLocationProvider.java:

傳送模式切換ing/切換 廣播:

./frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

voice根據mode 更新處理:

./frameworks/base/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java

三、省電模式流程分析

1、設定應用入口檔案:

./packages/apps/Settings/src/com/android/settings/fuelgauge/BatterySaverSettings.java

節能助手開啟或關閉時,呼叫onSwitchChanged方法,引數isChecked表示節能助手處於開啟(true)或關閉(false)狀態。開啟時isChecked為true,傳送訊息mStartMode開啟新執行緒開啟省電模式;否則關閉省電模式。

2、提供呼叫介面檔案:

.\frameworks\base\core\java\android\os\PowerManager.java

3、傳送模式切換廣播:

./frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

mIsPowered變量表示充電狀態,true表示正在充電(已接入電源),否則為false;setLowPowerModeInternal方法中首先判斷mIsPowered是否處於充電狀態,如果正在充電則直接返回false,表示不允許設定省電模式(省電模式會在裝置充電時自動關閉)。

接著根據引數mode的值設定系統變數”low_power”(LOW_POWER_MODE),並設定變數mLowPowerModeSetting(Current state of the low power mode setting.表示設定低電模式的當前狀態;從系統設定中獲取的值,即資料庫欄位“low_power”的值)。

接下來設定變數mAutoLowPowerModeSnoozingThe user turnedoff low power mode below the trigger level表示電量低於省電模式的觸發點時,關閉省電模式)。該變數值是由mAutoLowPowerModeConfigured(自動開啟省電模式的當前狀態,即資料庫欄位“low_power_trigger_level”是否為0的值;不為0時表示打開了自動開啟功能,該變數為true)和mBatteryLevelLowTrue if the battery level is currentlyconsidered low.如果電池電量低為true)這兩個變數決定的。當電量低並且允許自動設定省電模式時,如果此時省電模式是開啟的,就要設定mAutoLowPowerModeSnoozing的值為false;如果省電模式是關閉的,就要設定mAutoLowPowerModeSnoozing的值為true。就是要求mAutoLowPowerModeSnoozing變數與省電模式的邏輯保持一致。

呼叫updateLowPowerModeLocked方法。

最後直接返回true,表示省電模式設定成功。

首先判斷如果當前正在充電並且開啟了省電模式,則關閉省電模式,將“low_power”欄位設定為0,mLowPowerModeSetting置為false。

接著建立兩個臨時變數autoLowPowerModeEnabled和lowPowerModeEnabled。autoLowPowerModeEnabled(當前沒有充電,自動開啟省電模式,電量低於省電模式的電量觸發點時不關閉省電模式,電池電量低,以上條件均滿足時為true);lowPowerModeEnabled(當mLowPowerModeSetting或autoLowPowerModeEnabled為真時,則設定為true);根據lowPowerModeEnabled臨時變數值和mLowPowerModeEnabled(true表示裝置處於省電模式,全域性變數)判斷是否執行省電模式的功能。當兩者狀態不一致時,更新mLowPowerModeEnabled狀態值。

接著呼叫powerHintInternal方法;之後使用後臺執行緒BackgroundThread處理事件,會先後傳送action為ACTION_POWER_SAVE_MODE_CHANGING和ACTION_POWER_SAVE_MODE_CHANGED的廣播,注意這兩個廣播中設定了addFlags為Intent.FLAG_RECEIVER_REGISTERED_ONLY,表示只有動態定義的廣播接收器才能接收到該廣播,在傳送ACTION_POWER_SAVE_MODE_CHANGING廣播的時候傳遞資料“mode”的值。在傳送這兩個廣播中間設定LowPowerModeListener,呼叫該介面的onLowPowerModeChanged方法(此處下文介紹)。

這裡先分析一下powerHintInternal方法的處理。

powerHintInternal(POWER_HINT_LOW_POWER,lowPowerModeEnabled ? 1 : 0)。注意:POWER_HINT_LOW_POWER是在hardware/libhardware/include/hardware/power.h中定義的。

4、JNI層函式呼叫

frameworks\base\services\core\jni\com_android_server_power_PowerManagerService.cpp。

呼叫靜態方法nativeSendPowerHint,gPowerModule是power_module型別的結構體,

下面分析一下power_module(電源模組)結構體。每個硬體模組必須有一個名為HAL_MODULE_INFO_SYM的資料結構,這個資料結構的欄位必須以hw_module_t開始後跟模組的詳細資訊。該結構體中定義了一個hw_module_t結構體(common)和三個函式(init,setInteractive,powerHint)。Power_module的定義如下:

Typedefstruct power_module {

         Struct hw_module_t common;

         Void (*init) (struct power_module*module);

         Void (*setInteractive)(structpower_module *module, int on);

         Void (*powerHint)(struct power_module*module, power_hint_t hint, void *data);

}power_module_t;

1)        (*init)():設定電源管理在執行時啟動的設定動作,例如設定預設的CPU頻率引數。只供由PowerManagerService載入的Power HAL例項呼叫。

2)        (*setInteractive)():該方法用來執行關閉屏幕後進入非互動狀態,同時開啟螢幕之前進入互動狀態;引數on表示當系統轉變為互動狀態或喚醒狀態時是一個非0值,當轉變為非互動狀態或asleep狀態時為0;該方法典型的操作就是開啟或關閉裝置,調整CPU頻率引數。當系統進入非互動狀態時該函式還可以呼叫相應介面允許核心掛起系統進入低電睡眠狀態;當系統進入互動狀態時禁止低電掛起。

3)        (*powerHint)():根據電源需求傳遞提示資訊,這可能會導致  CPU頻率的調整和一些控制項的功耗/效能的調整。可能的提示是:

POWER_HINT_VSYNC(垂直同步):前臺應用從SurfaceFlinger中啟動或停止請求一個VSYNC脈衝。如果該應用已開始請求VSYNC,然後CPU和GPU很快載入,可能會適當加快CPU和儲存器速度。該引數為非0值表示需要請求VSYNC,若為0表示不再需要請求VSYNC。

POWER_HINT_INTERACTION:使用者與裝置互動,例如觸控式螢幕事件。CPU和GPU會加速載入,適當提高CPU頻率,儲存器匯流排,此引數暫時沒有使用。

POWER_HINT_LOW_POWER:省電模式的啟用或關閉。省電模式是以消耗效能為代價的。非0值表示開啟省電模式,為0時表示已關閉省電模式。

5、Native層函式呼叫IPowerManager.cpp

frameworks\native\services\powermanager\IPowerManager.cpp

採用binder通訊方式,將POWER_HINT_LOW_POWER和開啟標誌傳送到服務端處理。

ACTION_POWER_SAVE_MODE_CHANGING廣播接收器

1、BatteryController.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java

在BatteryController類中接收到ACTION_POWER_SAVE_MODE_CHANGING廣播後獲取傳遞的“mode”資料值,作為setPowerSave方法的引數,如果mode值與當前mPowerSave值相等,則直接返回,若不相等則賦值給當前mPowerSave值;並呼叫firePowerSaveChanged方法。

在firePowerSaveChanged方法中,遍歷BatteryStateChangeCallback物件,並呼叫介面的onPowerSaveChanged方法。這裡為什麼是一個列表呢? (凡實現了該介面的類,均在這個列表中儲存)。

ArrayList<BatteryStateChangeCallback>mChangeCallbacks =newArrayList<>();

2、BatteryMeterView.java(電池計量器)

frameworks\base\packages\SystemUI\src\com\android\systemui\BatteryMeterView.java

BatteryMeterView類實現了BatteryController.BatteryStateChangeCallback介面,回撥onPowerSaveChanged方法,在onPowerSaveChanged方法中呼叫invalidate方法會重新整理介面。

在getColorForLevel方法中,如果處於省電模式,則返回省電模式設定的顏色值:battery_saver_mode_color(#fff4511e)

3、PowerUI.java

在PowerUI.java中註冊廣播接收器,監聽省電模式設定,分別接收action為POWER_SAVE_MODE_CHANGING和POWER_SAVE_MODE_CHANGED的廣播,接收到廣播後分別調用setSaverMode方法和updateSaverMode方法。

在setSaverMode方法中呼叫內部介面WarningsUI的showSaverMode方法。PowerNotificationWarning實現了WarningsUI介面,因此呼叫PowerNotificationWarnings的showSaverMode方法。

4、設定通知:PowerNotificationWarnings.java

frameworks\base\packages\SystemUI\src\com\android\systemui\power\PowerNotificationWarning.java

PowerNotificationWarnings中有幾個變數:mSaver表示是否開啟了省電模式;mInvalidCharger表示無效充電器;mWarning表示

mSaver為true時,showSaverNotification()方法被呼叫,顯示節電助手已開啟的通知。

在節電助手通知欄中新增一個Action,觸發一個動作為ACTION_STOP_SAVER(PNW.stopSaver)的廣播事件,這個事件用來關閉省電模式。

接著判斷hasSaverSettings方法返回值,在該方法中呼叫了Intent.resolveActivity方法,該方法的含義是:如果當前裝置上不存在可接收某種隱式Intent的應用程式,則呼叫startActivity()的應用程式將會崩潰。為了預先判斷一下是否存在可接收Intent的應用程式,呼叫Intent物件的resolveActivity方法。如果結果非空,則表示至少存在一個可處理該Intent的應用程式,並且可安全呼叫startActivity方法。如果結果為null,請勿再使用該Intent,並儘可能關閉那些會發起該Intent的功能。

為該Notification新增一個PendingIntent(android.settings.BATTERY_SAVER_SETTINGS),因此呼叫Notification.Builder.setContentIntent方法。目前沒有該action的廣播接收器。 因此點選該通知時沒有反應。

最後呼叫mNoMan.notifyAsUser(TAG_NOTIFICATION,ID_NOTIFICATION, nb.build(), UserHandle.CURRENT); 發出這個通知。

5、降低螢幕亮度

在PowerManagerService中更新電源狀態的時候呼叫updateDisplayPowerStateLocked方法時,會獲取省電模式狀態,儲存在DisplayPowerRequest的lowPowerMode屬性中。

mDisplayPowerRequest.lowPowerMode =mLowPowerModeEnabled;

最終呼叫到DisplayPowerController類中,在updatePowerState方法中設定螢幕亮度值,如果處於省電模式狀態,設定螢幕亮度值減半處理;

PowerMnagerInternal.LowPowerModeListener

此處回過頭來看看PowerManagerService的updateLowPowerModeLocked方法中生成的PowerMnagerInternal.LowPowerModeListener陣列。

該陣列是由所有實現PowerMnagerInternal.LowPowerModeListener介面的類組成的。

1、取消震動效果:VibratorService.java

frameworks\base\services\core\java\com\android\server\VibratorService.java

在systemReady方法中註冊省電模式監聽器,當省電模式發生改變時回撥onLowPowerModeChanged方法,該方法中呼叫updateInputDeviceVibrators方法。

在updateInputDeviceVibrators方法中獲取省電模式狀態。

mLowPowerMode = mPowerManagerInternal.getLowPowerModeEnabled();

VibratorService類中startVibrationLocked方法負責震動效果,首先判斷是否處於省電模式,若為省電模式直接返回,不再做震動操作。

2、取消動畫設定:WindowManagerService.java

frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java

         在WindowManagerService的構造方法中,註冊省電模式的監聽器,當回撥onLowPowerModeChanged方法時,比較mAnimationDisabled(視窗動畫的使能狀態)與省電模式使能狀態,如果不相等則為mAnimationDisabled賦值並呼叫dispatchNewAnimatorScaleLocked方法。

在diapatchNewAnimatorScaleLocked方法中傳送H.NEW_ANIMATOR_SCALE訊息。

mH接收到H.NEW_ANIMATOR_SCALE訊息時,是如何處理的呢?首先呼叫getCurrentAnimatorScale方法獲取當前動畫持續時間比,如果處於省電模式狀態則返回0,不再開啟動畫效果。

ACTION_POWER_SAVE_MODE_CHANGED廣播接收器

1、PowerUI.java

接收到ACTION_POWER_SAVE_MODE_CHANGED廣播後,更新省電模式狀態。

此時呼叫到PowerNotificationWarning的setSaverMode方法中,如下

以下處理流程同接收到ACTION_POWER_SAVE_MODE_CHANGING廣播後一樣,只是當省電模式狀態相等時就會return。

2、BatteryController.java

接收ACTION_POWER_SAVE_MODE_CHANGED廣播,更新省電模式狀態。

此時if語句成立,直接返回。

3、KeyguardStatusBarView.java、StatusBarHeaderView.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java

在KeyguardStatusBarView類和StatusBarHeaderView類中onPowerSaveChanged方法中暫時沒有處理。

4、PhoneStatusBar.java

./frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java

5、關閉GPS功能:GpsLocationProvider.java

./frameworks/base/services/core/java/com/android/server/location/GpsLocationProvider.java

         變數:

mDisableGps:使gps失效時為true,用來支援設定中的省電模式。

BATTERY_SAVER_GPS_MODE= “batterySaverGpsMode”;開啟省電模式時安全設定GPS動作。

BATTERY_SAVER_MODE_NO_CHANGE:設定batterySaverGpsMode的值,例如不受省電模式的影響。

BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF:batterySaverGpsMode的值,例如省電模式開啟並處於待機狀態時使GPS功能失效。

該類中接收到廣播android.os.action.POWER_SAVE_MODE_CHANGED時,呼叫updateLowPowerMode方法。

獲取系統設定中設定的“batterySaverGpsMode”欄位值,預設返回BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF的值;如果返回的是預設值,則定義臨時變數disableGps,如果與全域性變數mDisbaleGps不等,賦值給mDisableGps,並呼叫updateRequirements方法。

在updateRequirements方法中,如果開啟的省電模式並待機狀態下關閉GPS。

6、關閉語音識別:SoundTriggerHelper.java

./frameworks/base/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java

PowerManagerService中傳送ACTION_POWER_SAVE_MODE_CHANGED廣播後,在SoundTriggerHelper中定義廣播接收器,接收ACTION_POWER_SAVE_MODE_CHANGED。並獲取是否處於省電模式的狀態值。

如果action不為ACTION_POWER_SAVE_MODE_CHANGED,直接退出;獲取省電模式的狀態,並呼叫onPowerSaveModeChangedLocked方法。

如果省電模式狀態值沒有改變,直接退出;否則將新獲取的狀態值賦值給全域性變數mIsPowerSaveMode,並呼叫updateRecognitionLocked(true)方法。

在updateRecognitionLocked方法中,判斷如果是省電模式,則停止語音識別。