Android|Android P 省电模式(LowPowerMode)(二) ------ 省电行为

在上篇文章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 typetype 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,亮度降低一半
【Android|Android P 省电模式(LowPowerMode)(二) ------ 省电行为】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上的变化。

    推荐阅读