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 R.drawable.ic_settings), 869 UserHandle.ALL); 870 }); 871 } 872 873 @VisibleForTesting triggerDynamicModeNotificationV2()874 void triggerDynamicModeNotificationV2() { 875 // The current lock is the PowerManager lock, which sits very low in the service lock 876 // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock. 877 runOnBgThread(() -> { 878 NotificationManager manager = mContext.getSystemService(NotificationManager.class); 879 ensureNotificationChannelExists(manager, DYNAMIC_MODE_NOTIF_CHANNEL_ID, 880 R.string.dynamic_mode_notification_channel_name); 881 882 // The bundle is used for highlighting a settings item when launching the settings page. 883 final var highlightBundle = new Bundle(1 /* capacity */); 884 highlightBundle.putString( 885 EXTRA_FRAGMENT_ARG_KEY, PREFERENCE_KEY_BATTERY_SAVER_SCHEDULER); 886 887 manager.notifyAsUser(TAG, DYNAMIC_MODE_NOTIFICATION_ID, 888 buildNotificationV2(DYNAMIC_MODE_NOTIF_CHANNEL_ID, 889 R.string.dynamic_mode_notification_title_v2, 890 R.string.dynamic_mode_notification_summary_v2, 891 Settings.ACTION_BATTERY_SAVER_SETTINGS, 892 0L /* timeoutMs */, 893 highlightBundle, 894 R.drawable.ic_qs_battery_saver), 895 UserHandle.ALL); 896 }); 897 } 898 899 @VisibleForTesting triggerStickyDisabledNotification()900 void triggerStickyDisabledNotification() { 901 if (!mBatterySaverTurnedOffNotificationEnabled) { 902 return; 903 } 904 // The current lock is the PowerManager lock, which sits very low in the service lock 905 // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock. 906 runOnBgThread(() -> { 907 NotificationManager manager = mContext.getSystemService(NotificationManager.class); 908 ensureNotificationChannelExists(manager, BATTERY_SAVER_NOTIF_CHANNEL_ID, 909 R.string.battery_saver_notification_channel_name); 910 911 manager.notifyAsUser(TAG, STICKY_AUTO_DISABLED_NOTIFICATION_ID, 912 buildNotification(BATTERY_SAVER_NOTIF_CHANNEL_ID, 913 R.string.battery_saver_off_notification_title, 914 R.string.battery_saver_charged_notification_summary, 915 Settings.ACTION_BATTERY_SAVER_SETTINGS, 916 STICKY_DISABLED_NOTIFY_TIMEOUT_MS, 917 R.drawable.ic_settings), 918 UserHandle.ALL); 919 }); 920 } 921 ensureNotificationChannelExists(NotificationManager manager, @NonNull String channelId, @StringRes int nameId)922 private void ensureNotificationChannelExists(NotificationManager manager, 923 @NonNull String channelId, @StringRes int nameId) { 924 NotificationChannel channel = new NotificationChannel( 925 channelId, mContext.getText(nameId), NotificationManager.IMPORTANCE_DEFAULT); 926 channel.setSound(null, null); 927 channel.setBlockable(true); 928 manager.createNotificationChannel(channel); 929 } 930 buildNotification(@onNull String channelId, @StringRes int titleId, @StringRes int summaryId, @NonNull String intentAction, long timeoutMs, int iconResId)931 private Notification buildNotification(@NonNull String channelId, @StringRes int titleId, 932 @StringRes int summaryId, @NonNull String intentAction, long timeoutMs, int iconResId) { 933 Resources res = mContext.getResources(); 934 Intent intent = new Intent(intentAction); 935 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 936 PendingIntent batterySaverIntent = PendingIntent.getActivity( 937 mContext, 0 /* requestCode */, intent, 938 PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); 939 final String title = res.getString(titleId); 940 final String summary = res.getString(summaryId); 941 942 return new Notification.Builder(mContext, channelId) 943 .setSmallIcon(iconResId) 944 .setContentTitle(title) 945 .setContentText(summary) 946 .setContentIntent(batterySaverIntent) 947 .setStyle(new Notification.BigTextStyle().bigText(summary)) 948 .setOnlyAlertOnce(true) 949 .setAutoCancel(true) 950 .setTimeoutAfter(timeoutMs) 951 .build(); 952 } 953 buildNotificationV2(@onNull String channelId, @StringRes int titleId, @StringRes int summaryId, @NonNull String intentAction, long timeoutMs, @NonNull Bundle highlightBundle, int iconResId)954 private Notification buildNotificationV2(@NonNull String channelId, @StringRes int titleId, 955 @StringRes int summaryId, @NonNull String intentAction, long timeoutMs, 956 @NonNull Bundle highlightBundle, int iconResId) { 957 Resources res = mContext.getResources(); 958 Intent intent = new Intent(intentAction) 959 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) 960 .putExtra(EXTRA_SHOW_FRAGMENT_TITLE, highlightBundle); 961 962 PendingIntent batterySaverIntent = PendingIntent.getActivityAsUser( 963 mContext, 0 /* requestCode */, intent, 964 PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, 965 null /* options */, UserHandle.CURRENT); 966 final String title = res.getString(titleId); 967 final String summary = res.getString(summaryId); 968 969 return new Notification.Builder(mContext, channelId) 970 .setSmallIcon(iconResId) 971 .setContentTitle(title) 972 .setContentText(summary) 973 .setContentIntent(batterySaverIntent) 974 .setStyle(new Notification.BigTextStyle().bigText(summary)) 975 .setOnlyAlertOnce(true) 976 .setAutoCancel(true) 977 .setTimeoutAfter(timeoutMs) 978 .build(); 979 } 980 hideDynamicModeNotification()981 private void hideDynamicModeNotification() { 982 hideNotification(DYNAMIC_MODE_NOTIFICATION_ID); 983 } 984 hideStickyDisabledNotification()985 private void hideStickyDisabledNotification() { 986 hideNotification(STICKY_AUTO_DISABLED_NOTIFICATION_ID); 987 } 988 hideNotification(int notificationId)989 private void hideNotification(int notificationId) { 990 // The current lock is the PowerManager lock, which sits very low in the service lock 991 // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock. 992 runOnBgThread(() -> { 993 NotificationManager manager = mContext.getSystemService(NotificationManager.class); 994 manager.cancelAsUser(TAG, notificationId, UserHandle.ALL); 995 }); 996 } 997 setStickyActive(boolean active)998 private void setStickyActive(boolean active) { 999 mSettingBatterySaverEnabledSticky = active; 1000 putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY, 1001 mSettingBatterySaverEnabledSticky ? 1 : 0); 1002 } 1003 1004 @VisibleForTesting putGlobalSetting(String key, int value)1005 protected void putGlobalSetting(String key, int value) { 1006 Settings.Global.putInt(mContext.getContentResolver(), key, value); 1007 } 1008 1009 @VisibleForTesting getGlobalSetting(String key, int defValue)1010 protected int getGlobalSetting(String key, int defValue) { 1011 return Settings.Global.getInt(mContext.getContentResolver(), key, defValue); 1012 } 1013 dump(PrintWriter pw)1014 public void dump(PrintWriter pw) { 1015 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 1016 1017 ipw.println(); 1018 ipw.println("Battery saver state machine:"); 1019 ipw.increaseIndent(); 1020 synchronized (mLock) { 1021 ipw.print("Enabled="); 1022 ipw.println(mBatterySaverController.isEnabled()); 1023 ipw.increaseIndent(); 1024 ipw.print("full="); 1025 ipw.println(mBatterySaverController.isFullEnabled()); 1026 ipw.print("adaptive="); 1027 ipw.print(mBatterySaverController.isAdaptiveEnabled()); 1028 if (mBatterySaverController.isAdaptiveEnabled()) { 1029 ipw.print(" (advertise="); 1030 ipw.print(getBatterySaverPolicy().shouldAdvertiseIsEnabled()); 1031 ipw.print(")"); 1032 } 1033 ipw.decreaseIndent(); 1034 ipw.println(); 1035 ipw.print("mState="); 1036 ipw.println(mState); 1037 1038 ipw.print("mLastChangedIntReason="); 1039 ipw.println(mLastChangedIntReason); 1040 ipw.print("mLastChangedStrReason="); 1041 ipw.println(mLastChangedStrReason); 1042 1043 ipw.print("mBootCompleted="); 1044 ipw.println(mBootCompleted); 1045 ipw.print("mSettingsLoaded="); 1046 ipw.println(mSettingsLoaded); 1047 ipw.print("mBatteryStatusSet="); 1048 ipw.println(mBatteryStatusSet); 1049 1050 ipw.print("mIsPowered="); 1051 ipw.println(mIsPowered); 1052 ipw.print("mBatteryLevel="); 1053 ipw.println(mBatteryLevel); 1054 ipw.print("mIsBatteryLevelLow="); 1055 ipw.println(mIsBatteryLevelLow); 1056 1057 ipw.print("mSettingAutomaticBatterySaver="); 1058 ipw.println(mSettingAutomaticBatterySaver); 1059 ipw.print("mSettingBatterySaverEnabled="); 1060 ipw.println(mSettingBatterySaverEnabled); 1061 ipw.print("mSettingBatterySaverEnabledSticky="); 1062 ipw.println(mSettingBatterySaverEnabledSticky); 1063 ipw.print("mSettingBatterySaverStickyAutoDisableEnabled="); 1064 ipw.println(mSettingBatterySaverStickyAutoDisableEnabled); 1065 ipw.print("mSettingBatterySaverStickyAutoDisableThreshold="); 1066 ipw.println(mSettingBatterySaverStickyAutoDisableThreshold); 1067 ipw.print("mSettingBatterySaverTriggerThreshold="); 1068 ipw.println(mSettingBatterySaverTriggerThreshold); 1069 ipw.print("mBatterySaverStickyBehaviourDisabled="); 1070 ipw.println(mBatterySaverStickyBehaviourDisabled); 1071 ipw.print("mBatterySaverTurnedOffNotificationEnabled="); 1072 ipw.println(mBatterySaverTurnedOffNotificationEnabled); 1073 1074 ipw.print("mDynamicPowerSavingsDefaultDisableThreshold="); 1075 ipw.println(mDynamicPowerSavingsDefaultDisableThreshold); 1076 ipw.print("mDynamicPowerSavingsDisableThreshold="); 1077 ipw.println(mDynamicPowerSavingsDisableThreshold); 1078 ipw.print("mDynamicPowerSavingsEnableBatterySaver="); 1079 ipw.println(mDynamicPowerSavingsEnableBatterySaver); 1080 1081 ipw.print("mLastAdaptiveBatterySaverChangedExternallyElapsed="); 1082 ipw.println(mLastAdaptiveBatterySaverChangedExternallyElapsed); 1083 } 1084 ipw.decreaseIndent(); 1085 } 1086 dumpProto(ProtoOutputStream proto, long tag)1087 public void dumpProto(ProtoOutputStream proto, long tag) { 1088 synchronized (mLock) { 1089 final long token = proto.start(tag); 1090 1091 proto.write(BatterySaverStateMachineProto.ENABLED, 1092 mBatterySaverController.isEnabled()); 1093 proto.write(BatterySaverStateMachineProto.STATE, mState); 1094 proto.write(BatterySaverStateMachineProto.IS_FULL_ENABLED, 1095 mBatterySaverController.isFullEnabled()); 1096 proto.write(BatterySaverStateMachineProto.IS_ADAPTIVE_ENABLED, 1097 mBatterySaverController.isAdaptiveEnabled()); 1098 proto.write(BatterySaverStateMachineProto.SHOULD_ADVERTISE_IS_ENABLED, 1099 getBatterySaverPolicy().shouldAdvertiseIsEnabled()); 1100 1101 proto.write(BatterySaverStateMachineProto.BOOT_COMPLETED, mBootCompleted); 1102 proto.write(BatterySaverStateMachineProto.SETTINGS_LOADED, mSettingsLoaded); 1103 proto.write(BatterySaverStateMachineProto.BATTERY_STATUS_SET, mBatteryStatusSet); 1104 1105 1106 proto.write(BatterySaverStateMachineProto.IS_POWERED, mIsPowered); 1107 proto.write(BatterySaverStateMachineProto.BATTERY_LEVEL, mBatteryLevel); 1108 proto.write(BatterySaverStateMachineProto.IS_BATTERY_LEVEL_LOW, mIsBatteryLevelLow); 1109 1110 proto.write(BatterySaverStateMachineProto.SETTING_AUTOMATIC_TRIGGER, 1111 mSettingAutomaticBatterySaver); 1112 proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED, 1113 mSettingBatterySaverEnabled); 1114 proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED_STICKY, 1115 mSettingBatterySaverEnabledSticky); 1116 proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_TRIGGER_THRESHOLD, 1117 mSettingBatterySaverTriggerThreshold); 1118 proto.write( 1119 BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_STICKY_AUTO_DISABLE_ENABLED, 1120 mSettingBatterySaverStickyAutoDisableEnabled); 1121 proto.write( 1122 BatterySaverStateMachineProto 1123 .SETTING_BATTERY_SAVER_STICKY_AUTO_DISABLE_THRESHOLD, 1124 mSettingBatterySaverStickyAutoDisableThreshold); 1125 1126 proto.write( 1127 BatterySaverStateMachineProto.DEFAULT_DYNAMIC_DISABLE_THRESHOLD, 1128 mDynamicPowerSavingsDefaultDisableThreshold); 1129 proto.write( 1130 BatterySaverStateMachineProto.DYNAMIC_DISABLE_THRESHOLD, 1131 mDynamicPowerSavingsDisableThreshold); 1132 proto.write( 1133 BatterySaverStateMachineProto.DYNAMIC_BATTERY_SAVER_ENABLED, 1134 mDynamicPowerSavingsEnableBatterySaver); 1135 1136 proto.write( 1137 BatterySaverStateMachineProto 1138 .LAST_ADAPTIVE_BATTERY_SAVER_CHANGED_EXTERNALLY_ELAPSED, 1139 mLastAdaptiveBatterySaverChangedExternallyElapsed); 1140 1141 proto.end(token); 1142 } 1143 } 1144 } 1145