在上篇文章Android P 省电模式(LowPowerMode)(一) ------ 省电模式手动开启流程 中最后分析到,开启省电模式后,会在 BatterySaverController 中回调所有注册的 LowPowerModeListener(onLowPowerModeChanged)和 plugin(onBatterySaverChanged),并发出广播。 我们看一下 系统做了哪些事情来实现省电。
主要有 振动,亮度,网络访问,GPS位置信息,动画,语音识别几个方面。
1. 限制振动 VibratorService.java
VibratorService.java中回调:
public void systemReady() {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
try {
..........................
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@Override
public int getServiceType() {
return ServiceType.VIBRATION;
}
@Override
public void onLowPowerModeChanged(PowerSaveState result) {
updateVibrators();//更改低电量状态
}
});
..........................
}
private void updateVibrators() {
synchronized (mLock) {
boolean devicesUpdated = updateInputDeviceVibratorsLocked();
boolean lowPowerModeUpdated = updateLowPowerModeLocked();//更改低电量状态
updateVibrationIntensityLocked();
if (devicesUpdated || lowPowerModeUpdated) {
// If the state changes out from under us then just reset.
doCancelVibrateLocked();
}
}
}
private boolean updateLowPowerModeLocked() {
boolean lowPowerMode = mPowerManagerInternal
.getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;//看看这个值怎么拿到的
if (lowPowerMode != mLowPowerMode) {
mLowPowerMode = lowPowerMode;//mLowPowerMode这个变量判断要不要震动会用到
return true;
}
return false;
}
frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java :
@Override
public PowerSaveState getLowPowerState(@ServiceType int serviceType) {
return mBatterySaverPolicy.getBatterySaverPolicy(serviceType,
mBatterySaverController.isEnabled());//这个方法根据传入的serviceType 决定要不要对省电模式做出反应,很关键的方法
}
frameworks\base\services\core\java\com\android\server\power\BatterySaverPolicy.java :
/**
* Get the {@link PowerSaveState} based on {@paramref type} and {@paramref realMode}.
* The result will have {@link PowerSaveState#batterySaverEnabled} and some other
* parameters when necessary.
*
* @param type type of the service, one of {@link ServiceType}
* @param realMode whether the battery saver is on by default
* @return State data that contains battery saver data
*/
public PowerSaveState getBatterySaverPolicy(@ServiceType int type, boolean realMode) {
synchronized (mLock) {
final PowerSaveState.Builder builder = new PowerSaveState.Builder()
.setGlobalBatterySaverEnabled(realMode);
if (!realMode) {
return builder.setBatterySaverEnabled(realMode)
.build();
}
switch (type) {
case ServiceType.GPS:
return builder.setBatterySaverEnabled(realMode)
.setGpsMode(mGpsMode)
.build();
case ServiceType.ANIMATION:
return builder.setBatterySaverEnabled(mAnimationDisabled)
.build();//mVibrationDisabledEffective决定省电模式下要不要取消动画
case ServiceType.FULL_BACKUP:
return builder.setBatterySaverEnabled(mFullBackupDeferred)
.build();
case ServiceType.KEYVALUE_BACKUP:
return builder.setBatterySaverEnabled(mKeyValueBackupDeferred)
.build();
case ServiceType.NETWORK_FIREWALL:
return builder.setBatterySaverEnabled(!mFireWallDisabled)
.build();
case ServiceType.SCREEN_BRIGHTNESS:
return builder.setBatterySaverEnabled(!mAdjustBrightnessDisabled)
.setBrightnessFactor(mAdjustBrightnessFactor)
.build();
case ServiceType.DATA_SAVER:
return builder.setBatterySaverEnabled(!mDataSaverDisabled)
.build();
case ServiceType.SOUND:
return builder.setBatterySaverEnabled(mSoundTriggerDisabled)
.build();
case ServiceType.VIBRATION:
return builder.setBatterySaverEnabled(mVibrationDisabledEffective)
.build();//mVibrationDisabledEffective决定省电模式下要不要禁止振动
case ServiceType.FORCE_ALL_APPS_STANDBY:
return builder.setBatterySaverEnabled(mForceAllAppsStandby)
.build();
case ServiceType.FORCE_BACKGROUND_CHECK:
return builder.setBatterySaverEnabled(mForceBackgroundCheck)
.build();
case ServiceType.OPTIONAL_SENSORS:
return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
.build();
case ServiceType.AOD:
return builder.setBatterySaverEnabled(mAodDisabled)
.build();
default:
return builder.setBatterySaverEnabled(realMode)
.build();
}
}
}
BatterySaverPolicy.java 这个类很关键,所有关于省电模式的默认配置都在这个类里面初始化,如果要定制省电模式行为的话,这个类会被用到。
回调的流程的最终目的就是根据配置修改了 mLowPowerMode 变量的值,这个值会在调用振动时使用,用以决定要不要振动。
@GuardedBy("mLock")
private void startVibrationLocked(final Vibration vib) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
try {
//关于省电模式下是否允许振动在这个方法里判断
if (!isAllowedToVibrateLocked(vib)) {
return;
}
//
final int intensity = getCurrentIntensityLocked(vib);
if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
return;
}
//如果是来电且响铃时振动开关未打开,则不振动
if (vib.isRingtone() && !shouldVibrateForRingtone()) {
if (DEBUG) {
Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
}
return;
}
........................
}
private boolean isAllowedToVibrateLocked(Vibration vib) {
//如果不在省电模式则允许振动,如果在省电模式,排除掉以下几种情况外都不允许震动
if (!mLowPowerMode) {
return true;
}
//省电模式对铃声振动不影响
if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
return true;
}
//省电模式对 闹钟,辅助功能和 VoIP通话,视频通话 的振动不影响
if (vib.usageHint == AudioAttributes.USAGE_ALARM ||
vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
return true;
}
return false;
}
2. 降低屏幕亮度
frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java :
/**
* Updates the display power state asynchronously.
* When the update is finished, mDisplayReady will be set to true. The display
* controller posts a message to tell us when the actual display power state
* has been updated so we come back here to double-check and finish up.
*
* This function recalculates the display power state each time.
*
* @return True if the display became ready.
*/
private boolean updateDisplayPowerStateLocked(int dirty) {
.......................
updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);
..........................
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
..........................
}
@VisibleForTesting
void updatePowerRequestFromBatterySaverPolicy(DisplayPowerRequest displayPowerRequest) {
PowerSaveState state = mBatterySaverPolicy.
getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS,
mBatterySaverController.isEnabled());
displayPowerRequest.lowPowerMode = state.batterySaverEnabled;
displayPowerRequest.screenLowPowerBrightnessFactor = state.brightnessFactor;
}
frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java :
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mSyncRoot) {
return mDisplayPowerController.requestPowerState(request,
waitForNegativeProximity);
}
}
frameworks\base\services\core\java\com\android\server\display\DisplayPowerController.java
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
................................
if (changed && !mPendingRequestChangedLocked) {
mPendingRequestChangedLocked = true;
sendUpdatePowerStateLocked();
}
.................................
}
}
sendUpdatePowerStateLocked 内部交由 Handler 消息处理,最终会调用 updatePowerState 方法:
private void updatePowerState() {
............................
// If low power mode is enabled, scale brightness by screenLowPowerBrightnessFactor
// as long as it is above the minimum threshold.
if (mPowerRequest.lowPowerMode) {
if (brightness > mScreenBrightnessRangeMinimum) {
final float brightnessFactor =
Math.min(mPowerRequest.screenLowPowerBrightnessFactor, 1);// 亮度缩放比例
final int lowPowerBrightness = (int) (brightness * brightnessFactor);
brightness = Math.max(lowPowerBrightness, mScreenBrightnessRangeMinimum);
}
}
............................
}
BatterySaverPolicy.java 中定义的 默认亮度缩放比例是 0.5,亮度降低一半
mAdjustBrightnessDisabled = parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, true); //原生的配置是省电模式情况下默认不调节亮度
mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
3. WindowManagerService 动画
frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java :
mPowerManagerInternal.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() {
@Override
public int getServiceType() {
return ServiceType.ANIMATION;
}
@Override
public void onLowPowerModeChanged(PowerSaveState result) {
synchronized (mWindowMap) {
//BatterySaverPolicy中配置的是否要在低电量中关闭动画,android P上是 false,默认不关闭动画,8.0上是true的
final boolean enabled = result.batterySaverEnabled;
//mAllowAnimationsInLowPowerMode代表是否在允许在低电模式下继续使用动画(默认是false,就是不允许),如果在低电模式下会把WMS的动画都关闭
if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {
mAnimationsDisabled = enabled;
dispatchNewAnimatorScaleLocked(null);
}
}
}
});
9.0上低电量模式下是不关闭动画的,8.0上是关闭的。
4. NetworkPolicyManagerService.java 网络防火墙
frameworks\base\services\core\java\com\android\server\net\NetworkPolicyManagerService.java
private void updateRulesForRestrictPowerUL() {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL");
try {
updateRulesForDeviceIdleUL();
updateRulesForPowerSaveUL();
updateRulesForAllAppsUL(TYPE_RESTRICT_POWER);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
}
低电量模式下主要就是去更新网络访问的规则,没仔细研究,不敢妄言,Android P上也是默认没有打开限制的,开启低电量模式不去限制网络。
5. GPS 位置信息相关限制
frameworks\base\services\core\java\com\android\server\power\batterysaver\BatterySaverLocationPlugin.java :
private void updateLocationState(BatterySaverController caller) {
final boolean kill =
(caller.getBatterySaverPolicy().getGpsMode()
== PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF) &&
caller.isEnabled() && !caller.isInteractive();
if (DEBUG) {
Slog.d(TAG, "Battery saver " + (kill ? "stopping" : "restoring") + " location.");
}
Settings.Global.putInt(mContext.getContentResolver(),
Global.LOCATION_GLOBAL_KILL_SWITCH, kill ? 1 : 0);
}
/**
* If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link Secure#LOCATION_MODE_OFF}
* temporarily for all users.
*
* @hide
*/
@TestApi
public static final String LOCATION_GLOBAL_KILL_SWITCH =
"location_global_kill_switch";
低电量情况下,灭屏后会关闭GPS,临时限制所有应用访问位置信息。
以上都是 开启低电量模式后,BatterySaverController.java 中主动去回调的,以下是 各模块自己监听 ACTION_POWER_SAVE_MODE_CHANGED 广播后自己处理的
6. 语音互动的功能
frameworks\base\services\voiceinteraction\java\com\android\server\soundtrigger\SoundTriggerHelper.java :
// A single routine that implements the start recognition logic for both generic and keyphrase
// models.
private int startRecognitionLocked(ModelData modelData, boolean notify) {
...........................
if (!isRecognitionAllowed()) {
// Nothing to do here.
Slog.w(TAG, "startRecognition requested but not allowed.");
MetricsLogger.count(mContext, "sth_start_recognition_not_allowed", 1);
return STATUS_OK;
}
}
// Whether we are allowed to run any recognition at all. The conditions that let us run
// a recognition include: no active phone call or not being in a power save mode. Also,
// the native service should be enabled.
private boolean isRecognitionAllowed() {
return !mCallActive && !mServiceDisabled && !mIsPowerSaveMode;
}
低电量模式下不识别语音
其他各上层模块,如settings,systemUI 也监听了 ACTION_POWER_SAVE_MODE_CHANGED 广播,主要是做一些 UI上的变化。