1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.power.batterysaver;
17 
18 import static com.android.server.power.batterysaver.BatterySaverController.reasonToString;
19 
20 import android.annotation.NonNull;
21 import android.annotation.StringRes;
22 import android.app.Notification;
23 import android.app.NotificationChannel;
24 import android.app.NotificationManager;
25 import android.app.PendingIntent;
26 import android.content.ContentResolver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.res.Resources;
30 import android.database.ContentObserver;
31 import android.os.BatterySaverPolicyConfig;
32 import android.os.Bundle;
33 import android.os.Handler;
34 import android.os.PowerManager;
35 import android.os.SystemClock;
36 import android.os.UserHandle;
37 import android.provider.Settings;
38 import android.util.IndentingPrintWriter;
39 import android.util.Slog;
40 import android.util.proto.ProtoOutputStream;
41 
42 import com.android.internal.R;
43 import com.android.internal.annotations.GuardedBy;
44 import com.android.internal.annotations.VisibleForTesting;
45 import com.android.internal.os.BackgroundThread;
46 import com.android.server.EventLogTags;
47 import com.android.server.power.BatterySaverStateMachineProto;
48 import com.android.server.power.PowerManagerService;
49 
50 import java.io.PrintWriter;
51 import java.time.Duration;
52 
53 /**
54  * Decides when to enable / disable battery saver.
55  *
56  * IMPORTANT: This class shares the power manager lock, which is very low in the lock hierarchy.
57  * Do not call out with the lock held. (Settings provider is okay.)
58  *
59  * Test: atest com.android.server.power.batterysaver.BatterySaverStateMachineTest
60  *
61  * Current state machine. This can be visualized using Graphviz:
62    <pre>
63 
64    digraph {
65      STATE_OFF
66      STATE_MANUAL_ON [label="STATE_MANUAL_ON\nTurned on manually by the user"]
67      STATE_AUTOMATIC_ON [label="STATE_AUTOMATIC_ON\nTurned on automatically by the system"]
68      STATE_OFF_AUTOMATIC_SNOOZED [
69        label="STATE_OFF_AUTOMATIC_SNOOZED\nTurned off manually by the user."
70            + " The system should not turn it back on automatically."
71      ]
72      STATE_PENDING_STICKY_ON [
73        label="STATE_PENDING_STICKY_ON\n"
74            + " Turned on manually by the user and then plugged in. Will turn back on after unplug."
75      ]
76 
77      STATE_OFF -> STATE_MANUAL_ON [label="manual"]
78      STATE_OFF -> STATE_AUTOMATIC_ON [label="Auto on AND charge <= auto threshold"]
79 
80      STATE_MANUAL_ON -> STATE_OFF [label="manual\nOR\nPlugged & sticky disabled"]
81      STATE_MANUAL_ON -> STATE_PENDING_STICKY_ON [label="Plugged & sticky enabled"]
82 
83      STATE_PENDING_STICKY_ON -> STATE_MANUAL_ON [label="Unplugged & sticky enabled"]
84      STATE_PENDING_STICKY_ON -> STATE_OFF [
85        label="Sticky disabled\nOR\nSticky auto off enabled AND charge >= sticky auto off threshold"
86      ]
87 
88      STATE_AUTOMATIC_ON -> STATE_OFF [label="Plugged"]
89      STATE_AUTOMATIC_ON -> STATE_OFF_AUTOMATIC_SNOOZED [label="Manual"]
90 
91      STATE_OFF_AUTOMATIC_SNOOZED -> STATE_OFF [label="Plug\nOR\nCharge > auto threshold"]
92      STATE_OFF_AUTOMATIC_SNOOZED -> STATE_MANUAL_ON [label="manual"]
93 
94      </pre>
95    }
96  */
97 public class BatterySaverStateMachine {
98     private static final String TAG = "BatterySaverStateMachine";
99     private static final String DYNAMIC_MODE_NOTIF_CHANNEL_ID = "dynamic_mode_notification";
100     private static final String BATTERY_SAVER_NOTIF_CHANNEL_ID = "battery_saver_channel";
101     private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
102     private static final String EXTRA_SHOW_FRAGMENT_TITLE = ":settings:show_fragment_args";
103     private static final String PREFERENCE_KEY_BATTERY_SAVER_SCHEDULER = "battery_saver_schedule";
104     private static final int DYNAMIC_MODE_NOTIFICATION_ID = 1992;
105     private static final int STICKY_AUTO_DISABLED_NOTIFICATION_ID = 1993;
106     private final Object mLock;
107 
108     private static final boolean DEBUG = BatterySaverPolicy.DEBUG;
109 
110     private static final long ADAPTIVE_CHANGE_TIMEOUT_MS = 24 * 60 * 60 * 1000L;
111 
112     /** Turn off adaptive battery saver if the device has charged above this level. */
113     private static final int ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL = 80;
114 
115     private static final long STICKY_DISABLED_NOTIFY_TIMEOUT_MS = Duration.ofHours(12).toMillis();
116 
117     private static final int STATE_OFF = BatterySaverStateMachineProto.STATE_OFF;
118 
119     /** Turned on manually by the user. */
120     private static final int STATE_MANUAL_ON = BatterySaverStateMachineProto.STATE_MANUAL_ON;
121 
122     /** Turned on automatically by the system. */
123     private static final int STATE_AUTOMATIC_ON = BatterySaverStateMachineProto.STATE_AUTOMATIC_ON;
124 
125     /** Turned off manually by the user. The system should not turn it back on automatically. */
126     private static final int STATE_OFF_AUTOMATIC_SNOOZED =
127             BatterySaverStateMachineProto.STATE_OFF_AUTOMATIC_SNOOZED;
128 
129     /** Turned on manually by the user and then plugged in. Will turn back on after unplug. */
130     private static final int STATE_PENDING_STICKY_ON =
131             BatterySaverStateMachineProto.STATE_PENDING_STICKY_ON;
132 
133     private final Context mContext;
134     private final BatterySaverController mBatterySaverController;
135 
136     /** Whether the system has booted. */
137     @GuardedBy("mLock")
138     private boolean mBootCompleted;
139 
140     /** Whether global settings have been loaded already. */
141     @GuardedBy("mLock")
142     private boolean mSettingsLoaded;
143 
144     /** Whether the first battery status has arrived. */
145     @GuardedBy("mLock")
146     private boolean mBatteryStatusSet;
147 
148     @GuardedBy("mLock")
149     private int mState;
150 
151     /** Whether the device is connected to any power source. */
152     @GuardedBy("mLock")
153     private boolean mIsPowered;
154 
155     /** Current battery level in %, 0-100. (Currently only used in dumpsys.) */
156     @GuardedBy("mLock")
157     private int mBatteryLevel;
158 
159     /** Whether the battery level is considered to be "low" or not. */
160     @GuardedBy("mLock")
161     private boolean mIsBatteryLevelLow;
162 
163     /** Previously known value of Settings.Global.LOW_POWER_MODE. */
164     @GuardedBy("mLock")
165     private boolean mSettingBatterySaverEnabled;
166 
167     /** Previously known value of Settings.Global.LOW_POWER_MODE_STICKY. */
168     @GuardedBy("mLock")
169     private boolean mSettingBatterySaverEnabledSticky;
170 
171     /** Config flag to track if battery saver's sticky behaviour is disabled. */
172     private final boolean mBatterySaverStickyBehaviourDisabled;
173 
174     /** Config flag to track if "Battery Saver turned off" notification is enabled. */
175     private final boolean mBatterySaverTurnedOffNotificationEnabled;
176 
177     /**
178      * Whether or not to end sticky battery saver upon reaching a level specified by
179      * {@link #mSettingBatterySaverStickyAutoDisableThreshold}.
180      */
181     @GuardedBy("mLock")
182     private boolean mSettingBatterySaverStickyAutoDisableEnabled;
183 
184     /**
185      * The battery level at which to end sticky battery saver. Only useful if
186      * {@link #mSettingBatterySaverStickyAutoDisableEnabled} is {@code true}.
187      */
188     @GuardedBy("mLock")
189     private int mSettingBatterySaverStickyAutoDisableThreshold;
190 
191     /**
192      * Config flag to track default disable threshold for Dynamic Power Savings enabled battery
193      * saver.
194      */
195     @GuardedBy("mLock")
196     private final int mDynamicPowerSavingsDefaultDisableThreshold;
197 
198     /**
199      * Previously known value of Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL.
200      * (Currently only used in dumpsys.)
201      */
202     @GuardedBy("mLock")
203     private int mSettingBatterySaverTriggerThreshold;
204 
205     /** Previously known value of Settings.Global.AUTOMATIC_POWER_SAVE_MODE. */
206     @GuardedBy("mLock")
207     private int mSettingAutomaticBatterySaver;
208 
209     /**
210      * When to disable battery saver again if it was enabled due to an external suggestion.
211      * Corresponds to Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD.
212      */
213     @GuardedBy("mLock")
214     private int mDynamicPowerSavingsDisableThreshold;
215 
216     /**
217      * Whether we've received a suggestion that battery saver should be on from an external app.
218      * Updates when Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED changes.
219      */
220     @GuardedBy("mLock")
221     private boolean mDynamicPowerSavingsEnableBatterySaver;
222 
223     /**
224      * Last reason passed to {@link #enableBatterySaverLocked}.
225      */
226     @GuardedBy("mLock")
227     private int mLastChangedIntReason;
228 
229     /**
230      * Last reason passed to {@link #enableBatterySaverLocked}.
231      */
232     @GuardedBy("mLock")
233     private String mLastChangedStrReason;
234 
235     /**
236      * The last time adaptive battery saver was changed by an external service, using elapsed
237      * realtime as the timebase.
238      */
239     @GuardedBy("mLock")
240     private long mLastAdaptiveBatterySaverChangedExternallyElapsed;
241 
242     private final ContentObserver mSettingsObserver = new ContentObserver(null) {
243         @Override
244         public void onChange(boolean selfChange) {
245             synchronized (mLock) {
246                 refreshSettingsLocked();
247             }
248         }
249     };
250 
BatterySaverStateMachine(Object lock, Context context, BatterySaverController batterySaverController)251     public BatterySaverStateMachine(Object lock,
252             Context context, BatterySaverController batterySaverController) {
253         mLock = lock;
254         mContext = context;
255         mBatterySaverController = batterySaverController;
256         mState = STATE_OFF;
257 
258         mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean(
259                 com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled);
260         mBatterySaverTurnedOffNotificationEnabled = mContext.getResources().getBoolean(
261                 com.android.internal.R.bool.config_batterySaverTurnedOffNotificationEnabled);
262         mDynamicPowerSavingsDefaultDisableThreshold = mContext.getResources().getInteger(
263                 com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold);
264     }
265 
266     /**
267      * Called by {@link PowerManagerService} on system ready, *with no lock held*.
268      */
systemReady()269     public void systemReady() {
270         mBatterySaverController.systemReady();
271         getBatterySaverPolicy().systemReady();
272     }
273 
274     /** @return Battery saver controller. */
getBatterySaverController()275     public BatterySaverController getBatterySaverController() {
276         return mBatterySaverController;
277     }
278 
279     /** @return Battery saver policy. */
getBatterySaverPolicy()280     public BatterySaverPolicy getBatterySaverPolicy() {
281         return mBatterySaverController.getBatterySaverPolicy();
282     }
283 
284     /** @return true if the automatic percentage based mode should be used */
isAutomaticModeActiveLocked()285     private boolean isAutomaticModeActiveLocked() {
286         return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE
287                 && mSettingBatterySaverTriggerThreshold > 0;
288     }
289 
290     /**
291      * The returned value won't necessarily make sense if {@link #isAutomaticModeActiveLocked()}
292      * returns {@code false}.
293      *
294      * @return true if the battery level is below automatic's threshold.
295      */
isInAutomaticLowZoneLocked()296     private boolean isInAutomaticLowZoneLocked() {
297         return mIsBatteryLevelLow;
298     }
299 
300     /** @return true if the dynamic mode should be used */
isDynamicModeActiveLocked()301     private boolean isDynamicModeActiveLocked() {
302         return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC
303                 && mDynamicPowerSavingsEnableBatterySaver;
304     }
305 
306     /**
307      * The returned value won't necessarily make sense if {@link #isDynamicModeActiveLocked()}
308      * returns {@code false}.
309      *
310      * @return true if the battery level is below dynamic's threshold.
311      */
isInDynamicLowZoneLocked()312     private boolean isInDynamicLowZoneLocked() {
313         return mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
314     }
315 
316     /**
317      * {@link com.android.server.power.PowerManagerService} calls it when the system is booted.
318      */
onBootCompleted()319     public void onBootCompleted() {
320         if (DEBUG) {
321             Slog.d(TAG, "onBootCompleted");
322         }
323         // Just booted. We don't want LOW_POWER_MODE to be persisted, so just always clear it.
324         putGlobalSetting(Settings.Global.LOW_POWER_MODE, 0);
325 
326         // This is called with the power manager lock held. Don't do anything that may call to
327         // upper services. (e.g. don't call into AM directly)
328         // So use a BG thread.
329         runOnBgThread(() -> {
330 
331             final ContentResolver cr = mContext.getContentResolver();
332             cr.registerContentObserver(Settings.Global.getUriFor(
333                     Settings.Global.LOW_POWER_MODE),
334                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
335             cr.registerContentObserver(Settings.Global.getUriFor(
336                     Settings.Global.LOW_POWER_MODE_STICKY),
337                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
338             cr.registerContentObserver(Settings.Global.getUriFor(
339                     Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
340                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
341             cr.registerContentObserver(Settings.Global.getUriFor(
342                     Settings.Global.AUTOMATIC_POWER_SAVE_MODE),
343                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
344             cr.registerContentObserver(Settings.Global.getUriFor(
345                     Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED),
346                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
347             cr.registerContentObserver(Settings.Global.getUriFor(
348                     Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD),
349                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
350             cr.registerContentObserver(Settings.Global.getUriFor(
351                     Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED),
352                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
353             cr.registerContentObserver(Settings.Global.getUriFor(
354                     Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL),
355                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
356 
357 
358             synchronized (mLock) {
359                 final boolean lowPowerModeEnabledSticky = getGlobalSetting(
360                         Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0;
361 
362                 if (lowPowerModeEnabledSticky) {
363                     mState = STATE_PENDING_STICKY_ON;
364                 }
365 
366                 mBootCompleted = true;
367 
368                 refreshSettingsLocked();
369 
370                 doAutoBatterySaverLocked();
371             }
372         });
373     }
374 
375     /**
376      * Run a {@link Runnable} on a background handler.
377      */
378     @VisibleForTesting
runOnBgThread(Runnable r)379     void runOnBgThread(Runnable r) {
380         BackgroundThread.getHandler().post(r);
381     }
382 
383     /**
384      * Run a {@link Runnable} on a background handler, but lazily. If the same {@link Runnable} is
385      * already registered, it'll be first removed before being re-posted.
386      */
387     @VisibleForTesting
runOnBgThreadLazy(Runnable r, int delayMillis)388     void runOnBgThreadLazy(Runnable r, int delayMillis) {
389         final Handler h = BackgroundThread.getHandler();
390         h.removeCallbacks(r);
391         h.postDelayed(r, delayMillis);
392     }
393 
394     @GuardedBy("mLock")
refreshSettingsLocked()395     private void refreshSettingsLocked() {
396         final boolean lowPowerModeEnabled = getGlobalSetting(
397                 Settings.Global.LOW_POWER_MODE, 0) != 0;
398         final boolean lowPowerModeEnabledSticky = getGlobalSetting(
399                 Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0;
400         final boolean dynamicPowerSavingsBatterySaver = getGlobalSetting(
401                 Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0) != 0;
402         final int lowPowerModeTriggerLevel = getGlobalSetting(
403                 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
404         final int automaticBatterySaverMode = getGlobalSetting(
405                 Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
406                 PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
407         final int dynamicPowerSavingsDisableThreshold = getGlobalSetting(
408                 Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
409                 mDynamicPowerSavingsDefaultDisableThreshold);
410         final boolean isStickyAutoDisableEnabled = getGlobalSetting(
411                 Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1) != 0;
412         final int stickyAutoDisableThreshold = getGlobalSetting(
413                 Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
414 
415         setSettingsLocked(lowPowerModeEnabled, lowPowerModeEnabledSticky,
416                 lowPowerModeTriggerLevel,
417                 isStickyAutoDisableEnabled, stickyAutoDisableThreshold,
418                 automaticBatterySaverMode,
419                 dynamicPowerSavingsBatterySaver, dynamicPowerSavingsDisableThreshold);
420     }
421 
422     /**
423      * {@link com.android.server.power.PowerManagerService} calls it when relevant global settings
424      * have changed.
425      *
426      * Note this will be called before {@link #onBootCompleted} too.
427      */
428     @GuardedBy("mLock")
429     @VisibleForTesting
setSettingsLocked(boolean batterySaverEnabled, boolean batterySaverEnabledSticky, int batterySaverTriggerThreshold, boolean isStickyAutoDisableEnabled, int stickyAutoDisableThreshold, int automaticBatterySaver, boolean dynamicPowerSavingsBatterySaver, int dynamicPowerSavingsDisableThreshold)430     void setSettingsLocked(boolean batterySaverEnabled, boolean batterySaverEnabledSticky,
431             int batterySaverTriggerThreshold,
432             boolean isStickyAutoDisableEnabled, int stickyAutoDisableThreshold,
433             int automaticBatterySaver,
434             boolean dynamicPowerSavingsBatterySaver, int dynamicPowerSavingsDisableThreshold) {
435         if (DEBUG) {
436             Slog.d(TAG, "setSettings: enabled=" + batterySaverEnabled
437                     + " sticky=" + batterySaverEnabledSticky
438                     + " threshold=" + batterySaverTriggerThreshold
439                     + " stickyAutoDisableEnabled=" + isStickyAutoDisableEnabled
440                     + " stickyAutoDisableThreshold=" + stickyAutoDisableThreshold
441                     + " automaticBatterySaver=" + automaticBatterySaver
442                     + " dynamicPowerSavingsBatterySaver=" + dynamicPowerSavingsBatterySaver
443                     + " dynamicPowerSavingsDisableThreshold="
444                     + dynamicPowerSavingsDisableThreshold);
445         }
446 
447         mSettingsLoaded = true;
448 
449         // Set sensible limits.
450         stickyAutoDisableThreshold = Math.max(stickyAutoDisableThreshold,
451                 batterySaverTriggerThreshold);
452 
453         final boolean enabledChanged = mSettingBatterySaverEnabled != batterySaverEnabled;
454         final boolean stickyChanged =
455                 mSettingBatterySaverEnabledSticky != batterySaverEnabledSticky;
456         final boolean thresholdChanged
457                 = mSettingBatterySaverTriggerThreshold != batterySaverTriggerThreshold;
458         final boolean stickyAutoDisableEnabledChanged =
459                 mSettingBatterySaverStickyAutoDisableEnabled != isStickyAutoDisableEnabled;
460         final boolean stickyAutoDisableThresholdChanged =
461                 mSettingBatterySaverStickyAutoDisableThreshold != stickyAutoDisableThreshold;
462         final boolean automaticModeChanged = mSettingAutomaticBatterySaver != automaticBatterySaver;
463         final boolean dynamicPowerSavingsThresholdChanged =
464                 mDynamicPowerSavingsDisableThreshold != dynamicPowerSavingsDisableThreshold;
465         final boolean dynamicPowerSavingsBatterySaverChanged =
466                 mDynamicPowerSavingsEnableBatterySaver != dynamicPowerSavingsBatterySaver;
467 
468         if (!(enabledChanged || stickyChanged || thresholdChanged || automaticModeChanged
469                 || stickyAutoDisableEnabledChanged || stickyAutoDisableThresholdChanged
470                 || dynamicPowerSavingsThresholdChanged || dynamicPowerSavingsBatterySaverChanged)) {
471             return;
472         }
473 
474         mSettingBatterySaverEnabled = batterySaverEnabled;
475         mSettingBatterySaverEnabledSticky = batterySaverEnabledSticky;
476         mSettingBatterySaverTriggerThreshold = batterySaverTriggerThreshold;
477         mSettingBatterySaverStickyAutoDisableEnabled = isStickyAutoDisableEnabled;
478         mSettingBatterySaverStickyAutoDisableThreshold = stickyAutoDisableThreshold;
479         mSettingAutomaticBatterySaver = automaticBatterySaver;
480         mDynamicPowerSavingsDisableThreshold = dynamicPowerSavingsDisableThreshold;
481         mDynamicPowerSavingsEnableBatterySaver = dynamicPowerSavingsBatterySaver;
482 
483         if (thresholdChanged) {
484             // To avoid spamming the event log, we throttle logging here.
485             runOnBgThreadLazy(mThresholdChangeLogger, 2000);
486         }
487 
488         if (!mSettingBatterySaverStickyAutoDisableEnabled) {
489             hideStickyDisabledNotification();
490         }
491 
492         if (enabledChanged) {
493             final String reason = batterySaverEnabled
494                     ? "Global.low_power changed to 1" : "Global.low_power changed to 0";
495             enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true,
496                     BatterySaverController.REASON_SETTING_CHANGED, reason);
497         } else {
498             doAutoBatterySaverLocked();
499         }
500     }
501 
502     private final Runnable mThresholdChangeLogger = () -> {
503         EventLogTags.writeBatterySaverSetting(mSettingBatterySaverTriggerThreshold);
504     };
505 
506     /**
507      * {@link com.android.server.power.PowerManagerService} calls it when battery state changes.
508      *
509      * Note this may be called before {@link #onBootCompleted} too.
510      */
setBatteryStatus(boolean newPowered, int newLevel, boolean newBatteryLevelLow)511     public void setBatteryStatus(boolean newPowered, int newLevel, boolean newBatteryLevelLow) {
512         if (DEBUG) {
513             Slog.d(TAG, "setBatteryStatus: powered=" + newPowered + " level=" + newLevel
514                     + " low=" + newBatteryLevelLow);
515         }
516         synchronized (mLock) {
517             mBatteryStatusSet = true;
518 
519             final boolean poweredChanged = mIsPowered != newPowered;
520             final boolean levelChanged = mBatteryLevel != newLevel;
521             final boolean lowChanged = mIsBatteryLevelLow != newBatteryLevelLow;
522 
523             if (!(poweredChanged || levelChanged || lowChanged)) {
524                 return;
525             }
526 
527             mIsPowered = newPowered;
528             mBatteryLevel = newLevel;
529             mIsBatteryLevelLow = newBatteryLevelLow;
530 
531             doAutoBatterySaverLocked();
532         }
533     }
534 
535     /**
536      * Change the full battery saver policy.
537      */
getFullBatterySaverPolicy()538     public BatterySaverPolicyConfig getFullBatterySaverPolicy() {
539         if (DEBUG) {
540             Slog.d(TAG, "getFullBatterySaverPolicy");
541         }
542 
543         synchronized (mLock) {
544             return mBatterySaverController.getPolicyLocked(BatterySaverPolicy.POLICY_LEVEL_FULL);
545         }
546     }
547 
548     /**
549      * Change the full battery saver policy.
550      */
setFullBatterySaverPolicy(BatterySaverPolicyConfig config)551     public boolean setFullBatterySaverPolicy(BatterySaverPolicyConfig config) {
552         if (DEBUG) {
553             Slog.d(TAG, "setFullBatterySaverPolicy: config=" + config);
554         }
555 
556         synchronized (mLock) {
557             return mBatterySaverController.setFullPolicyLocked(config,
558                     BatterySaverController.REASON_FULL_POWER_SAVINGS_CHANGED);
559         }
560     }
561 
562     /**
563      * Enable or disable the current adaptive battery saver policy. This may not change what's in
564      * effect if full battery saver is also enabled.
565      */
setAdaptiveBatterySaverEnabled(boolean enabled)566     public boolean setAdaptiveBatterySaverEnabled(boolean enabled) {
567         if (DEBUG) {
568             Slog.d(TAG, "setAdaptiveBatterySaverEnabled: enabled=" + enabled);
569         }
570         synchronized (mLock) {
571             mLastAdaptiveBatterySaverChangedExternallyElapsed = SystemClock.elapsedRealtime();
572             return mBatterySaverController.setAdaptivePolicyEnabledLocked(
573                     enabled, BatterySaverController.REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED);
574         }
575     }
576 
577     /**
578      * Change the adaptive battery saver policy.
579      */
setAdaptiveBatterySaverPolicy(BatterySaverPolicyConfig config)580     public boolean setAdaptiveBatterySaverPolicy(BatterySaverPolicyConfig config) {
581         if (DEBUG) {
582             Slog.d(TAG, "setAdaptiveBatterySaverPolicy: config=" + config);
583         }
584 
585         synchronized (mLock) {
586             mLastAdaptiveBatterySaverChangedExternallyElapsed = SystemClock.elapsedRealtime();
587             return mBatterySaverController.setAdaptivePolicyLocked(config,
588                     BatterySaverController.REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED);
589         }
590     }
591 
592     /**
593      * Decide whether to auto-start / stop battery saver.
594      */
595     @GuardedBy("mLock")
doAutoBatterySaverLocked()596     private void doAutoBatterySaverLocked() {
597         if (DEBUG) {
598             Slog.d(TAG, "doAutoBatterySaverLocked: mBootCompleted=" + mBootCompleted
599                     + " mSettingsLoaded=" + mSettingsLoaded
600                     + " mBatteryStatusSet=" + mBatteryStatusSet
601                     + " mState=" + mState
602                     + " mIsBatteryLevelLow=" + mIsBatteryLevelLow
603                     + " mIsPowered=" + mIsPowered
604                     + " mSettingAutomaticBatterySaver=" + mSettingAutomaticBatterySaver
605                     + " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky
606                     + " mSettingBatterySaverStickyAutoDisableEnabled="
607                     + mSettingBatterySaverStickyAutoDisableEnabled);
608         }
609         if (!(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
610             return; // Not fully initialized yet.
611         }
612 
613         updateStateLocked(false, false);
614 
615         // Adaptive control.
616         if (SystemClock.elapsedRealtime() - mLastAdaptiveBatterySaverChangedExternallyElapsed
617                 > ADAPTIVE_CHANGE_TIMEOUT_MS) {
618             mBatterySaverController.setAdaptivePolicyEnabledLocked(
619                     false, BatterySaverController.REASON_TIMEOUT);
620             mBatterySaverController.resetAdaptivePolicyLocked(
621                     BatterySaverController.REASON_TIMEOUT);
622         } else if (mIsPowered && mBatteryLevel >= ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL) {
623             mBatterySaverController.setAdaptivePolicyEnabledLocked(false,
624                     BatterySaverController.REASON_PLUGGED_IN);
625         }
626     }
627 
628     /**
629      * Update the state machine based on the current settings and battery/charge status.
630      *
631      * @param manual Whether the change was made by the user.
632      * @param enable Whether the user wants to turn battery saver on or off. Is only used if {@param
633      *               manual} is true.
634      */
635     @GuardedBy("mLock")
updateStateLocked(boolean manual, boolean enable)636     private void updateStateLocked(boolean manual, boolean enable) {
637         if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
638             return; // Not fully initialized yet.
639         }
640 
641         switch (mState) {
642             case STATE_OFF: {
643                 if (!mIsPowered) {
644                     if (manual) {
645                         if (!enable) {
646                             Slog.e(TAG, "Tried to disable BS when it's already OFF");
647                             return;
648                         }
649                         enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
650                                 BatterySaverController.REASON_MANUAL_ON);
651                         hideStickyDisabledNotification();
652                         mState = STATE_MANUAL_ON;
653                     } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) {
654                         enableBatterySaverLocked(/*enable*/ true, /*manual*/ false,
655                                 BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON);
656                         hideStickyDisabledNotification();
657                         mState = STATE_AUTOMATIC_ON;
658                     } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) {
659                         enableBatterySaverLocked(/*enable*/ true, /*manual*/ false,
660                                 BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON);
661                         hideStickyDisabledNotification();
662                         mState = STATE_AUTOMATIC_ON;
663                     }
664                 }
665                 break;
666             }
667 
668             case STATE_MANUAL_ON: {
669                 if (manual) {
670                     if (enable) {
671                         Slog.e(TAG, "Tried to enable BS when it's already MANUAL_ON");
672                         return;
673                     }
674                     enableBatterySaverLocked(/*enable*/ false, /*manual*/ true,
675                             BatterySaverController.REASON_MANUAL_OFF);
676                     mState = STATE_OFF;
677                 } else if (mIsPowered) {
678                     enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
679                             BatterySaverController.REASON_PLUGGED_IN);
680                     if (mSettingBatterySaverEnabledSticky
681                             && !mBatterySaverStickyBehaviourDisabled) {
682                         mState = STATE_PENDING_STICKY_ON;
683                     } else {
684                         mState = STATE_OFF;
685                     }
686                 }
687                 break;
688             }
689 
690             case STATE_AUTOMATIC_ON: {
691                 if (mIsPowered) {
692                     enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
693                             BatterySaverController.REASON_PLUGGED_IN);
694                     mState = STATE_OFF;
695                 } else if (manual) {
696                     if (enable) {
697                         Slog.e(TAG, "Tried to enable BS when it's already AUTO_ON");
698                         return;
699                     }
700                     enableBatterySaverLocked(/*enable*/ false, /*manual*/ true,
701                             BatterySaverController.REASON_MANUAL_OFF);
702                     // When battery saver is disabled manually (while battery saver is enabled)
703                     // when the battery level is low, we "snooze" BS -- i.e. disable auto battery
704                     // saver.
705                     // We resume auto-BS once the battery level is not low, or the device is
706                     // plugged in.
707                     mState = STATE_OFF_AUTOMATIC_SNOOZED;
708                 } else if (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked()) {
709                     enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
710                             BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF);
711                     mState = STATE_OFF;
712                 } else if (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked()) {
713                     enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
714                             BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF);
715                     mState = STATE_OFF;
716                 } else if (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked()) {
717                     enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
718                             BatterySaverController.REASON_SETTING_CHANGED);
719                     mState = STATE_OFF;
720                 }
721                 break;
722             }
723 
724             case STATE_OFF_AUTOMATIC_SNOOZED: {
725                 if (manual) {
726                     if (!enable) {
727                         Slog.e(TAG, "Tried to disable BS when it's already AUTO_SNOOZED");
728                         return;
729                     }
730                     enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
731                             BatterySaverController.REASON_MANUAL_ON);
732                     mState = STATE_MANUAL_ON;
733                 } else if (mIsPowered // Plugging in resets snooze.
734                         || (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked())
735                         || (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked())
736                         || (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked())) {
737                     mState = STATE_OFF;
738                 }
739                 break;
740             }
741 
742             case STATE_PENDING_STICKY_ON: {
743                 if (manual) {
744                     // This shouldn't be possible. We'll only be in this state when the device is
745                     // plugged in, so the user shouldn't be able to manually change state.
746                     Slog.e(TAG, "Tried to manually change BS state from PENDING_STICKY_ON");
747                     return;
748                 }
749                 final boolean shouldTurnOffSticky = mSettingBatterySaverStickyAutoDisableEnabled
750                         && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold;
751                 final boolean isStickyDisabled =
752                         mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky;
753                 if (isStickyDisabled || shouldTurnOffSticky) {
754                     mState = STATE_OFF;
755                     setStickyActive(false);
756                     triggerStickyDisabledNotification();
757                 } else if (!mIsPowered) {
758                     // Re-enable BS.
759                     enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
760                             BatterySaverController.REASON_STICKY_RESTORE);
761                     mState = STATE_MANUAL_ON;
762                 }
763                 break;
764             }
765 
766             default:
767                 Slog.wtf(TAG, "Unknown state: " + mState);
768                 break;
769         }
770     }
771 
772     @VisibleForTesting
getState()773     int getState() {
774         synchronized (mLock) {
775             return mState;
776         }
777     }
778 
779     /**
780      * {@link com.android.server.power.PowerManagerService} calls it when
781      * {@link android.os.PowerManager#setPowerSaveModeEnabled} is called.
782      *
783      * Note this could? be called before {@link #onBootCompleted} too.
784      */
setBatterySaverEnabledManually(boolean enabled)785     public void setBatterySaverEnabledManually(boolean enabled) {
786         if (DEBUG) {
787             Slog.d(TAG, "setBatterySaverEnabledManually: enabled=" + enabled);
788         }
789         synchronized (mLock) {
790             updateStateLocked(true, enabled);
791             // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true and
792             //  enabled is false
793         }
794     }
795 
796     @GuardedBy("mLock")
enableBatterySaverLocked(boolean enable, boolean manual, int intReason)797     private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason) {
798         enableBatterySaverLocked(enable, manual, intReason, reasonToString(intReason));
799     }
800 
801     /**
802      * Actually enable / disable battery saver. Write the new state to the global settings
803      * and propagate it to {@link #mBatterySaverController}.
804      */
805     @GuardedBy("mLock")
enableBatterySaverLocked(boolean enable, boolean manual, int intReason, String strReason)806     private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason,
807             String strReason) {
808         if (DEBUG) {
809             Slog.d(TAG, "enableBatterySaver: enable=" + enable + " manual=" + manual
810                     + " reason=" + strReason + "(" + intReason + ")");
811         }
812         final boolean wasEnabled = mBatterySaverController.isFullEnabled();
813 
814         if (wasEnabled == enable) {
815             if (DEBUG) {
816                 Slog.d(TAG, "Already " + (enable ? "enabled" : "disabled"));
817             }
818             return;
819         }
820         if (enable && mIsPowered) {
821             if (DEBUG) Slog.d(TAG, "Can't enable: isPowered");
822             return;
823         }
824         mLastChangedIntReason = intReason;
825         mLastChangedStrReason = strReason;
826 
827         mSettingBatterySaverEnabled = enable;
828         putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0);
829 
830         if (manual) {
831             setStickyActive(!mBatterySaverStickyBehaviourDisabled && enable);
832         }
833         mBatterySaverController.enableBatterySaver(enable, intReason);
834 
835         // Handle triggering the notification to show/hide when appropriate
836         if (intReason == BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON
837                 || intReason == BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON) {
838             if (Flags.updateAutoTurnOnNotificationStringAndAction()) {
839                 triggerDynamicModeNotificationV2();
840             } else {
841                 triggerDynamicModeNotification();
842             }
843         } else if (!enable) {
844             hideDynamicModeNotification();
845         }
846 
847         if (DEBUG) {
848             Slog.d(TAG, "Battery saver: Enabled=" + enable
849                     + " manual=" + manual
850                     + " reason=" + strReason + "(" + intReason + ")");
851         }
852     }
853 
854     @VisibleForTesting
triggerDynamicModeNotification()855     void triggerDynamicModeNotification() {
856         // The current lock is the PowerManager lock, which sits very low in the service lock
857         // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock.
858         runOnBgThread(() -> {
859             NotificationManager manager = mContext.getSystemService(NotificationManager.class);
860             ensureNotificationChannelExists(manager, DYNAMIC_MODE_NOTIF_CHANNEL_ID,
861                     R.string.dynamic_mode_notification_channel_name);
862 
863             manager.notifyAsUser(TAG, DYNAMIC_MODE_NOTIFICATION_ID,
864                     buildNotification(DYNAMIC_MODE_NOTIF_CHANNEL_ID,
865                             R.string.dynamic_mode_notification_title,
866                             R.string.dynamic_mode_notification_summary,
867                             Settings.ACTION_BATTERY_SAVER_SETTINGS, 0L),
868                     UserHandle.ALL);
869         });
870     }
871 
872     @VisibleForTesting
triggerDynamicModeNotificationV2()873     void triggerDynamicModeNotificationV2() {
874         // The current lock is the PowerManager lock, which sits very low in the service lock
875         // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock.
876         runOnBgThread(() -> {
877             NotificationManager manager = mContext.getSystemService(NotificationManager.class);
878             ensureNotificationChannelExists(manager, DYNAMIC_MODE_NOTIF_CHANNEL_ID,
879                     R.string.dynamic_mode_notification_channel_name);
880 
881             // The bundle is used for highlighting a settings item when launching the settings page.
882             final var highlightBundle = new Bundle(1 /* capacity */);
883             highlightBundle.putString(
884                     EXTRA_FRAGMENT_ARG_KEY, PREFERENCE_KEY_BATTERY_SAVER_SCHEDULER);
885 
886             manager.notifyAsUser(TAG, DYNAMIC_MODE_NOTIFICATION_ID,
887                     buildNotificationV2(DYNAMIC_MODE_NOTIF_CHANNEL_ID,
888                             R.string.dynamic_mode_notification_title_v2,
889                             R.string.dynamic_mode_notification_summary_v2,
890                             Settings.ACTION_BATTERY_SAVER_SETTINGS,
891                             0L /* timeoutMs */,
892                             highlightBundle),
893                     UserHandle.ALL);
894         });
895     }
896 
897     @VisibleForTesting
triggerStickyDisabledNotification()898     void triggerStickyDisabledNotification() {
899         if (!mBatterySaverTurnedOffNotificationEnabled) {
900             return;
901         }
902         // The current lock is the PowerManager lock, which sits very low in the service lock
903         // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock.
904         runOnBgThread(() -> {
905             NotificationManager manager = mContext.getSystemService(NotificationManager.class);
906             ensureNotificationChannelExists(manager, BATTERY_SAVER_NOTIF_CHANNEL_ID,
907                     R.string.battery_saver_notification_channel_name);
908 
909             manager.notifyAsUser(TAG, STICKY_AUTO_DISABLED_NOTIFICATION_ID,
910                     buildNotification(BATTERY_SAVER_NOTIF_CHANNEL_ID,
911                             R.string.battery_saver_off_notification_title,
912                             R.string.battery_saver_charged_notification_summary,
913                             Settings.ACTION_BATTERY_SAVER_SETTINGS,
914                             STICKY_DISABLED_NOTIFY_TIMEOUT_MS),
915                     UserHandle.ALL);
916         });
917     }
918 
ensureNotificationChannelExists(NotificationManager manager, @NonNull String channelId, @StringRes int nameId)919     private void ensureNotificationChannelExists(NotificationManager manager,
920             @NonNull String channelId, @StringRes int nameId) {
921         NotificationChannel channel = new NotificationChannel(
922                 channelId, mContext.getText(nameId), NotificationManager.IMPORTANCE_DEFAULT);
923         channel.setSound(null, null);
924         channel.setBlockable(true);
925         manager.createNotificationChannel(channel);
926     }
927 
buildNotification(@onNull String channelId, @StringRes int titleId, @StringRes int summaryId, @NonNull String intentAction, long timeoutMs)928     private Notification buildNotification(@NonNull String channelId, @StringRes int titleId,
929             @StringRes int summaryId, @NonNull String intentAction, long timeoutMs) {
930         Resources res = mContext.getResources();
931         Intent intent = new Intent(intentAction);
932         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
933         PendingIntent batterySaverIntent = PendingIntent.getActivity(
934                 mContext, 0 /* requestCode */, intent,
935                 PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
936         final String title = res.getString(titleId);
937         final String summary = res.getString(summaryId);
938 
939         return new Notification.Builder(mContext, channelId)
940                 .setSmallIcon(R.drawable.ic_battery)
941                 .setContentTitle(title)
942                 .setContentText(summary)
943                 .setContentIntent(batterySaverIntent)
944                 .setStyle(new Notification.BigTextStyle().bigText(summary))
945                 .setOnlyAlertOnce(true)
946                 .setAutoCancel(true)
947                 .setTimeoutAfter(timeoutMs)
948                 .build();
949     }
950 
buildNotificationV2(@onNull String channelId, @StringRes int titleId, @StringRes int summaryId, @NonNull String intentAction, long timeoutMs, @NonNull Bundle highlightBundle)951     private Notification buildNotificationV2(@NonNull String channelId, @StringRes int titleId,
952             @StringRes int summaryId, @NonNull String intentAction, long timeoutMs,
953             @NonNull Bundle highlightBundle) {
954         Resources res = mContext.getResources();
955         Intent intent = new Intent(intentAction)
956                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
957                 .putExtra(EXTRA_SHOW_FRAGMENT_TITLE, highlightBundle);
958 
959         PendingIntent batterySaverIntent = PendingIntent.getActivity(
960                 mContext, 0 /* requestCode */, intent,
961                 PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
962         final String title = res.getString(titleId);
963         final String summary = res.getString(summaryId);
964 
965         return new Notification.Builder(mContext, channelId)
966                 .setSmallIcon(R.drawable.ic_battery)
967                 .setContentTitle(title)
968                 .setContentText(summary)
969                 .setContentIntent(batterySaverIntent)
970                 .setStyle(new Notification.BigTextStyle().bigText(summary))
971                 .setOnlyAlertOnce(true)
972                 .setAutoCancel(true)
973                 .setTimeoutAfter(timeoutMs)
974                 .build();
975     }
976 
hideDynamicModeNotification()977     private void hideDynamicModeNotification() {
978         hideNotification(DYNAMIC_MODE_NOTIFICATION_ID);
979     }
980 
hideStickyDisabledNotification()981     private void hideStickyDisabledNotification() {
982         hideNotification(STICKY_AUTO_DISABLED_NOTIFICATION_ID);
983     }
984 
hideNotification(int notificationId)985     private void hideNotification(int notificationId) {
986         // The current lock is the PowerManager lock, which sits very low in the service lock
987         // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock.
988         runOnBgThread(() -> {
989             NotificationManager manager = mContext.getSystemService(NotificationManager.class);
990             manager.cancelAsUser(TAG, notificationId, UserHandle.ALL);
991         });
992     }
993 
setStickyActive(boolean active)994     private void setStickyActive(boolean active) {
995         mSettingBatterySaverEnabledSticky = active;
996         putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY,
997                 mSettingBatterySaverEnabledSticky ? 1 : 0);
998     }
999 
1000     @VisibleForTesting
putGlobalSetting(String key, int value)1001     protected void putGlobalSetting(String key, int value) {
1002         Settings.Global.putInt(mContext.getContentResolver(), key, value);
1003     }
1004 
1005     @VisibleForTesting
getGlobalSetting(String key, int defValue)1006     protected int getGlobalSetting(String key, int defValue) {
1007         return Settings.Global.getInt(mContext.getContentResolver(), key, defValue);
1008     }
1009 
dump(PrintWriter pw)1010     public void dump(PrintWriter pw) {
1011         final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
1012 
1013         ipw.println();
1014         ipw.println("Battery saver state machine:");
1015         ipw.increaseIndent();
1016         synchronized (mLock) {
1017             ipw.print("Enabled=");
1018             ipw.println(mBatterySaverController.isEnabled());
1019             ipw.increaseIndent();
1020             ipw.print("full=");
1021             ipw.println(mBatterySaverController.isFullEnabled());
1022             ipw.print("adaptive=");
1023             ipw.print(mBatterySaverController.isAdaptiveEnabled());
1024             if (mBatterySaverController.isAdaptiveEnabled()) {
1025                 ipw.print(" (advertise=");
1026                 ipw.print(getBatterySaverPolicy().shouldAdvertiseIsEnabled());
1027                 ipw.print(")");
1028             }
1029             ipw.decreaseIndent();
1030             ipw.println();
1031             ipw.print("mState=");
1032             ipw.println(mState);
1033 
1034             ipw.print("mLastChangedIntReason=");
1035             ipw.println(mLastChangedIntReason);
1036             ipw.print("mLastChangedStrReason=");
1037             ipw.println(mLastChangedStrReason);
1038 
1039             ipw.print("mBootCompleted=");
1040             ipw.println(mBootCompleted);
1041             ipw.print("mSettingsLoaded=");
1042             ipw.println(mSettingsLoaded);
1043             ipw.print("mBatteryStatusSet=");
1044             ipw.println(mBatteryStatusSet);
1045 
1046             ipw.print("mIsPowered=");
1047             ipw.println(mIsPowered);
1048             ipw.print("mBatteryLevel=");
1049             ipw.println(mBatteryLevel);
1050             ipw.print("mIsBatteryLevelLow=");
1051             ipw.println(mIsBatteryLevelLow);
1052 
1053             ipw.print("mSettingAutomaticBatterySaver=");
1054             ipw.println(mSettingAutomaticBatterySaver);
1055             ipw.print("mSettingBatterySaverEnabled=");
1056             ipw.println(mSettingBatterySaverEnabled);
1057             ipw.print("mSettingBatterySaverEnabledSticky=");
1058             ipw.println(mSettingBatterySaverEnabledSticky);
1059             ipw.print("mSettingBatterySaverStickyAutoDisableEnabled=");
1060             ipw.println(mSettingBatterySaverStickyAutoDisableEnabled);
1061             ipw.print("mSettingBatterySaverStickyAutoDisableThreshold=");
1062             ipw.println(mSettingBatterySaverStickyAutoDisableThreshold);
1063             ipw.print("mSettingBatterySaverTriggerThreshold=");
1064             ipw.println(mSettingBatterySaverTriggerThreshold);
1065             ipw.print("mBatterySaverStickyBehaviourDisabled=");
1066             ipw.println(mBatterySaverStickyBehaviourDisabled);
1067             ipw.print("mBatterySaverTurnedOffNotificationEnabled=");
1068             ipw.println(mBatterySaverTurnedOffNotificationEnabled);
1069 
1070             ipw.print("mDynamicPowerSavingsDefaultDisableThreshold=");
1071             ipw.println(mDynamicPowerSavingsDefaultDisableThreshold);
1072             ipw.print("mDynamicPowerSavingsDisableThreshold=");
1073             ipw.println(mDynamicPowerSavingsDisableThreshold);
1074             ipw.print("mDynamicPowerSavingsEnableBatterySaver=");
1075             ipw.println(mDynamicPowerSavingsEnableBatterySaver);
1076 
1077             ipw.print("mLastAdaptiveBatterySaverChangedExternallyElapsed=");
1078             ipw.println(mLastAdaptiveBatterySaverChangedExternallyElapsed);
1079         }
1080         ipw.decreaseIndent();
1081     }
1082 
dumpProto(ProtoOutputStream proto, long tag)1083     public void dumpProto(ProtoOutputStream proto, long tag) {
1084         synchronized (mLock) {
1085             final long token = proto.start(tag);
1086 
1087             proto.write(BatterySaverStateMachineProto.ENABLED,
1088                     mBatterySaverController.isEnabled());
1089             proto.write(BatterySaverStateMachineProto.STATE, mState);
1090             proto.write(BatterySaverStateMachineProto.IS_FULL_ENABLED,
1091                     mBatterySaverController.isFullEnabled());
1092             proto.write(BatterySaverStateMachineProto.IS_ADAPTIVE_ENABLED,
1093                     mBatterySaverController.isAdaptiveEnabled());
1094             proto.write(BatterySaverStateMachineProto.SHOULD_ADVERTISE_IS_ENABLED,
1095                     getBatterySaverPolicy().shouldAdvertiseIsEnabled());
1096 
1097             proto.write(BatterySaverStateMachineProto.BOOT_COMPLETED, mBootCompleted);
1098             proto.write(BatterySaverStateMachineProto.SETTINGS_LOADED, mSettingsLoaded);
1099             proto.write(BatterySaverStateMachineProto.BATTERY_STATUS_SET, mBatteryStatusSet);
1100 
1101 
1102             proto.write(BatterySaverStateMachineProto.IS_POWERED, mIsPowered);
1103             proto.write(BatterySaverStateMachineProto.BATTERY_LEVEL, mBatteryLevel);
1104             proto.write(BatterySaverStateMachineProto.IS_BATTERY_LEVEL_LOW, mIsBatteryLevelLow);
1105 
1106             proto.write(BatterySaverStateMachineProto.SETTING_AUTOMATIC_TRIGGER,
1107                     mSettingAutomaticBatterySaver);
1108             proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED,
1109                     mSettingBatterySaverEnabled);
1110             proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED_STICKY,
1111                     mSettingBatterySaverEnabledSticky);
1112             proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_TRIGGER_THRESHOLD,
1113                     mSettingBatterySaverTriggerThreshold);
1114             proto.write(
1115                     BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_STICKY_AUTO_DISABLE_ENABLED,
1116                     mSettingBatterySaverStickyAutoDisableEnabled);
1117             proto.write(
1118                     BatterySaverStateMachineProto
1119                             .SETTING_BATTERY_SAVER_STICKY_AUTO_DISABLE_THRESHOLD,
1120                     mSettingBatterySaverStickyAutoDisableThreshold);
1121 
1122             proto.write(
1123                     BatterySaverStateMachineProto.DEFAULT_DYNAMIC_DISABLE_THRESHOLD,
1124                     mDynamicPowerSavingsDefaultDisableThreshold);
1125             proto.write(
1126                     BatterySaverStateMachineProto.DYNAMIC_DISABLE_THRESHOLD,
1127                     mDynamicPowerSavingsDisableThreshold);
1128             proto.write(
1129                     BatterySaverStateMachineProto.DYNAMIC_BATTERY_SAVER_ENABLED,
1130                     mDynamicPowerSavingsEnableBatterySaver);
1131 
1132             proto.write(
1133                     BatterySaverStateMachineProto
1134                             .LAST_ADAPTIVE_BATTERY_SAVER_CHANGED_EXTERNALLY_ELAPSED,
1135                     mLastAdaptiveBatterySaverChangedExternallyElapsed);
1136 
1137             proto.end(token);
1138         }
1139     }
1140 }
1141