我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android PowerManagerService 打开省电模式

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android PowerManagerService 打开省电模式

概要

初识Android PowerManagerService省电模式对省电模式进行了一个初步认识,介绍了一些概念,以及对省电模式环境初始化的代码进行了简单分析。读者需要仔细阅读第一篇文章,再来看这一篇文章。

打开省电模式,有三种方式:

  • 手动模式,也就是用户手动打开省电模式。
  • 自动模式,用户设置一个电量百分比阈值,当电量低于这个阈值,自动触发省电模式。
  • 动态模式,这种模式其实就是自动模式。根据文档,这个模式是提供给应用,根据情况自动调整触发省电模式的阈值。

本文只关注如下内容:

  • 省电模式的打开过程。
  • 什么是 battery saver sticky 模式。

只要掌握了上面2点内容,自动模式、动态模式,都可以自行分析。

打开省电模式

现在以手动打开省电模式为例,分析省电模式的打开过程。

从初识Android PowerManagerService省电模式可知,在 Settings->Battery->Battery Saver 界面,可以手动打开省电模式,调用代码如下

最终会调用 PowerManagerService 对应的方法:

public boolean setPowerSaveModeEnabled(boolean enabled) {
    if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER)
            != PackageManager.PERMISSION_GRANTED) {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.DEVICE_POWER, null);
    }
    final long ident = Binder.clearCallingIdentity();
    try {
        return setLowPowerModeInternal(enabled);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}


private boolean setLowPowerModeInternal(boolean enabled) {
    synchronized (mLock) {
        // 充电状态下,不允许打开/关闭省电模式
        if (mIsPowered) {
            return false;
        }

        mBatterySaverStateMachine.setBatterySaverEnabledManually(enabled);

        return true;
    }
}

在 AOSP 的设计中,省电模式和充电状态是冲突的。如果设备处于省电模式状态,此时插入充电器,那么一定会关闭省电模式。如果设备处于充电状态,那么是不允许打开省电模式的。

说实话,我不是很认同这种设计。我认为省电模式是用户的强烈个人意愿,只能由用户自己决定打开或者关闭。

BatterySaverStateMachine状态管理

从上面代码可知,打开省电模式时,通过 BatterySaverStateMachine#setBatterySaverEnabledManually() 方法,把指令传给状态机

public void setBatterySaverEnabledManually(boolean enabled) {
    synchronized (mLock) {
        updateStateLocked(true, enabled);
    }
}

状态机通过 updateStateLocked() 更新内部状态,然后根据状态执行相应的操作。 注意,这里的第一个参数表示是否是用户手动打开省电模式,值为 true,第二个参数表示是否打开省电模式,根据我们分析的例子,这里的值为 true。

    private void updateStateLocked(boolean manual, boolean enable) {
        if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
            return; // Not fully initialized yet.
        }

        switch (mState) {
            case STATE_OFF: {
                if (!mIsPowered) { // 非充电模式,才允许操作省电模式
                    if (manual) { // 手动操作
                        if (!enable) {
                            return;
                        }
                        // 用户手动打开省电模式
                        enableBatterySaverLocked( true,  true,
                                BatterySaverController.REASON_MANUAL_ON);
                        hideStickyDisabledNotification();
                        // 状态切换为 STATE_MANUAL_ON
                        mState = STATE_MANUAL_ON;
                    } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) {
                        // ... 自动模式
                    } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) { 
                        // ... 动态模式
                    }
                }
                break;
            }

            // ...
        }
    }

状态机里的默认状态是 STATE_OFF,表示省电模式默认关闭。

通过 enableBatterySaverLocked( true, true, BatterySaverController.REASON_MANUAL_ON); 打开省电模式,然后把状态切换为 STATE_MANUAL_ON。对于每一次状态切换,我们都要注意,因此这会影响下一次状态切换。

private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason) {
    enableBatterySaverLocked(enable, manual, intReason, reasonToString(intReason));
}

private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason,
        String strReason) {
    final boolean wasEnabled = mBatterySaverController.isFullEnabled();
    // 已经处于省电模式状态
    if (wasEnabled == enable) {
        return;
    }

    // 充电中,是不允许打开省电模式的
    if (enable && mIsPowered) {
        return;
    }

    mLastChangedIntReason = intReason;
    mLastChangedStrReason = strReason;

    mSettingBatterySaverEnabled = enable;
    // 1. 保存省电模式的状态
    putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0);

    // 2. 打开 battery saver sticky 模式
    if (manual) { // 用户手动操作省电模式
        // mBatterySaverStickyBehaviourDisabled 默认为 false,表示支持 battery saver sticky 模式
        setStickyActive(!mBatterySaverStickyBehaviourDisabled && enable);
    }

    // 3. 通过 BatterySaverController 打开省电模式
    mBatterySaverController.enableBatterySaver(enable, intReason);

    // 动态省电模式相关
    if (intReason == BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON) {
        triggerDynamicModeNotification();
    } else if (!enable) {
        hideDynamicModeNotification();
    }
}

在打开省电模式之前,首先把数据库 Settings.Global.LOW_POWER_MODE 字段的值保存为 1。

low power 应该翻译为低功耗,俗称省电模式,而 low battery 才应该翻译为低电量,不要混淆了。 源码中 BatteryManagerService#getBatteryLevelLow() 表示电量是否低于自动省电模式的电量百分比,这个函数的命名非常差劲,一度让我误以为是低电量(电量低于15%),其实它表示是否触发了自动省电模式。

第二步,我们要注意了,这里涉及了 battery saver sticky 功能。根据判断条件可知,只有在用户手动操作省电模式的情况下,才会触发 battery saver sticky 功能,来看下 setStickyActive()

private void setStickyActive(boolean active) {
    // 表示 battery saver sticky 模式已经打开
    mSettingBatterySaverEnabledSticky = active;
    // Settings.Global.LOW_POWER_MODE_STICKY 代表 battery saver sticky功能的状态
    putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY,
            mSettingBatterySaverEnabledSticky ? 1 : 0);
}

很简单,就是保存状态,表示 battery saver sticky 功能已经打开。

第三步,把打开省电模式的实际操作,交给了省电模式控制器 BatterySaverController

BatterySaverController切换省电模式

现在来看下 BatterySaverController#enableBatterySaver() 如何打开省电模式

public void enableBatterySaver(boolean enable, int reason) {
    synchronized (mLock) {
        if (getFullEnabledLocked() == enable) {
            return;
        }
        // 1. 保存省电模式的状态
        setFullEnabledLocked(enable);

        // 2. 更新省电模式策略
        if (updatePolicyLevelLocked()) {
            // 3. 处理省电模式状态的改变
            mHandler.postStateChanged( true, reason);
        }
    }
}

private boolean getFullEnabledLocked() {
    return mFullEnabledRaw;
}
private void setFullEnabledLocked(boolean value) {
    if (mFullEnabledRaw == value) {
        return;
    }
    // 刷新省电模式的缓存,客户端可以通过 PowerManager 获取省电模式状态
    PowerManager.invalidatePowerSaveModeCaches();
    mFullEnabledRaw = value;
}

首先使用 mFullEnabledRaw 保存省电模式状态。

然后,更新省电模式的策略。省电模式会影响很多模块的功能,例如,最直观的就是影响屏幕亮度。因此打开省电模式,必须得有一个策略,这些策略影响某些模块的功能。

最后,处理省电模式状态的改变。其中包括切换省电模式,通知省电模式的监听者。

mFullEnabledRaw 表示 full battery saver,其实就是用户用到的省电模式。其实还有一种省电模式 adaptive battery saver,这种省电模式,是通过命令行设置的,应该是与测试相关,执行 adb shell power set-adaptive-power-saver-enabled true 来开启,具体可以参考 PowerManagerShellCommand 类。

BattterySaverPolicy控制省电策略

现在来看下 BatterySaverController#updatePolicyLevelLocked() 如何更新省电模式策略

private boolean updatePolicyLevelLocked() {
    if (getFullEnabledLocked()) {
        // 设置省电模式 policy level
        return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_FULL);
    } else if (getAdaptiveEnabledLocked()) {
        return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_ADAPTIVE);
    } else {
        return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_OFF);
    }
}

原来是给 BatterySaverPolicy 设置了 policy level,值为 BatterySaverPolicy.POLICY_LEVEL_FULL

boolean setPolicyLevel(@PolicyLevel int level) {
    synchronized (mLock) {
        if (mPolicyLevel == level) {
            return false;
        }
        if (mPolicyLevel == POLICY_LEVEL_FULL) {
            mFullPolicy = mDefaultFullPolicy;
        }
        switch (level) {
            case POLICY_LEVEL_FULL:
            case POLICY_LEVEL_ADAPTIVE:
            case POLICY_LEVEL_OFF:
                // 1. 保存 level
                mPolicyLevel = level;
                break;
            default:
                Slog.wtf(TAG, "setPolicyLevel invalid level given: " + level);
                return false;
        }
        // 2. 根据 level,更新有效的 policy
        updatePolicyDependenciesLocked();
        return true;
    }
}

BatterSaverPolicy 保存了 policy level,并且调用 updatePolicyDependenciesLocked() 来更新有效的 battery saver policy

private void updatePolicyDependenciesLocked() {
    // 1. 根据 policy level, 获取对应的 policy
    final Policy rawPolicy = getCurrentRawPolicyLocked();

    // 刷新省电模式缓存
    invalidatePowerSaveModeCaches();

    // 车载
    final int locationMode;
    if (mAutomotiveProjectionActive.get()
            && rawPolicy.locationMode != PowerManager.LOCATION_MODE_NO_CHANGE
            && rawPolicy.locationMode != PowerManager.LOCATION_MODE_FOREGROUND_ONLY) {
        // If car projection is enabled, ensure that navigation works.
        locationMode = PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
    } else {
        locationMode = rawPolicy.locationMode;
    }

    // 2. 根据获取的策略,来更新有效的策略
    // mEffectivePolicyRaw 表示实际生效的 policy
    // mEffectivePolicyRaw 的数据,基本上都是从 rawPolicy 中复制过来的
    // 只有几项是需要调整的,例如 车载 或者 无障碍,这两个特殊的情况,在使用时注意下即可
    mEffectivePolicyRaw = new Policy(
            rawPolicy.adjustBrightnessFactor,
            rawPolicy.advertiseIsEnabled,
            rawPolicy.cpuFrequenciesForInteractive,
            rawPolicy.cpuFrequenciesForNoninteractive,
            rawPolicy.deferFullBackup,
            rawPolicy.deferKeyValueBackup,
            rawPolicy.disableAnimation,
            rawPolicy.disableAod,
            rawPolicy.disableLaunchBoost,
            rawPolicy.disableOptionalSensors,
            // Don't disable vibration when accessibility is on.
            rawPolicy.disableVibration && !mAccessibilityEnabled.get(),
            rawPolicy.enableAdjustBrightness,
            rawPolicy.enableDataSaver,
            rawPolicy.enableFirewall,
            // Don't force night mode when car projection is enabled.
            rawPolicy.enableNightMode && !mAutomotiveProjectionActive.get(),
            rawPolicy.enableQuickDoze,
            rawPolicy.forceAllAppsStandby,
            rawPolicy.forceBackgroundCheck,
            locationMode,
            rawPolicy.soundTriggerMode
    );
    // ...
}

// 默认省电模式策略
private Policy mFullPolicy = DEFAULT_FULL_POLICY;

private Policy getCurrentRawPolicyLocked() {
    switch (mPolicyLevel) {
        case POLICY_LEVEL_FULL:
            return mFullPolicy;
        case POLICY_LEVEL_ADAPTIVE:
            return mAdaptivePolicy;
        case POLICY_LEVEL_OFF:
        default:
            return OFF_POLICY;
    }
}

getCurrentRawPolicyLocked() 会获取默认的省电模式策略 DEFAULT_FULL_POLICY,然后根据一些情况调整省电模式策略,最后形成有效的省电模式策略 mEffectivePolicyRaw

现在让我们看看这个默认的省电策略 DEFAULT_FULL_POLICY 到底是何方神圣

private static final Policy DEFAULT_FULL_POLICY = new Policy(
        0.5f,  
        true,  
        new CpuFrequencies(), 
        new CpuFrequencies(), 
        true,  
        true,  
        false, 
        true,  
        true,  
        true,  
        true,  
        false, 
        false, 
        true,  
        true, 
        true, 
        true, 
        true, 
        PowerManager.LOCATION_MODE_FOREGROUND_ONLY, 
        PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY 
);

Policy 就是一个数据封装类,看下它构造函数的参数,我们就能大致猜测出省电模式影响哪些模块的功能。

这里注意下第三个和第四个参数,它表示省电模式下,需要限制频率的 CPU 的编号以及限制的频率值,这里默认是空,后面会用到。

处理省电模式状态改变

现在让我们回到打开省电模式的代码

public void enableBatterySaver(boolean enable, int reason) {
    synchronized (mLock) {
        if (getFullEnabledLocked() == enable) {
            return;
        }
        // 1. 保存省电模式的状态
        setFullEnabledLocked(enable);

        // 2. 更新省电模式策略
        if (updatePolicyLevelLocked()) {
            // 3. 处理省电模式状态的改变
            mHandler.postStateChanged( true, reason);
        }
    }
}

前两步已经分析完毕,现在来看看第三步,它最终会调用 BatterySaverController#handleBatterySaverStateChanged() 来处理省电模式状态改变

void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) {
    final LowPowerModeListener[] listeners;

    final boolean enabled;
    // 获取设备是否处于交互状态
    // 一般来说,如果屏幕熄灭,设备处于非交互状态,屏幕电量,设备处于交互状态
    final boolean isInteractive = getPowerManager().isInteractive();
    final ArrayMap<String, String> fileValues;

    synchronized (mLock) {
        // 获取省电模式的状态
        enabled = getFullEnabledLocked() || getAdaptiveEnabledLocked();

        // 保存前一个 full battery saver状态
        mFullPreviouslyEnabled = getFullEnabledLocked();
        // 保存前一个adaptive battery saver状态
        mAdaptivePreviouslyEnabled = getAdaptiveEnabledLocked();

        listeners = mListeners.toArray(new LowPowerModeListener[0]);

        mIsInteractive = isInteractive;

        if (enabled) {
            // 1. 打开省电模式情况下,获取频率受限的CPU的编号以及受限的值
            fileValues = mBatterySaverPolicy.getFileValues(isInteractive);
        } else {
            fileValues = null;
        }
    }

    // 2. 通过 PowerManagerService 向底层设置省电模式
    final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
    if (pmi != null) {
        pmi.setPowerMode(Mode.LOW_POWER, isEnabled());
    }

    // 用 BatterySavingStats 记录数据
    updateBatterySavingStats();

    // 3. 根据策略,限制或恢复CPU频率
    if (ArrayUtils.isEmpty(fileValues)) {
        // CPU 策略为空,表示需要恢复 CPU 之前的频率
        mFileUpdater.restoreDefault();
    } else {
        // CPU 频率策略不为空,表示需要限制 CPU 频率
        mFileUpdater.writeFiles(fileValues);
    }

    if (sendBroadcast) {
        // 4. 发送广播
        Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);

        // 可以在 frameworks-res 的配置文件中配置一个应用的包名
        // 这个应用可以在manifest.xml中注册广播接收器,接收省电模式状态改变
        if (getPowerSaveModeChangedListenerPackage().isPresent()) {
            intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)
                    .setPackage(getPowerSaveModeChangedListenerPackage().get())
                    .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
                            | Intent.FLAG_RECEIVER_FOREGROUND);
            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
        }

        // 发送一个内部版本的广播,但是接收者需要权限
        intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                Manifest.permission.DEVICE_POWER);

        // 5. 通知监听者
        for (LowPowerModeListener listener : listeners) {
            final PowerSaveState result =
                    mBatterySaverPolicy.getBatterySaverPolicy(listener.getServiceType());
            listener.onLowPowerModeChanged(result);
        }
    }
}

第一步和第三步,是在省电模式下限制 CPU 频率的。根据前面分析可知,目前默认策略是没有配置CPU频率的,因此这两步不分析了。我将在后面的文章中,分析如何控制省电模式策略,到时候再来分析这里的代码逻辑。

第二步,通过 PowerManagerService 向底层设置省电模式,底层称之为低功耗模式(low power mode)。

第四步,发送省电模式状态改变的广播。

第五步,通知监听者。谁会是监听者呢?当然是那些受省电模式影响的模块。

让我们看下返回给监听者的数据到底是什么?看下mBatterySaverPolicy.getBatterySaverPolicy(listener.getServiceType())

    public PowerSaveState getBatterySaverPolicy(@ServiceType int type) {
        synchronized (mLock) {
            final Policy currPolicy = getCurrentPolicyLocked();
            final PowerSaveState.Builder builder = new PowerSaveState.Builder()
                    .setGlobalBatterySaverEnabled(currPolicy.advertiseIsEnabled);
            switch (type) {
                case ServiceType.LOCATION:
                    boolean isEnabled = currPolicy.advertiseIsEnabled
                            || currPolicy.locationMode != PowerManager.LOCATION_MODE_NO_CHANGE;
                    return builder.setBatterySaverEnabled(isEnabled)
                            .setLocationMode(currPolicy.locationMode)
                            .build();
                case ServiceType.ANIMATION:
                    return builder.setBatterySaverEnabled(currPolicy.disableAnimation)
                            .build();
                // ...

                case ServiceType.VIBRATION:
                    return builder.setBatterySaverEnabled(currPolicy.disableVibration)
                            .build();
                case ServiceType.FORCE_ALL_APPS_STANDBY:
                    return builder.setBatterySaverEnabled(currPolicy.forceAllAppsStandby)
                            .build();
                case ServiceType.FORCE_BACKGROUND_CHECK:
                    return builder.setBatterySaverEnabled(currPolicy.forceBackgroundCheck)
                            .build();
                // ...
                default:
                    return builder.setBatterySaverEnabled(currPolicy.advertiseIsEnabled)
                            .build();
            }
        }
    }

原来,根据监听者的类型,返回一个 PowerSaveState 对象,这个对象中只包含了监听者关心的数据。

从这里,我们应该有所领悟,如果我们自己开发了一个功能模块

  • 如果受省电模式策略影响,必须注册一个监听器,获取省电模式下策略,然后调整模块的功能。
  • 如果这个模块是个耗电大户,那么必须监听省电模式,在省电模式下执行相应的操作。

现在很多项目都关注电量消耗问题,省电模式到底能让手机待机多长时间,也是一个考核的指标。

battery saver sticky 模式

根据前面的分析,只有在用户手动操作省电模式的时候,才会相应的打开或者关闭 battery saver sticky 模式。

我先总结下什么是 battery saver sticky 模式? 当手机已经处于省电模式,插入电源,系统会默认关闭省电模式,如果此时拔掉电源或者手机重启,当 battery saver sticky 功能已经打开的情况下,系统会重新打开省电模式。

现在让我们从代码角度分析,继续使用上面的例子分析,假如现在已经打开了省电模式,此时插入了电源,来看下状态机的切换动作 BatterySaverStateMachine#updateStateLocked()

    private void updateStateLocked(boolean manual, boolean enable) {
        if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
            return; // Not fully initialized yet.
        }

        switch (mState) {
            case STATE_OFF: {
                if (!mIsPowered) { // 充电状态下,不允许打开省电模式
                    if (manual) { // 手动模式
                        if (!enable) {
                            Slog.e(TAG, "Tried to disable BS when it's already OFF");
                            return;
                        }
                        enableBatterySaverLocked( true,  true,
                                BatterySaverController.REASON_MANUAL_ON);
                        hideStickyDisabledNotification();
                        // 1. 用户打开省电模式,状态切换为 STATE_MANUAL_ON
                        mState = STATE_MANUAL_ON;
                    } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) {
                        // 自动模式 ...
                    } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) {
                        // 动态模式 ...
                    }
                }
                break;
            }

            case STATE_MANUAL_ON: {
                if (manual) {
                    // ...
                } else if (mIsPowered) { // 2. 插入电源
                    // 关闭省电模式
                    enableBatterySaverLocked( false,  false,
                            BatterySaverController.REASON_PLUGGED_IN);
                    // 手动打开省电模式时,mSettingBatterySaverEnabledSticky 设置为 true
                    // mBatterySaverStickyBehaviourDisabled 默认为 false,表示支持这个 feature
                    if (mSettingBatterySaverEnabledSticky
                            && !mBatterySaverStickyBehaviourDisabled) {
                        // 插入电源,状态切换为 STATE_PENDING_STICKY_ON
                        mState = STATE_PENDING_STICKY_ON;
                    } else {
                        mState = STATE_OFF;
                    }
                }
                break;
            }

            // ...

            case STATE_PENDING_STICKY_ON: { // 3. battery saver sticky 模式操作
                if (manual) {
                    return;
                }
                // mSettingBatterySaverStickyAutoDisableEnabled 对应 Battery Saver界面下的 Turn off when charging 开关
                // mSettingBatterySaverStickyAutoDisableThreshold 默认值为 90
                final boolean shouldTurnOffSticky = mSettingBatterySaverStickyAutoDisableEnabled
                        && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold;
                // 手动打开省电模式,再插入电源,此时 isStickyDisabled 值为 false
                final boolean isStickyDisabled =
                        mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky;
                if (isStickyDisabled || shouldTurnOffSticky) {
                    // 3.2 如果Turn off when charging 开关被打开,并且电量大于90%,那么不会重新打开省电模式
                    mState = STATE_OFF;
                    setStickyActive(false);
                    triggerStickyDisabledNotification();
                } else if (!mIsPowered) {
                    // Re-enable BS.
                    // 3.1 断开电源,重新打开省电模式
                    enableBatterySaverLocked( true,  true,
                            BatterySaverController.REASON_STICKY_RESTORE);
                    mState = STATE_MANUAL_ON;
                }
                break;
            }
            // ...
        }
    }

首先看下第一步,它打开了省电模式,并且状态切换为 STATE_MANUAL_ON

如果此时,插入电源,那么会进入第二步, 关闭省电模式, 并把状态切换为 STATE_PENDING_STICKY_ON

如果关闭了设置中 Battery Saver 界面的 Turn off when Charging 开关,此时拔掉电源,那么进入 3.1 步,又会再次打开省电模式,这就是 sticky 的含义。

如果打开了设置中 Battery Saver 界面的 Turn off when Charging 开关,那么进入 3.2 步,不会再次打开省电模式。

设置中 Battery Saver 界面的 Turn off when Charging 开关就是 battery saver sticky auto disable 功能。

结束

通读了整个省电模式的代码,给我的感觉是很多功能都非常鸡肋,限于偏于原因,我只分析了核心的代码,那就是如何切换省电模式。剩下的其他功能,留给读者自行分析。

到此这篇关于Android PowerManagerService 打开省电模式的文章就介绍到这了,更多相关Android PowerManagerService 内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android PowerManagerService 打开省电模式

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

win10平板模式省电吗

本文小编为大家详细介绍“win10平板模式省电吗”,内容详细,步骤清晰,细节处理妥当,希望这篇“win10平板模式省电吗”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。win10平板模式会省电吗:答:不会省电,和桌
2023-07-01

android怎么打开开发者模式

要打开Android设备上的开发者模式,请按照以下步骤操作:1. 打开手机的设置菜单,可以在应用列表中找到设置图标,通常是一个齿轮或者一个齿轮加锁的图标。2. 在设置菜单中,向下滚动找到“关于手机”或“关于设备”的选项,然后点击它。3. 在
2023-09-12

电脑表格打开是兼容模式如何弄

要将电脑表格打开为兼容模式,您可以按照以下步骤进行操作:1. 打开电脑表格应用程序(例如Microsoft Excel)。2. 在菜单栏中,找到“文件”选项并点击打开。3. 在文件浏览器中,选择您要打开的表格文件,并点击“打开”按钮。4.
2023-09-11

电脑360浏览器极速模式如何打开

这篇文章主要介绍“电脑360浏览器极速模式如何打开”,在日常操作中,相信很多人在电脑360浏览器极速模式如何打开问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”电脑360浏览器极速模式如何打开”的疑惑有所帮助!
2023-07-01

电脑显示器黑屏显示省电模式如何解决

这篇文章主要介绍“电脑显示器黑屏显示省电模式如何解决”,在日常操作中,相信很多人在电脑显示器黑屏显示省电模式如何解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”电脑显示器黑屏显示省电模式如何解决”的疑惑有所
2023-07-01

在Windows电脑上以安全模式打开Office应用

在Windows电脑上以安全模式打开Office应用,可以按照以下步骤操作:1. 关闭所有Office应用程序。2. 按下Windows键+R键打开运行对话框。3. 在运行对话框中输入"winword /safe"(如果要打开Word)或"
2023-09-14

win11如何打开开发者模式

今天小编给大家分享一下win11如何打开开发者模式的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1、首先点击任务栏最左边的w
2023-07-02

win10电脑怎么打开高性能模式加速游戏

这篇文章主要介绍“win10电脑怎么打开高性能模式加速游戏”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“win10电脑怎么打开高性能模式加速游戏”文章能帮助大家解决问题。开启方法/步骤:1.打开wi
2023-06-27

Android软键盘显示模式及打开和关闭方式(推荐)

Android软键盘显示模式: Android定义了一个属性,名字为windowSoftInputMode, 用它可以让程序可以控制活动主窗口调整的方式。我们可以在AndroidManifet.xml中对Activity进行设置。如
2022-06-06

wps怎么打开ppt模式

这篇文章主要介绍“wps怎么打开ppt模式”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“wps怎么打开ppt模式”文章能帮助大家解决问题。1、首先打开wps,然后进入软件。 2、之后可以点击左侧的“
2023-07-02

详解Android MVP开发模式

本文主要讲解MVP开发模式以及具体实例。一、简介 MVP(Model View Presenter)模式是著名的MVC(Model View Controller)模式的一个演化版本,目前它在Android应用开发中越来越重要了。初看起来我
2022-06-06

win10怎么开启节电模式

今天就跟大家聊聊有关win10怎么开启节电模式,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。很多时候为了提高笔记本电脑的用电时间和效率,特别是电脑电池容量不大的,很多人都会选择开启电
2023-06-27

win101903游戏模式怎么打开

今天小编给大家分享一下win101903游戏模式怎么打开的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。简介: 打开专注助手在
2023-07-02

win10护眼模式如何打开

要打开Windows 10的护眼模式,您可以按照以下步骤操作:1. 点击Windows开始菜单,然后选择“设置”(图标为齿轮状)。2. 在“设置”窗口中,点击“系统”选项。3. 在“系统”窗口中,点击左侧的“显示”选项。4. 在右侧找到“亮
2023-09-12

Wordpress怎么打开调试模式

这篇文章主要介绍“Wordpress怎么打开调试模式”,在日常操作中,相信很多人在Wordpress怎么打开调试模式问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Wordpress怎么打开调试模式”的疑惑有所
2023-06-04

csm如何打开兼容模式

这篇文章主要介绍了csm如何打开兼容模式的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇csm如何打开兼容模式文章都会有所收获,下面我们一起来看看吧。csm打开兼容模式的方法:1、首先把电脑重启,在重启时连续按D
2023-03-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录