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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269