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 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上的变化。

你可能感兴趣的:(Android P 省电模式(LowPowerMode)(二) ------ 省电行为)