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