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