1 /* 2 * Copyright (C) 2017 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 android.Manifest; 19 import android.annotation.Nullable; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.content.pm.PackageManagerInternal; 25 import android.hardware.power.Mode; 26 import android.os.BatteryManager; 27 import android.os.BatterySaverPolicyConfig; 28 import android.os.Handler; 29 import android.os.Looper; 30 import android.os.Message; 31 import android.os.PowerManager; 32 import android.os.PowerManagerInternal; 33 import android.os.PowerManagerInternal.LowPowerModeListener; 34 import android.os.PowerSaveState; 35 import android.os.UserHandle; 36 import android.util.Slog; 37 38 import com.android.internal.R; 39 import com.android.internal.annotations.GuardedBy; 40 import com.android.internal.annotations.VisibleForTesting; 41 import com.android.server.EventLogTags; 42 import com.android.server.LocalServices; 43 import com.android.server.power.batterysaver.BatterySaverPolicy.BatterySaverPolicyListener; 44 import com.android.server.power.batterysaver.BatterySaverPolicy.Policy; 45 import com.android.server.power.batterysaver.BatterySaverPolicy.PolicyLevel; 46 import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState; 47 import com.android.server.power.batterysaver.BatterySavingStats.DozeState; 48 import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState; 49 import com.android.server.power.batterysaver.BatterySavingStats.PlugState; 50 51 import java.util.ArrayList; 52 import java.util.Objects; 53 import java.util.Optional; 54 55 /** 56 * Responsible for battery saver mode transition logic. 57 * 58 * IMPORTANT: This class shares the power manager lock, which is very low in the lock hierarchy. 59 * Do not call out with the lock held. (Settings provider is okay.) 60 */ 61 public class BatterySaverController implements BatterySaverPolicyListener { 62 static final String TAG = "BatterySaverController"; 63 64 static final boolean DEBUG = BatterySaverPolicy.DEBUG; 65 66 private final Object mLock; 67 private final Context mContext; 68 private final MyHandler mHandler; 69 70 private PowerManager mPowerManager; 71 72 private final BatterySaverPolicy mBatterySaverPolicy; 73 74 private final BatterySavingStats mBatterySavingStats; 75 76 @GuardedBy("mLock") 77 private final ArrayList<LowPowerModeListener> mListeners = new ArrayList<>(); 78 79 /** 80 * Do not access directly; always use {@link #setFullEnabledLocked} 81 * and {@link #getFullEnabledLocked} 82 */ 83 @GuardedBy("mLock") 84 private boolean mFullEnabledRaw; 85 86 /** 87 * Do not access directly; always use {@link #setAdaptiveEnabledLocked} and 88 * {@link #getAdaptiveEnabledLocked}. 89 */ 90 @GuardedBy("mLock") 91 private boolean mAdaptiveEnabledRaw; 92 93 @GuardedBy("mLock") 94 private boolean mIsPluggedIn; 95 96 /** 97 * Whether full was previously enabled or not; only for the event logging. Only use it from 98 * {@link #handleBatterySaverStateChanged}. 99 */ 100 private boolean mFullPreviouslyEnabled; 101 102 /** 103 * Whether adaptive was previously enabled or not; only for the event logging. Only use it from 104 * {@link #handleBatterySaverStateChanged}. 105 */ 106 private boolean mAdaptivePreviouslyEnabled; 107 108 @GuardedBy("mLock") 109 private boolean mIsInteractive; 110 111 /** 112 * Package name that will receive an explicit manifest broadcast for 113 * {@link PowerManager#ACTION_POWER_SAVE_MODE_CHANGED}. It's {@code null} if it hasn't been 114 * retrieved yet. 115 */ 116 @Nullable 117 private Optional<String> mPowerSaveModeChangedListenerPackage; 118 119 public static final int REASON_PERCENTAGE_AUTOMATIC_ON = 0; 120 public static final int REASON_PERCENTAGE_AUTOMATIC_OFF = 1; 121 public static final int REASON_MANUAL_ON = 2; 122 public static final int REASON_MANUAL_OFF = 3; 123 public static final int REASON_STICKY_RESTORE = 4; 124 public static final int REASON_INTERACTIVE_CHANGED = 5; 125 public static final int REASON_POLICY_CHANGED = 6; 126 public static final int REASON_PLUGGED_IN = 7; 127 public static final int REASON_SETTING_CHANGED = 8; 128 public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON = 9; 129 public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF = 10; 130 public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 11; 131 public static final int REASON_TIMEOUT = 12; 132 public static final int REASON_FULL_POWER_SAVINGS_CHANGED = 13; 133 reasonToString(int reason)134 static String reasonToString(int reason) { 135 switch (reason) { 136 case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON: 137 return "Percentage Auto ON"; 138 case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF: 139 return "Percentage Auto OFF"; 140 case BatterySaverController.REASON_MANUAL_ON: 141 return "Manual ON"; 142 case BatterySaverController.REASON_MANUAL_OFF: 143 return "Manual OFF"; 144 case BatterySaverController.REASON_STICKY_RESTORE: 145 return "Sticky restore"; 146 case BatterySaverController.REASON_INTERACTIVE_CHANGED: 147 return "Interactivity changed"; 148 case BatterySaverController.REASON_POLICY_CHANGED: 149 return "Policy changed"; 150 case BatterySaverController.REASON_PLUGGED_IN: 151 return "Plugged in"; 152 case BatterySaverController.REASON_SETTING_CHANGED: 153 return "Setting changed"; 154 case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON: 155 return "Dynamic Warning Auto ON"; 156 case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF: 157 return "Dynamic Warning Auto OFF"; 158 case BatterySaverController.REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED: 159 return "Adaptive Power Savings changed"; 160 case BatterySaverController.REASON_TIMEOUT: 161 return "timeout"; 162 case BatterySaverController.REASON_FULL_POWER_SAVINGS_CHANGED: 163 return "Full Power Savings changed"; 164 default: 165 return "Unknown reason: " + reason; 166 } 167 } 168 169 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 170 @Override 171 public void onReceive(Context context, Intent intent) { 172 if (DEBUG) { 173 Slog.d(TAG, "onReceive: " + intent); 174 } 175 switch (intent.getAction()) { 176 case Intent.ACTION_SCREEN_ON: 177 case Intent.ACTION_SCREEN_OFF: 178 if (!isPolicyEnabled()) { 179 updateBatterySavingStats(); 180 return; // No need to send it if not enabled. 181 } 182 // We currently evaluate state only for CPU frequency changes. 183 // Don't send the broadcast, because we never did so in this case. 184 mHandler.postStateChanged(/*sendBroadcast=*/ false, 185 REASON_INTERACTIVE_CHANGED); 186 break; 187 case Intent.ACTION_BATTERY_CHANGED: 188 synchronized (mLock) { 189 mIsPluggedIn = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0); 190 } 191 // Fall-through. 192 case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED: 193 case PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED: 194 updateBatterySavingStats(); 195 break; 196 } 197 } 198 }; 199 200 /** 201 * Constructor. 202 */ BatterySaverController(Object lock, Context context, Looper looper, BatterySaverPolicy policy, BatterySavingStats batterySavingStats)203 public BatterySaverController(Object lock, Context context, Looper looper, 204 BatterySaverPolicy policy, BatterySavingStats batterySavingStats) { 205 mLock = lock; 206 mContext = context; 207 mHandler = new MyHandler(looper); 208 mBatterySaverPolicy = policy; 209 mBatterySaverPolicy.addListener(this); 210 mBatterySavingStats = batterySavingStats; 211 212 PowerManager.invalidatePowerSaveModeCaches(); 213 } 214 215 /** 216 * Add a listener. 217 */ addListener(LowPowerModeListener listener)218 public void addListener(LowPowerModeListener listener) { 219 synchronized (mLock) { 220 mListeners.add(listener); 221 } 222 } 223 224 /** 225 * Called by {@link BatterySaverStateMachine} on system ready, *with no lock held*. 226 */ systemReady()227 public void systemReady() { 228 final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); 229 filter.addAction(Intent.ACTION_SCREEN_OFF); 230 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 231 filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 232 filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED); 233 mContext.registerReceiver(mReceiver, filter); 234 235 mHandler.postSystemReady(); 236 } 237 getPowerManager()238 private PowerManager getPowerManager() { 239 if (mPowerManager == null) { 240 mPowerManager = 241 Objects.requireNonNull(mContext.getSystemService(PowerManager.class)); 242 } 243 return mPowerManager; 244 } 245 246 @Override onBatterySaverPolicyChanged(BatterySaverPolicy policy)247 public void onBatterySaverPolicyChanged(BatterySaverPolicy policy) { 248 if (!isPolicyEnabled()) { 249 return; // No need to send it if not enabled. 250 } 251 mHandler.postStateChanged(/*sendBroadcast=*/ true, REASON_POLICY_CHANGED); 252 } 253 254 private class MyHandler extends Handler { 255 private static final int MSG_STATE_CHANGED = 1; 256 257 private static final int ARG_DONT_SEND_BROADCAST = 0; 258 private static final int ARG_SEND_BROADCAST = 1; 259 260 private static final int MSG_SYSTEM_READY = 2; 261 MyHandler(Looper looper)262 public MyHandler(Looper looper) { 263 super(looper); 264 } 265 postStateChanged(boolean sendBroadcast, int reason)266 void postStateChanged(boolean sendBroadcast, int reason) { 267 obtainMessage(MSG_STATE_CHANGED, sendBroadcast ? 268 ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, reason).sendToTarget(); 269 } 270 postSystemReady()271 public void postSystemReady() { 272 obtainMessage(MSG_SYSTEM_READY, 0, 0).sendToTarget(); 273 } 274 275 @Override dispatchMessage(Message msg)276 public void dispatchMessage(Message msg) { 277 switch (msg.what) { 278 case MSG_STATE_CHANGED: 279 handleBatterySaverStateChanged( 280 msg.arg1 == ARG_SEND_BROADCAST, 281 msg.arg2); 282 break; 283 } 284 } 285 } 286 287 /** Enable or disable full battery saver. */ 288 @VisibleForTesting enableBatterySaver(boolean enable, int reason)289 public void enableBatterySaver(boolean enable, int reason) { 290 synchronized (mLock) { 291 if (getFullEnabledLocked() == enable) { 292 return; 293 } 294 setFullEnabledLocked(enable); 295 296 if (updatePolicyLevelLocked()) { 297 mHandler.postStateChanged(/*sendBroadcast=*/ true, reason); 298 } 299 } 300 } 301 updatePolicyLevelLocked()302 private boolean updatePolicyLevelLocked() { 303 if (getFullEnabledLocked()) { 304 return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_FULL); 305 } else if (getAdaptiveEnabledLocked()) { 306 return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_ADAPTIVE); 307 } else { 308 return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_OFF); 309 } 310 } 311 getPolicyLocked(@olicyLevel int policyLevel)312 BatterySaverPolicyConfig getPolicyLocked(@PolicyLevel int policyLevel) { 313 return mBatterySaverPolicy.getPolicyLocked(policyLevel).toConfig(); 314 } 315 316 /** 317 * @return whether battery saver is enabled or not. This takes into 318 * account whether a policy says to advertise isEnabled so this can be propagated externally. 319 */ isEnabled()320 public boolean isEnabled() { 321 synchronized (mLock) { 322 return getFullEnabledLocked() || (getAdaptiveEnabledLocked() 323 && mBatterySaverPolicy.shouldAdvertiseIsEnabled()); 324 } 325 } 326 327 /** 328 * @return whether battery saver policy is enabled or not. This does not take into account 329 * whether a policy says to advertise isEnabled, so this shouldn't be propagated externally. 330 */ isPolicyEnabled()331 private boolean isPolicyEnabled() { 332 synchronized (mLock) { 333 return getFullEnabledLocked() || getAdaptiveEnabledLocked(); 334 } 335 } 336 isFullEnabled()337 boolean isFullEnabled() { 338 synchronized (mLock) { 339 return getFullEnabledLocked(); 340 } 341 } 342 setFullPolicyLocked(BatterySaverPolicyConfig config, int reason)343 boolean setFullPolicyLocked(BatterySaverPolicyConfig config, int reason) { 344 return setFullPolicyLocked(BatterySaverPolicy.Policy.fromConfig(config), reason); 345 } 346 setFullPolicyLocked(Policy policy, int reason)347 boolean setFullPolicyLocked(Policy policy, int reason) { 348 if (mBatterySaverPolicy.setFullPolicyLocked(policy)) { 349 mHandler.postStateChanged(/*sendBroadcast=*/ true, reason); 350 return true; 351 } 352 return false; 353 } 354 isAdaptiveEnabled()355 boolean isAdaptiveEnabled() { 356 synchronized (mLock) { 357 return getAdaptiveEnabledLocked(); 358 } 359 } 360 setAdaptivePolicyLocked(BatterySaverPolicyConfig config, int reason)361 boolean setAdaptivePolicyLocked(BatterySaverPolicyConfig config, int reason) { 362 return setAdaptivePolicyLocked(BatterySaverPolicy.Policy.fromConfig(config), reason); 363 } 364 setAdaptivePolicyLocked(Policy policy, int reason)365 boolean setAdaptivePolicyLocked(Policy policy, int reason) { 366 if (mBatterySaverPolicy.setAdaptivePolicyLocked(policy)) { 367 mHandler.postStateChanged(/*sendBroadcast=*/ true, reason); 368 return true; 369 } 370 return false; 371 } 372 resetAdaptivePolicyLocked(int reason)373 boolean resetAdaptivePolicyLocked(int reason) { 374 if (mBatterySaverPolicy.resetAdaptivePolicyLocked()) { 375 mHandler.postStateChanged(/*sendBroadcast=*/ true, reason); 376 return true; 377 } 378 return false; 379 } 380 setAdaptivePolicyEnabledLocked(boolean enabled, int reason)381 boolean setAdaptivePolicyEnabledLocked(boolean enabled, int reason) { 382 if (getAdaptiveEnabledLocked() == enabled) { 383 return false; 384 } 385 setAdaptiveEnabledLocked(enabled); 386 if (updatePolicyLevelLocked()) { 387 mHandler.postStateChanged(/*sendBroadcast=*/ true, reason); 388 return true; 389 } 390 return false; 391 } 392 393 /** @return whether device is in interactive state. */ isInteractive()394 public boolean isInteractive() { 395 synchronized (mLock) { 396 return mIsInteractive; 397 } 398 } 399 400 /** @return Battery saver policy. */ getBatterySaverPolicy()401 public BatterySaverPolicy getBatterySaverPolicy() { 402 return mBatterySaverPolicy; 403 } 404 405 /** 406 * @return true if launch boost should currently be disabled. 407 */ isLaunchBoostDisabled()408 public boolean isLaunchBoostDisabled() { 409 return isPolicyEnabled() && mBatterySaverPolicy.isLaunchBoostDisabled(); 410 } 411 412 /** 413 * Dispatch power save events to the listeners. 414 * 415 * This method is always called on the handler thread. 416 * 417 * This method is called only in the following cases: 418 * - When battery saver becomes activated. 419 * - When battery saver becomes deactivated. 420 * - When battery saver is on and the interactive state changes. 421 * - When battery saver is on and the battery saver policy changes. 422 * - When adaptive battery saver becomes activated. 423 * - When adaptive battery saver becomes deactivated. 424 * - When adaptive battery saver is active (and full is off) and the policy changes. 425 */ handleBatterySaverStateChanged(boolean sendBroadcast, int reason)426 void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) { 427 final LowPowerModeListener[] listeners; 428 429 final boolean enabled; 430 final boolean isInteractive = getPowerManager().isInteractive(); 431 432 synchronized (mLock) { 433 enabled = getFullEnabledLocked() || getAdaptiveEnabledLocked(); 434 435 EventLogTags.writeBatterySaverMode( 436 mFullPreviouslyEnabled ? 1 : 0, // Previously off or on. 437 mAdaptivePreviouslyEnabled ? 1 : 0, // Previously off or on. 438 getFullEnabledLocked() ? 1 : 0, // Now off or on. 439 getAdaptiveEnabledLocked() ? 1 : 0, // Now off or on. 440 isInteractive ? 1 : 0, // Device interactive state. 441 enabled ? mBatterySaverPolicy.toEventLogString() : "", 442 reason); 443 444 mFullPreviouslyEnabled = getFullEnabledLocked(); 445 mAdaptivePreviouslyEnabled = getAdaptiveEnabledLocked(); 446 447 listeners = mListeners.toArray(new LowPowerModeListener[0]); 448 449 mIsInteractive = isInteractive; 450 } 451 452 final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class); 453 if (pmi != null) { 454 pmi.setPowerMode(Mode.LOW_POWER, isEnabled()); 455 } 456 457 updateBatterySavingStats(); 458 459 if (sendBroadcast) { 460 461 if (DEBUG) { 462 Slog.i(TAG, "Sending broadcasts for mode: " + isEnabled()); 463 } 464 465 // Send the broadcasts and notify the listeners. We only do this when the battery saver 466 // mode changes, but not when only the screen state changes. 467 Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 468 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 469 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 470 471 // Send the broadcast to a manifest-registered receiver that is specified in the config. 472 if (getPowerSaveModeChangedListenerPackage().isPresent()) { 473 intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED) 474 .setPackage(getPowerSaveModeChangedListenerPackage().get()) 475 .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND 476 | Intent.FLAG_RECEIVER_FOREGROUND); 477 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 478 } 479 480 // Send internal version that requires signature permission. 481 intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL); 482 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 483 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 484 Manifest.permission.DEVICE_POWER); 485 486 for (LowPowerModeListener listener : listeners) { 487 final PowerSaveState result = 488 mBatterySaverPolicy.getBatterySaverPolicy(listener.getServiceType()); 489 listener.onLowPowerModeChanged(result); 490 } 491 } 492 } 493 getPowerSaveModeChangedListenerPackage()494 private Optional<String> getPowerSaveModeChangedListenerPackage() { 495 if (mPowerSaveModeChangedListenerPackage == null) { 496 String configPowerSaveModeChangedListenerPackage = 497 mContext.getString(R.string.config_powerSaveModeChangedListenerPackage); 498 mPowerSaveModeChangedListenerPackage = 499 LocalServices 500 .getService(PackageManagerInternal.class) 501 .isSystemPackage(configPowerSaveModeChangedListenerPackage) 502 ? Optional.of(configPowerSaveModeChangedListenerPackage) 503 : Optional.empty(); 504 } 505 return mPowerSaveModeChangedListenerPackage; 506 } 507 updateBatterySavingStats()508 private void updateBatterySavingStats() { 509 final PowerManager pm = getPowerManager(); 510 if (pm == null) { 511 Slog.wtf(TAG, "PowerManager not initialized"); 512 return; 513 } 514 final boolean isInteractive = pm.isInteractive(); 515 final int dozeMode = 516 pm.isDeviceIdleMode() ? DozeState.DEEP 517 : pm.isLightDeviceIdleMode() ? DozeState.LIGHT 518 : DozeState.NOT_DOZING; 519 520 synchronized (mLock) { 521 mBatterySavingStats.transitionState( 522 getFullEnabledLocked() ? BatterySaverState.ON : 523 (getAdaptiveEnabledLocked() ? BatterySaverState.ADAPTIVE : 524 BatterySaverState.OFF), 525 isInteractive ? InteractiveState.INTERACTIVE : 526 InteractiveState.NON_INTERACTIVE, 527 dozeMode, 528 mIsPluggedIn ? PlugState.PLUGGED : PlugState.UNPLUGGED); 529 } 530 } 531 532 @GuardedBy("mLock") setFullEnabledLocked(boolean value)533 private void setFullEnabledLocked(boolean value) { 534 if (mFullEnabledRaw == value) { 535 return; 536 } 537 PowerManager.invalidatePowerSaveModeCaches(); 538 mFullEnabledRaw = value; 539 } 540 541 /** Non-blocking getter exists as a reminder not to directly modify the cached field */ getFullEnabledLocked()542 private boolean getFullEnabledLocked() { 543 return mFullEnabledRaw; 544 } 545 546 @GuardedBy("mLock") setAdaptiveEnabledLocked(boolean value)547 private void setAdaptiveEnabledLocked(boolean value) { 548 if (mAdaptiveEnabledRaw == value) { 549 return; 550 } 551 PowerManager.invalidatePowerSaveModeCaches(); 552 mAdaptiveEnabledRaw = value; 553 } 554 555 /** Non-blocking getter exists as a reminder not to directly modify the cached field */ getAdaptiveEnabledLocked()556 private boolean getAdaptiveEnabledLocked() { 557 return mAdaptiveEnabledRaw; 558 } 559 } 560