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

2019-07-14 02:27发布

 一、如何开启5.0省电模式

打开安卓5.0设备的设置选项,然后前往电池菜单,点击菜单键,弹出并选择“节电助手”,随后点击顶部的开关便可。 此外,要是用户运行的是原生版安卓,可以下拉安卓通知中心,然后点击电池按钮,便可进入电池界面,找到“省电模式”。              开启此模式后,屏幕亮度会调低,后台数据(大部分)关闭,动画全部取消,震动关闭,基本上和厂商们的省电模式行为差不多,都是以牺牲可用性来换取使用时间。 不同的是,开启此模式后,Android 5.0除了一个通知图标之外,还会用无处不在的亮橙 {MOD}来提醒你:顶部状态栏、底部通知栏全部变为橙 {MOD},很多图标等素材资源增加橙 {MOD},甚至一些应用的顶部栏里也会变 {MOD}。

二、相关代码

设置应用入口文件: ./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、提供调用接口文件: .frameworksasecorejavaandroidosPowerManager.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层函数调用 frameworksaseservicescorejnicom_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 ativeservicespowermanagerIPowerManager.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方法。这里为什么是一个列表呢? (凡实现了该接口的类,均在这个列表中保存)。 ArrayListmChangeCallbacks =newArrayList<>(); 2、BatteryMeterView.java(电池计量器) frameworksasepackagesSystemUIsrccomandroidsystemuiBatteryMeterView.java BatteryMeterView类实现了BatteryController.BatteryStateChangeCallback接口,回调onPowerSaveChanged方法,在onPowerSaveChanged方法中调用invalidate方法会刷新界面。 在getColorForLevel方法中,如果处于省电模式,则返回省电模式设置的颜 {MOD}值: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 frameworksasepackagesSystemUIsrccomandroidsystemuipowerPowerNotificationWarning.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 frameworksaseservicescorejavacomandroidserverVibratorService.java 在systemReady方法中注册省电模式监听器,当省电模式发生改变时回调onLowPowerModeChanged方法,该方法中调用updateInputDeviceVibrators方法。 在updateInputDeviceVibrators方法中获取省电模式状态。 mLowPowerMode = mPowerManagerInternal.getLowPowerModeEnabled(); VibratorService类中startVibrationLocked方法负责震动效果,首先判断是否处于省电模式,若为省电模式直接返回,不再做震动操作。 2、取消动画设置:WindowManagerService.java frameworksaseservicescorejavacomandroidserverwmWindowManagerService.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方法中,判断如果是省电模式,则停止语音识别。