2020-08-01 Google 省电模式

1. 省电模式主要做什么?

  1. DisplayPowerController->屏幕亮度减半
  2. VibratorService->关闭触摸震动和来电震动
  3. NetworkPolicyManagerService->限制 Doze 非白名单应用联网(WiFi与数据流量)使用
  4. WindowManagerService->关闭动画
  5. PowerManagerService->省电模式-CPU降频
  6. UiModeManagerService->开启暗色主题模式(Q平台版本新增)
  7. GnssLocationProvider->灭屏后开启GPS待机省电模式
  8. SoundTriggerHelper->拦截语音交互功能
  9. DeviceStateMonitor->设置Modem为省电模式
  10. PowerUI->取消低电量通知提醒

2. 开启省电模式

2.1 UI 设置界面

Googel原生省电模式.png

2.2 软件 API 接口

    public void setGooglePowerSave(boolean enable) {
        PowerManager mPowerManager = ((PowerManager) getSystemService(Context.POWER_SERVICE));
        mPowerManager.setPowerSaveMode(enable);
    }

    // 需要注册权限 android.Manifest.permission.DEVICE_POWER
    public boolean setPowerSaveMode(boolean enabled) {
        ...
        return setLowPowerModeInternal(enabled);
        ...
    }
    
    private boolean setLowPowerModeInternal(boolean enabled) {
        ...
        mBatterySaverStateMachine.setBatterySaverEnabledManually(enabled);
        ...
    }
    
    public void setBatterySaverEnabledManually(boolean enabled) {
        ...
        enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true,
                    (enabled ? BatterySaverController.REASON_MANUAL_ON
                            : BatterySaverController.REASON_MANUAL_OFF),
                    (enabled ? "Manual ON" : "Manual OFF"));
        ...
    }
    
    private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason,
            String strReason) {
        ...
        putGlobalSetting(Global.LOW_POWER_MODE, enable ? 1 : 0);
        ...
        mBatterySaverController.enableBatterySaver(enable, intReason);
        ...
    }
    
    public void enableBatterySaver(boolean enable, int reason) {
        ...
        mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
        ...
    }
    
    public void postStateChanged(boolean sendBroadcast, int reason) {
        obtainMessage(MSG_STATE_CHANGED, sendBroadcast ?
                ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, reason).sendToTarget();
    }
    
    private class MyHandler extends Handler {
        @Override
        public void dispatchMessage(Message msg) {
            switch (msg.what) {
                case MSG_STATE_CHANGED:
                    handleBatterySaverStateChanged(
                            msg.arg1 == ARG_SEND_BROADCAST,
                            msg.arg2);
                    break;
            ...
    }
    
    void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) {
        ...
        // CPU 调低频
        pmi.powerHint(PowerHint.LOW_POWER, enabled ? 1 : 0);
        ...
        Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
        ...
        intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
        ...
        for (LowPowerModeListener listener : listeners) {
            ...
            // 通知所有注册 LowPowerModeListener 的服务会发生改变
            listener.onLowPowerModeChanged(result);
            ...
        }
    }

3. 省电模式的策略

3.1 省电模式事件

Google 原生省电模式开启后,以下注册 LowPowerModeListener 的服务会发生改变

    // 省电模式变化广播 1
    // 普通 APP 使用动态广播
    Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
        // 省电模式是否开启
        .putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, enabled)
        .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
    
    // 省电模式变化广播 2
    // 普通 APP 可监听
    // 需要重点查看接受这个广播的系统服务做了什么
    intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    mContext.sendBroadcastAsUser(intent, UserHandle.ALL);    
    
    // 省电模式变化广播 3
    // 需要注册 Manifest.permission.DEVICE_POWER 权限且需要系统签名才能收到
    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);
    
    // 系统其它服务,主要注册监听 LowPowerModeListener 变化进行省电模式的开启
    for (LowPowerModeListener listener : listeners) {
        final PowerSaveState result =
                mBatterySaverPolicy.getBatterySaverPolicy(
                        listener.getServiceType(), enabled);
        listener.onLowPowerModeChanged(result);
    }

上述中Google 省电中系统监听到省电模式变化,这里主要指的是 监听 LowPowerModeListener 和 ACTION_POWER_SAVE_MODE_CHANGED广播 执行对应的省电策略

3.1.1 监听 ACTION_POWER_SAVE_MODE_CHANGED 广播

  1. GnssLocationProvider-限制 GPS,灭屏关闭GPS
  2. SoundTriggerHelper-关闭语音互动
  3. DeviceStateMonitor-设置Modem为省电模式
  4. PowerUI-忽略低电量提醒

3.1.2 监听 LowPowerModeListener 广播

  1. VibratorService-关闭触摸震动
  2. NetworkPolicyManagerService-限制 Doze 非白名单应用联网(WiFi与数据流量)使用
  3. WindowManagerService-关闭动画

3.2 省电模式-关闭触摸震动和来电震动

  • /frameworks/base/services/core/java/com/android/server/VibratorService.java
    public void systemReady() {
        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
            mPowerManagerInternal.registerLowPowerModeObserver(
                new PowerManagerInternal.LowPowerModeListener() {
                    @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 void doCancelVibrateLocked() {
        ...
        doVibratorOff();
        ...
    }

3.3 省电模式-限制 Doze 非白名单应用联网(WiFi与数据流量)使用

  • /frameworks/base/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
    ...
    mPowerManagerInternal.registerLowPowerModeObserver(
        ...
        @Override
        public void onLowPowerModeChanged(PowerSaveState result) {
            final boolean enabled = result.batterySaverEnabled;
            synchronized (mUidRulesFirstLock) {
                if (mRestrictPower != enabled) {
                    mRestrictPower = enabled;
                    updateRulesForRestrictPowerUL();
                }
            }
        }
    });
    ...
    
    private void updateRulesForRestrictPowerUL() {
        ...
        updateRulesForPowerSaveUL();
        ...
    }

    void updateRulesForPowerSaveUL() {
        ...
        updateRulesForWhitelistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
                    mUidFirewallPowerSaveRules);
        ...
    }
    
    private void updateRulesForWhitelistedPowerSaveUL(boolean enabled, int chain,
        ...
        if (enabled) {
            setUidFirewallRulesUL(chain, uidRules, CHAIN_TOGGLE_ENABLE);
        } else {
            setUidFirewallRulesUL(chain, null, CHAIN_TOGGLE_DISABLE);
        }
        ...
    }
    
    /**
     * Calls {@link #setUidFirewallRules(int, SparseIntArray)} and
     * {@link #enableFirewallChainUL(int, boolean)} synchronously.
     *
     * @param chain firewall chain.
     * @param uidRules new UID rules; if {@code null}, only toggles chain state.
     * @param toggle whether the chain should be enabled, disabled, or not changed.
     */
    private void setUidFirewallRulesUL(int chain, @Nullable SparseIntArray uidRules,
        ...
        if (toggle != CHAIN_TOGGLE_NONE) {
            enableFirewallChainUL(chain, toggle == CHAIN_TOGGLE_ENABLE);
        }
    }

3.4 省电模式-关闭动画

  • /frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
    if (mPowerManagerInternal != null) {
        mPowerManagerInternal.registerLowPowerModeObserver(
                new PowerManagerInternal.LowPowerModeListener() {
            @Override
            public void onLowPowerModeChanged(PowerSaveState result) {
                synchronized (mWindowMap) {
                    final boolean enabled = result.batterySaverEnabled;
                    if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {
                        
                        mAnimationsDisabled = enabled;
                        dispatchNewAnimatorScaleLocked(null);
                    }
                }
            }
    });

3.5 省电模式-CPU降频

  • /frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
    这里的CPU调频的 Native 方法需要ODM或方案商自行实现

private static native void nativeSendPowerHint(int hintId, int data);

private void powerHintInternal(int hintId, int data) {
    nativeSendPowerHint(hintId, data);
}

3.6 省电模式-开启暗色主题模式

Q/frameworks/base/services/core/java/com/android/server/UiModeManagerService.java

      mPowerSave = localPowerManager.getLowPowerState(ServiceType.NIGHT_MODE).batterySaverEnabled
      localPowerManager.registerLowPowerModeObserver(ServiceType.NIGHT_MODE,
              state -> {
          synchronized (mLock) {
              if (mPowerSave == state.batterySaverEnabled) {
                  return;
              }
              mPowerSave = state.batterySaverEnabled;
              if (mSystemReady) {
                  updateLocked(0, 0);
              }
          }
      });

3.7 省电模式-灭屏后开启GPS待机省电模式

  • /frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        ...
        } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
            || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
            || Intent.ACTION_SCREEN_OFF.equals(action)
            || Intent.ACTION_SCREEN_ON.equals(action)) {
            updateLowPowerMode();
        ...
    }
    
    private void updateLowPowerMode() {
        // Disable GPS if we are in device idle mode.
        boolean disableGps = mPowerManager.isDeviceIdleMode();
        final PowerSaveState result =
                mPowerManager.getPowerSaveState(ServiceType.GPS);
        switch (result.gpsMode) {
            case PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
                // If we are in battery saver mode and the screen is off, disable GPS.
                // 省电模式开启,灭屏后开启GPS待机省电模式(stopNavigating)
                disableGps |= result.batterySaverEnabled && !mPowerManager.isInteractive();
                break;
        }
        if (disableGps != mDisableGps) {
            mDisableGps = disableGps;
            updateRequirements();
        }
    }

}

3.8 省电模式-拦截语音交互功能

  • /frameworks/base/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
    class PowerSaveModeListener extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            ...
            boolean active = mPowerManager.getPowerSaveState(ServiceType.SOUND)
                    .batterySaverEnabled;
            if (DBG) Slog.d(TAG, "onPowerSaveModeChanged: " + active);
            synchronized (mLock) {
                onPowerSaveModeChangedLocked(active);
            }
        }
    }
    
    // 拦截语音交互功能
    private void onPowerSaveModeChangedLocked(boolean isPowerSaveMode) {
        if (mIsPowerSaveMode == isPowerSaveMode) {
            return;
        }
        mIsPowerSaveMode = isPowerSaveMode;
        updateAllRecognitionsLocked(true /* notify */);
    }

3.9 省电模式-设置Modem为省电模式

  • /frameworks/opt/telephony/src/java/com/android/internal/telephony/DeviceStateMonitor.java
    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            switch (intent.getAction()) {
                case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED:
                    msg = obtainMessage(EVENT_POWER_SAVE_MODE_CHANGED);
                    msg.arg1 = isPowerSaveModeOn() ? 1 : 0;
                    log("Power Save mode " + ((msg.arg1 == 1) ? "on" : "off"), true);
                    break;
        }
    }
        
    public void handleMessage(Message msg) {
        ...
        case EVENT_POWER_SAVE_MODE_CHANGED:
        ...
        onUpdateDeviceState(msg.what, msg.arg1 != 0);
        ...
    }
    
    private void onUpdateDeviceState(int eventType, boolean state) {
        ...
        sendDeviceState(POWER_SAVE_MODE, mIsPowerSaveOn);
        ...
    }
        
    /**
     * Send the device state to the modem.
     *
     * @param type Device state type. See DeviceStateType defined in types.hal.
     * @param state True if enabled/on, otherwise disabled/off
     */
    private void sendDeviceState(int type, boolean state) {
        log("send type: " + deviceTypeToString(type) + ", state=" + state, true);
        mPhone.mCi.sendDeviceState(type, state, null);
    }

3.10 省电模式-取消低电量通知提醒

  • /frameworks/base/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
    @Override
    public void onReceive(Context context, Intent intent) {
        ...
        if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
            ThreadUtils.postOnBackgroundThread(() -> {
                if (mPowerManager.isPowerSaveMode()) {
                    // 取消低电量通知提醒
                    mWarnings.dismissLowBatteryWarning();
                }
            });

3.11 省电模式-屏幕亮度减半

  • /frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

updatePowerStateLocked()是PowerManagerService最核心的函数,PMS中使用一个int值mDirty作为标志位判断电源状态是否发生变化,当电源状态发生改变时,如亮灭屏、电池状态改变、省电模式都会调用该方法。从而判断是否要根据省电模式进行亮度减半的策略

    private void updatePowerStateLocked() {
        ...
        // Phase 3: Update display power state.
        final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
        ...
    }

    private boolean updateDisplayPowerStateLocked(int dirty) {
        ...
        // 获取当前是否为省电模式
        updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);
        ...
        // 重头戏
        mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
                    mRequestWaitForNegativeProximity);
        ...    
    }
    
    void updatePowerRequestFromBatterySaverPolicy(DisplayPowerRequest displayPowerRequest) {
        ...
        displayPowerRequest.lowPowerMode = state.batterySaverEnabled;
        ...
    }
    
    public boolean requestPowerState(DisplayPowerRequest request,
                boolean waitForNegativeProximity) {
        ...
        return mDisplayPowerController.requestPowerState(request,
                        waitForNegativeProximity);
    }
    
    public boolean requestPowerState(DisplayPowerRequest request,
        boolean waitForNegativeProximity) {
        ...
        sendUpdatePowerStateLocked();
        ...
    }
    
    private void sendUpdatePowerStateLocked() {
        ...
        Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
        ...
    }
    
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_UPDATE_POWER_STATE:
                updatePowerState();
                break;
            }
            ...
    }
    
    private void updatePowerState() {
        ...
        if (mPowerRequest.lowPowerMode) {
            if (brightness > mScreenBrightnessRangeMinimum) {
                // 由于 screenLowPowerBrightnessFactor = 0.5f
                // 开启省电模式,亮度减半
                final float brightnessFactor =
                        Math.min(mPowerRequest.screenLowPowerBrightnessFactor, 1);
                final int lowPowerBrightness = (int) (brightness * brightnessFactor);
                brightness = Math.max(lowPowerBrightness, mScreenBrightnessRangeMinimum);
            }
        ...
    }

你可能感兴趣的:(省电续航,省电模式,android,低功耗模式,功耗续航,电池省电)