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