溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android?PowerManagerService打開省電模式怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2022-08-24 15:59:45 來源:億速云 閱讀:302 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“Android PowerManagerService打開省電模式怎么實(shí)現(xiàn)”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Android PowerManagerService打開省電模式怎么實(shí)現(xiàn)”吧!

    概要

    打開省電模式,有三種方式:

    • 手動(dòng)模式,也就是用戶手動(dòng)打開省電模式。

    • 自動(dòng)模式,用戶設(shè)置一個(gè)電量百分比閾值,當(dāng)電量低于這個(gè)閾值,自動(dòng)觸發(fā)省電模式。

    • 動(dòng)態(tài)模式,這種模式其實(shí)就是自動(dòng)模式。根據(jù)文檔,這個(gè)模式是提供給應(yīng)用,根據(jù)情況自動(dòng)調(diào)整觸發(fā)省電模式的閾值。

    本文只關(guān)注如下內(nèi)容:

    • 省電模式的打開過程。

    • 什么是 battery saver sticky 模式。

    只要掌握了上面2點(diǎn)內(nèi)容,自動(dòng)模式、動(dòng)態(tài)模式,都可以自行分析。

    打開省電模式

    現(xiàn)在以手動(dòng)打開省電模式為例,分析省電模式的打開過程。

    從初識(shí)Android PowerManagerService省電模式可知,在 Settings->Battery->Battery Saver 界面,可以手動(dòng)打開省電模式,調(diào)用代碼如下

    最終會(huì)調(diào)用 PowerManagerService 對應(yīng)的方法:

    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) {
            // 充電狀態(tài)下,不允許打開/關(guān)閉省電模式
            if (mIsPowered) {
                return false;
            }
    
            mBatterySaverStateMachine.setBatterySaverEnabledManually(enabled);
    
            return true;
        }
    }

    在 AOSP 的設(shè)計(jì)中,省電模式和充電狀態(tài)是沖突的。如果設(shè)備處于省電模式狀態(tài),此時(shí)插入充電器,那么一定會(huì)關(guān)閉省電模式。如果設(shè)備處于充電狀態(tài),那么是不允許打開省電模式的。

    說實(shí)話,我不是很認(rèn)同這種設(shè)計(jì)。我認(rèn)為省電模式是用戶的強(qiáng)烈個(gè)人意愿,只能由用戶自己決定打開或者關(guān)閉。

    BatterySaverStateMachine狀態(tài)管理

    從上面代碼可知,打開省電模式時(shí),通過 BatterySaverStateMachine#setBatterySaverEnabledManually() 方法,把指令傳給狀態(tài)機(jī)

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

    狀態(tài)機(jī)通過 updateStateLocked() 更新內(nèi)部狀態(tài),然后根據(jù)狀態(tài)執(zhí)行相應(yīng)的操作。 注意,這里的第一個(gè)參數(shù)表示是否是用戶手動(dòng)打開省電模式,值為 true,第二個(gè)參數(shù)表示是否打開省電模式,根據(jù)我們分析的例子,這里的值為 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) { // 手動(dòng)操作
                            if (!enable) {
                                return;
                            }
                            // 用戶手動(dòng)打開省電模式
                            enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
                                    BatterySaverController.REASON_MANUAL_ON);
                            hideStickyDisabledNotification();
                            // 狀態(tài)切換為 STATE_MANUAL_ON
                            mState = STATE_MANUAL_ON;
                        } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) {
                            // ... 自動(dòng)模式
                        } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) { 
                            // ... 動(dòng)態(tài)模式
                        }
                    }
                    break;
                }
    
                // ...
            }
        }

    狀態(tài)機(jī)里的默認(rèn)狀態(tài)是 STATE_OFF,表示省電模式默認(rèn)關(guān)閉。

    通過 enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, BatterySaverController.REASON_MANUAL_ON); 打開省電模式,然后把狀態(tài)切換為 STATE_MANUAL_ON。對于每一次狀態(tài)切換,我們都要注意,因此這會(huì)影響下一次狀態(tài)切換。

    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();
        // 已經(jīng)處于省電模式狀態(tài)
        if (wasEnabled == enable) {
            return;
        }
    
        // 充電中,是不允許打開省電模式的
        if (enable && mIsPowered) {
            return;
        }
    
        mLastChangedIntReason = intReason;
        mLastChangedStrReason = strReason;
    
        mSettingBatterySaverEnabled = enable;
        // 1. 保存省電模式的狀態(tài)
        putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0);
    
        // 2. 打開 battery saver sticky 模式
        if (manual) { // 用戶手動(dòng)操作省電模式
            // mBatterySaverStickyBehaviourDisabled 默認(rèn)為 false,表示支持 battery saver sticky 模式
            setStickyActive(!mBatterySaverStickyBehaviourDisabled && enable);
        }
    
        // 3. 通過 BatterySaverController 打開省電模式
        mBatterySaverController.enableBatterySaver(enable, intReason);
    
        // 動(dòng)態(tài)省電模式相關(guān)
        if (intReason == BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON) {
            triggerDynamicModeNotification();
        } else if (!enable) {
            hideDynamicModeNotification();
        }
    }

    在打開省電模式之前,首先把數(shù)據(jù)庫 Settings.Global.LOW_POWER_MODE 字段的值保存為 1。

    low power 應(yīng)該翻譯為低功耗,俗稱省電模式,而 low battery 才應(yīng)該翻譯為低電量,不要混淆了。 源碼中 BatteryManagerService#getBatteryLevelLow() 表示電量是否低于自動(dòng)省電模式的電量百分比,這個(gè)函數(shù)的命名非常差勁,一度讓我誤以為是低電量(電量低于15%),其實(shí)它表示是否觸發(fā)了自動(dòng)省電模式。

    第二步,我們要注意了,這里涉及了 battery saver sticky 功能。根據(jù)判斷條件可知,只有在用戶手動(dòng)操作省電模式的情況下,才會(huì)觸發(fā) battery saver sticky 功能,來看下 setStickyActive()

    private void setStickyActive(boolean active) {
        // 表示 battery saver sticky 模式已經(jīng)打開
        mSettingBatterySaverEnabledSticky = active;
        // Settings.Global.LOW_POWER_MODE_STICKY 代表 battery saver sticky功能的狀態(tài)
        putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY,
                mSettingBatterySaverEnabledSticky ? 1 : 0);
    }

    很簡單,就是保存狀態(tài),表示 battery saver sticky 功能已經(jīng)打開。

    第三步,把打開省電模式的實(shí)際操作,交給了省電模式控制器 BatterySaverController。

    BatterySaverController切換省電模式

    現(xiàn)在來看下 BatterySaverController#enableBatterySaver() 如何打開省電模式

    public void enableBatterySaver(boolean enable, int reason) {
        synchronized (mLock) {
            if (getFullEnabledLocked() == enable) {
                return;
            }
            // 1. 保存省電模式的狀態(tài)
            setFullEnabledLocked(enable);
    
            // 2. 更新省電模式策略
            if (updatePolicyLevelLocked()) {
                // 3. 處理省電模式狀態(tài)的改變
                mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
            }
        }
    }
    
    private boolean getFullEnabledLocked() {
        return mFullEnabledRaw;
    }
    private void setFullEnabledLocked(boolean value) {
        if (mFullEnabledRaw == value) {
            return;
        }
        // 刷新省電模式的緩存,客戶端可以通過 PowerManager 獲取省電模式狀態(tài)
        PowerManager.invalidatePowerSaveModeCaches();
        mFullEnabledRaw = value;
    }

    首先使用 mFullEnabledRaw 保存省電模式狀態(tài)。

    然后,更新省電模式的策略。省電模式會(huì)影響很多模塊的功能,例如,最直觀的就是影響屏幕亮度。因此打開省電模式,必須得有一個(gè)策略,這些策略影響某些模塊的功能。

    最后,處理省電模式狀態(tài)的改變。其中包括切換省電模式,通知省電模式的監(jiān)聽者。

    mFullEnabledRaw 表示 full battery saver,其實(shí)就是用戶用到的省電模式。其實(shí)還有一種省電模式 adaptive battery saver,這種省電模式,是通過命令行設(shè)置的,應(yīng)該是與測試相關(guān),執(zhí)行 adb shell power set-adaptive-power-saver-enabled true 來開啟,具體可以參考 PowerManagerShellCommand 類。

    BattterySaverPolicy控制省電策略

    現(xiàn)在來看下 BatterySaverController#updatePolicyLevelLocked() 如何更新省電模式策略

    private boolean updatePolicyLevelLocked() {
        if (getFullEnabledLocked()) {
            // 設(shè)置省電模式 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 設(shè)置了 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. 根據(jù) level,更新有效的 policy
            updatePolicyDependenciesLocked();
            return true;
        }
    }

    BatterSaverPolicy 保存了 policy level,并且調(diào)用 updatePolicyDependenciesLocked() 來更新有效的 battery saver policy。

    private void updatePolicyDependenciesLocked() {
        // 1. 根據(jù) policy level, 獲取對應(yīng)的 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. 根據(jù)獲取的策略,來更新有效的策略
        // mEffectivePolicyRaw 表示實(shí)際生效的 policy
        // mEffectivePolicyRaw 的數(shù)據(jù),基本上都是從 rawPolicy 中復(fù)制過來的
        // 只有幾項(xiàng)是需要調(diào)整的,例如 車載 或者 無障礙,這兩個(gè)特殊的情況,在使用時(shí)注意下即可
        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
        );
        // ...
    }
    
    // 默認(rèn)省電模式策略
    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() 會(huì)獲取默認(rèn)的省電模式策略 DEFAULT_FULL_POLICY,然后根據(jù)一些情況調(diào)整省電模式策略,最后形成有效的省電模式策略 mEffectivePolicyRaw

    現(xiàn)在讓我們看看這個(gè)默認(rèn)的省電策略 DEFAULT_FULL_POLICY 到底是何方神圣

    private static final Policy DEFAULT_FULL_POLICY = new Policy(
            0.5f,  /* adjustBrightnessFactor */
            true,  /* advertiseIsEnabled */
            new CpuFrequencies(), /* cpuFrequenciesForInteractive */
            new CpuFrequencies(), /* cpuFrequenciesForNoninteractive */
            true,  /* deferFullBackup */
            true,  /* deferKeyValueBackup */
            false, /* disableAnimation */
            true,  /* disableAod */
            true,  /* disableLaunchBoost */
            true,  /* disableOptionalSensors */
            true,  /* disableVibration */
            false, /* enableAdjustBrightness */
            false, /* enableDataSaver */
            true,  /* enableFirewall */
            true, /* enableNightMode */
            true, /* enableQuickDoze */
            true, /* forceAllAppsStandby */
            true, /* forceBackgroundCheck */
            PowerManager.LOCATION_MODE_FOREGROUND_ONLY, /* locationMode */
            PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY /* soundTriggerMode */
    );

    Policy 就是一個(gè)數(shù)據(jù)封裝類,看下它構(gòu)造函數(shù)的參數(shù),我們就能大致猜測出省電模式影響哪些模塊的功能。

    這里注意下第三個(gè)和第四個(gè)參數(shù),它表示省電模式下,需要限制頻率的 CPU 的編號(hào)以及限制的頻率值,這里默認(rèn)是空,后面會(huì)用到。

    處理省電模式狀態(tài)改變

    現(xiàn)在讓我們回到打開省電模式的代碼

    public void enableBatterySaver(boolean enable, int reason) {
        synchronized (mLock) {
            if (getFullEnabledLocked() == enable) {
                return;
            }
            // 1. 保存省電模式的狀態(tài)
            setFullEnabledLocked(enable);
    
            // 2. 更新省電模式策略
            if (updatePolicyLevelLocked()) {
                // 3. 處理省電模式狀態(tài)的改變
                mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
            }
        }
    }

    前兩步已經(jīng)分析完畢,現(xiàn)在來看看第三步,它最終會(huì)調(diào)用 BatterySaverController#handleBatterySaverStateChanged() 來處理省電模式狀態(tài)改變

    void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) {
        final LowPowerModeListener[] listeners;
    
        final boolean enabled;
        // 獲取設(shè)備是否處于交互狀態(tài)
        // 一般來說,如果屏幕熄滅,設(shè)備處于非交互狀態(tài),屏幕電量,設(shè)備處于交互狀態(tài)
        final boolean isInteractive = getPowerManager().isInteractive();
        final ArrayMap<String, String> fileValues;
    
        synchronized (mLock) {
            // 獲取省電模式的狀態(tài)
            enabled = getFullEnabledLocked() || getAdaptiveEnabledLocked();
    
            // 保存前一個(gè) full battery saver狀態(tài)
            mFullPreviouslyEnabled = getFullEnabledLocked();
            // 保存前一個(gè)adaptive battery saver狀態(tài)
            mAdaptivePreviouslyEnabled = getAdaptiveEnabledLocked();
    
            listeners = mListeners.toArray(new LowPowerModeListener[0]);
    
            mIsInteractive = isInteractive;
    
            if (enabled) {
                // 1. 打開省電模式情況下,獲取頻率受限的CPU的編號(hào)以及受限的值
                fileValues = mBatterySaverPolicy.getFileValues(isInteractive);
            } else {
                fileValues = null;
            }
        }
    
        // 2. 通過 PowerManagerService 向底層設(shè)置省電模式
        final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
        if (pmi != null) {
            pmi.setPowerMode(Mode.LOW_POWER, isEnabled());
        }
    
        // 用 BatterySavingStats 記錄數(shù)據(jù)
        updateBatterySavingStats();
    
        // 3. 根據(jù)策略,限制或恢復(fù)CPU頻率
        if (ArrayUtils.isEmpty(fileValues)) {
            // CPU 策略為空,表示需要恢復(fù) CPU 之前的頻率
            mFileUpdater.restoreDefault();
        } else {
            // CPU 頻率策略不為空,表示需要限制 CPU 頻率
            mFileUpdater.writeFiles(fileValues);
        }
    
        if (sendBroadcast) {
            // 4. 發(fā)送廣播
            Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
    
            // 可以在 frameworks-res 的配置文件中配置一個(gè)應(yīng)用的包名
            // 這個(gè)應(yīng)用可以在manifest.xml中注冊廣播接收器,接收省電模式狀態(tài)改變
            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);
            }
    
            // 發(fā)送一個(gè)內(nèi)部版本的廣播,但是接收者需要權(quán)限
            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. 通知監(jiān)聽者
            for (LowPowerModeListener listener : listeners) {
                final PowerSaveState result =
                        mBatterySaverPolicy.getBatterySaverPolicy(listener.getServiceType());
                listener.onLowPowerModeChanged(result);
            }
        }
    }

    第一步和第三步,是在省電模式下限制 CPU 頻率的。根據(jù)前面分析可知,目前默認(rèn)策略是沒有配置CPU頻率的,因此這兩步不分析了。我將在后面的文章中,分析如何控制省電模式策略,到時(shí)候再來分析這里的代碼邏輯。

    第二步,通過 PowerManagerService 向底層設(shè)置省電模式,底層稱之為低功耗模式(low power mode)。

    第四步,發(fā)送省電模式狀態(tài)改變的廣播。

    第五步,通知監(jiān)聽者。誰會(huì)是監(jiān)聽者呢?當(dāng)然是那些受省電模式影響的模塊。

    讓我們看下返回給監(jiān)聽者的數(shù)據(jù)到底是什么?看下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();
                }
            }
        }

    原來,根據(jù)監(jiān)聽者的類型,返回一個(gè) PowerSaveState 對象,這個(gè)對象中只包含了監(jiān)聽者關(guān)心的數(shù)據(jù)。

    從這里,我們應(yīng)該有所領(lǐng)悟,如果我們自己開發(fā)了一個(gè)功能模塊

    • 如果受省電模式策略影響,必須注冊一個(gè)監(jiān)聽器,獲取省電模式下策略,然后調(diào)整模塊的功能。

    • 如果這個(gè)模塊是個(gè)耗電大戶,那么必須監(jiān)聽省電模式,在省電模式下執(zhí)行相應(yīng)的操作。

    現(xiàn)在很多項(xiàng)目都關(guān)注電量消耗問題,省電模式到底能讓手機(jī)待機(jī)多長時(shí)間,也是一個(gè)考核的指標(biāo)。

    battery saver sticky 模式

    根據(jù)前面的分析,只有在用戶手動(dòng)操作省電模式的時(shí)候,才會(huì)相應(yīng)的打開或者關(guān)閉 battery saver sticky 模式。

    我先總結(jié)下什么是 battery saver sticky 模式? 當(dāng)手機(jī)已經(jīng)處于省電模式,插入電源,系統(tǒng)會(huì)默認(rèn)關(guān)閉省電模式,如果此時(shí)拔掉電源或者手機(jī)重啟,當(dāng) battery saver sticky 功能已經(jīng)打開的情況下,系統(tǒng)會(huì)重新打開省電模式。

    現(xiàn)在讓我們從代碼角度分析,繼續(xù)使用上面的例子分析,假如現(xiàn)在已經(jīng)打開了省電模式,此時(shí)插入了電源,來看下狀態(tài)機(jī)的切換動(dòng)作 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) { // 充電狀態(tài)下,不允許打開省電模式
                        if (manual) { // 手動(dòng)模式
                            if (!enable) {
                                Slog.e(TAG, "Tried to disable BS when it's already OFF");
                                return;
                            }
                            enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
                                    BatterySaverController.REASON_MANUAL_ON);
                            hideStickyDisabledNotification();
                            // 1. 用戶打開省電模式,狀態(tài)切換為 STATE_MANUAL_ON
                            mState = STATE_MANUAL_ON;
                        } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) {
                            // 自動(dòng)模式 ...
                        } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) {
                            // 動(dòng)態(tài)模式 ...
                        }
                    }
                    break;
                }
    
                case STATE_MANUAL_ON: {
                    if (manual) {
                        // ...
                    } else if (mIsPowered) { // 2. 插入電源
                        // 關(guān)閉省電模式
                        enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
                                BatterySaverController.REASON_PLUGGED_IN);
                        // 手動(dòng)打開省電模式時(shí),mSettingBatterySaverEnabledSticky 設(shè)置為 true
                        // mBatterySaverStickyBehaviourDisabled 默認(rèn)為 false,表示支持這個(gè) feature
                        if (mSettingBatterySaverEnabledSticky
                                && !mBatterySaverStickyBehaviourDisabled) {
                            // 插入電源,狀態(tài)切換為 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 對應(yīng) Battery Saver界面下的 Turn off when charging 開關(guān)
                    // mSettingBatterySaverStickyAutoDisableThreshold 默認(rèn)值為 90
                    final boolean shouldTurnOffSticky = mSettingBatterySaverStickyAutoDisableEnabled
                            && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold;
                    // 手動(dòng)打開省電模式,再插入電源,此時(shí) isStickyDisabled 值為 false
                    final boolean isStickyDisabled =
                            mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky;
                    if (isStickyDisabled || shouldTurnOffSticky) {
                        // 3.2 如果Turn off when charging 開關(guān)被打開,并且電量大于90%,那么不會(huì)重新打開省電模式
                        mState = STATE_OFF;
                        setStickyActive(false);
                        triggerStickyDisabledNotification();
                    } else if (!mIsPowered) {
                        // Re-enable BS.
                        // 3.1 斷開電源,重新打開省電模式
                        enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
                                BatterySaverController.REASON_STICKY_RESTORE);
                        mState = STATE_MANUAL_ON;
                    }
                    break;
                }
                // ...
            }
        }

    首先看下第一步,它打開了省電模式,并且狀態(tài)切換為 STATE_MANUAL_ON。

    如果此時(shí),插入電源,那么會(huì)進(jìn)入第二步, 關(guān)閉省電模式, 并把狀態(tài)切換為 STATE_PENDING_STICKY_ON

    如果關(guān)閉了設(shè)置中 Battery Saver 界面的 Turn off when Charging 開關(guān),此時(shí)拔掉電源,那么進(jìn)入 3.1 步,又會(huì)再次打開省電模式,這就是 sticky 的含義。

    如果打開了設(shè)置中 Battery Saver 界面的 Turn off when Charging 開關(guān),那么進(jìn)入 3.2 步,不會(huì)再次打開省電模式。

    設(shè)置中 Battery Saver 界面的 Turn off when Charging 開關(guān)就是 battery saver sticky auto disable 功能。

    感謝各位的閱讀,以上就是“Android PowerManagerService打開省電模式怎么實(shí)現(xiàn)”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Android PowerManagerService打開省電模式怎么實(shí)現(xiàn)這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI