1 /* 2 * Copyright (C) 2021 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 17 package com.android.server.power; 18 19 import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL; 20 import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST; 21 import static android.os.PowerManager.lowPowerStandbyAllowedReasonsToString; 22 23 import android.Manifest; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.app.ActivityManager; 27 import android.app.ActivityManagerInternal; 28 import android.app.AlarmManager; 29 import android.app.IActivityManager; 30 import android.app.IForegroundServiceObserver; 31 import android.content.BroadcastReceiver; 32 import android.content.ContentResolver; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.IntentFilter; 36 import android.content.pm.PackageManager; 37 import android.content.pm.ServiceInfo; 38 import android.content.res.Resources; 39 import android.database.ContentObserver; 40 import android.net.Uri; 41 import android.os.Environment; 42 import android.os.Handler; 43 import android.os.IBinder; 44 import android.os.Looper; 45 import android.os.Message; 46 import android.os.PowerManager; 47 import android.os.PowerManager.LowPowerStandbyAllowedReason; 48 import android.os.PowerManager.LowPowerStandbyPolicy; 49 import android.os.PowerManager.LowPowerStandbyPortDescription; 50 import android.os.PowerManagerInternal; 51 import android.os.RemoteException; 52 import android.os.SystemClock; 53 import android.os.UserHandle; 54 import android.os.UserManager; 55 import android.provider.DeviceConfig; 56 import android.provider.Settings; 57 import android.text.TextUtils; 58 import android.util.ArraySet; 59 import android.util.AtomicFile; 60 import android.util.IndentingPrintWriter; 61 import android.util.Slog; 62 import android.util.SparseBooleanArray; 63 import android.util.SparseIntArray; 64 import android.util.Xml; 65 import android.util.proto.ProtoOutputStream; 66 67 import com.android.internal.R; 68 import com.android.internal.annotations.GuardedBy; 69 import com.android.internal.annotations.VisibleForTesting; 70 import com.android.modules.utils.TypedXmlPullParser; 71 import com.android.modules.utils.TypedXmlSerializer; 72 import com.android.server.LocalServices; 73 import com.android.server.PowerAllowlistInternal; 74 import com.android.server.net.NetworkPolicyManagerInternal; 75 76 import org.xmlpull.v1.XmlPullParser; 77 import org.xmlpull.v1.XmlPullParserException; 78 79 import java.io.File; 80 import java.io.FileInputStream; 81 import java.io.FileNotFoundException; 82 import java.io.FileOutputStream; 83 import java.io.IOException; 84 import java.io.PrintWriter; 85 import java.util.ArrayList; 86 import java.util.Arrays; 87 import java.util.Collections; 88 import java.util.List; 89 import java.util.Objects; 90 import java.util.Set; 91 import java.util.concurrent.Executor; 92 import java.util.function.Supplier; 93 94 /** 95 * Controls Low Power Standby state. 96 * 97 * Instantiated by {@link PowerManagerService} only if Low Power Standby is supported. 98 * 99 * <p>Low Power Standby is active when all of the following conditions are met: 100 * <ul> 101 * <li>Low Power Standby is enabled 102 * <li>The device is not interactive, and has been non-interactive for a given timeout 103 * <li>The device is not in a doze maintenance window (devices may be configured to also 104 * apply restrictions during doze maintenance windows, see {@link #setActiveDuringMaintenance}) 105 * </ul> 106 * 107 * <p>When Low Power Standby is active, the following restrictions are applied to applications 108 * with procstate less important than {@link android.app.ActivityManager#PROCESS_STATE_BOUND_TOP} 109 * unless they are exempted (see {@link LowPowerStandbyPolicy}): 110 * <ul> 111 * <li>Network access is blocked 112 * <li>Wakelocks are disabled 113 * </ul> 114 * 115 * @hide 116 */ 117 public class LowPowerStandbyController { 118 private static final String TAG = "LowPowerStandbyController"; 119 private static final boolean DEBUG = false; 120 private static final boolean DEFAULT_ACTIVE_DURING_MAINTENANCE = false; 121 122 private static final int MSG_STANDBY_TIMEOUT = 0; 123 private static final int MSG_NOTIFY_ACTIVE_CHANGED = 1; 124 private static final int MSG_NOTIFY_ALLOWLIST_CHANGED = 2; 125 private static final int MSG_NOTIFY_POLICY_CHANGED = 3; 126 private static final int MSG_FOREGROUND_SERVICE_STATE_CHANGED = 4; 127 private static final int MSG_NOTIFY_STANDBY_PORTS_CHANGED = 5; 128 129 private static final String TAG_ROOT = "low-power-standby-policy"; 130 private static final String TAG_IDENTIFIER = "identifier"; 131 private static final String TAG_EXEMPT_PACKAGE = "exempt-package"; 132 private static final String TAG_ALLOWED_REASONS = "allowed-reasons"; 133 private static final String TAG_ALLOWED_FEATURES = "allowed-features"; 134 private static final String ATTR_VALUE = "value"; 135 136 private final Handler mHandler; 137 private final SettingsObserver mSettingsObserver; 138 private final DeviceConfigWrapper mDeviceConfig; 139 private final Supplier<IActivityManager> mActivityManager; 140 private final File mPolicyFile; 141 private final Object mLock = new Object(); 142 143 private final Context mContext; 144 private final Clock mClock; 145 private final AlarmManager.OnAlarmListener mOnStandbyTimeoutExpired = 146 this::onStandbyTimeoutExpired; 147 private final LowPowerStandbyControllerInternal mLocalService = new LocalService(); 148 private final SparseIntArray mUidAllowedReasons = new SparseIntArray(); 149 private final List<StandbyPortsLock> mStandbyPortLocks = new ArrayList<>(); 150 151 @GuardedBy("mLock") 152 private boolean mEnableCustomPolicy; 153 private boolean mEnableStandbyPorts; 154 155 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 156 @Override 157 public void onReceive(Context context, Intent intent) { 158 switch (intent.getAction()) { 159 case Intent.ACTION_SCREEN_OFF: 160 onNonInteractive(); 161 break; 162 case Intent.ACTION_SCREEN_ON: 163 onInteractive(); 164 break; 165 case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED: 166 onDeviceIdleModeChanged(); 167 break; 168 } 169 } 170 }; 171 private final TempAllowlistChangeListener mTempAllowlistChangeListener = 172 new TempAllowlistChangeListener(); 173 private final PhoneCallServiceTracker mPhoneCallServiceTracker = new PhoneCallServiceTracker(); 174 175 private final BroadcastReceiver mPackageBroadcastReceiver = new BroadcastReceiver() { 176 @Override 177 public void onReceive(Context context, Intent intent) { 178 if (DEBUG) { 179 Slog.d(TAG, "Received package intent: action=" + intent.getAction() + ", data=" 180 + intent.getData()); 181 } 182 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 183 if (replacing) { 184 return; 185 } 186 final Uri intentUri = intent.getData(); 187 final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart() 188 : null; 189 synchronized (mLock) { 190 final LowPowerStandbyPolicy policy = getPolicy(); 191 if (policy.getExemptPackages().contains(packageName)) { 192 enqueueNotifyAllowlistChangedLocked(); 193 } 194 } 195 } 196 }; 197 198 private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() { 199 @Override 200 public void onReceive(Context context, Intent intent) { 201 if (DEBUG) { 202 Slog.d(TAG, "Received user intent: action=" + intent.getAction()); 203 } 204 synchronized (mLock) { 205 enqueueNotifyAllowlistChangedLocked(); 206 } 207 } 208 }; 209 210 private final class StandbyPortsLock implements IBinder.DeathRecipient { 211 private final IBinder mToken; 212 private final int mUid; 213 private final List<LowPowerStandbyPortDescription> mPorts; 214 StandbyPortsLock(IBinder token, int uid, List<LowPowerStandbyPortDescription> ports)215 StandbyPortsLock(IBinder token, int uid, List<LowPowerStandbyPortDescription> ports) { 216 mToken = token; 217 mUid = uid; 218 mPorts = ports; 219 } 220 linkToDeath()221 public boolean linkToDeath() { 222 try { 223 mToken.linkToDeath(this, 0); 224 return true; 225 } catch (RemoteException e) { 226 Slog.i(TAG, "StandbyPorts token already died"); 227 return false; 228 } 229 } 230 unlinkToDeath()231 public void unlinkToDeath() { 232 mToken.unlinkToDeath(this, 0); 233 } 234 getToken()235 public IBinder getToken() { 236 return mToken; 237 } 238 getUid()239 public int getUid() { 240 return mUid; 241 } 242 getPorts()243 public List<LowPowerStandbyPortDescription> getPorts() { 244 return mPorts; 245 } 246 247 @Override binderDied()248 public void binderDied() { 249 releaseStandbyPorts(mToken); 250 } 251 } 252 253 @GuardedBy("mLock") 254 private AlarmManager mAlarmManager; 255 @GuardedBy("mLock") 256 private PowerManager mPowerManager; 257 private ActivityManagerInternal mActivityManagerInternal; 258 @GuardedBy("mLock") 259 private boolean mSupportedConfig; 260 @GuardedBy("mLock") 261 private boolean mEnabledByDefaultConfig; 262 @GuardedBy("mLock") 263 private int mStandbyTimeoutConfig; 264 265 /** Whether Low Power Standby is enabled in Settings */ 266 @GuardedBy("mLock") 267 private boolean mIsEnabled; 268 269 /** 270 * Whether Low Power Standby is currently active (enforcing restrictions). 271 */ 272 @GuardedBy("mLock") 273 private boolean mIsActive; 274 275 /** Whether the device is currently interactive */ 276 @GuardedBy("mLock") 277 private boolean mIsInteractive; 278 279 /** The time the device was last interactive, in {@link SystemClock#elapsedRealtime()}. */ 280 @GuardedBy("mLock") 281 private long mLastInteractiveTimeElapsed; 282 283 /** 284 * Whether we are in device idle mode. 285 * During maintenance windows Low Power Standby is deactivated to allow 286 * apps to run maintenance tasks. 287 */ 288 @GuardedBy("mLock") 289 private boolean mIsDeviceIdle; 290 291 /** 292 * Whether the device has entered idle mode since becoming non-interactive. 293 * In the initial non-idle period after turning the screen off, Low Power Standby is already 294 * allowed to become active. Later non-idle periods are treated as maintenance windows, during 295 * which Low Power Standby is deactivated to allow apps to run maintenance tasks. 296 */ 297 @GuardedBy("mLock") 298 private boolean mIdleSinceNonInteractive; 299 300 /** Whether Low Power Standby restrictions should be active during doze maintenance mode. */ 301 @GuardedBy("mLock") 302 private boolean mActiveDuringMaintenance; 303 304 /** Force Low Power Standby to be active. */ 305 @GuardedBy("mLock") 306 private boolean mForceActive; 307 308 /** Current Low Power Standby policy. */ 309 @GuardedBy("mLock") 310 @Nullable 311 private LowPowerStandbyPolicy mPolicy; 312 313 @VisibleForTesting 314 static final LowPowerStandbyPolicy DEFAULT_POLICY = new LowPowerStandbyPolicy( 315 "DEFAULT_POLICY", 316 Collections.emptySet(), 317 PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION, 318 Collections.emptySet()); 319 320 /** Functional interface for providing time. */ 321 @VisibleForTesting 322 interface Clock { 323 /** Returns milliseconds since boot, including time spent in sleep. */ elapsedRealtime()324 long elapsedRealtime(); 325 } 326 LowPowerStandbyController(Context context, Looper looper)327 public LowPowerStandbyController(Context context, Looper looper) { 328 this(context, looper, SystemClock::elapsedRealtime, 329 new DeviceConfigWrapper(), () -> ActivityManager.getService(), 330 new File(Environment.getDataSystemDirectory(), "low_power_standby_policy.xml")); 331 } 332 333 @VisibleForTesting LowPowerStandbyController(Context context, Looper looper, Clock clock, DeviceConfigWrapper deviceConfig, Supplier<IActivityManager> activityManager, File policyFile)334 LowPowerStandbyController(Context context, Looper looper, Clock clock, 335 DeviceConfigWrapper deviceConfig, Supplier<IActivityManager> activityManager, 336 File policyFile) { 337 mContext = context; 338 mHandler = new LowPowerStandbyHandler(looper); 339 mClock = clock; 340 mSettingsObserver = new SettingsObserver(mHandler); 341 mDeviceConfig = deviceConfig; 342 mActivityManager = activityManager; 343 mPolicyFile = policyFile; 344 } 345 346 /** Call when system services are ready */ 347 @VisibleForTesting systemReady()348 public void systemReady() { 349 final Resources resources = mContext.getResources(); 350 synchronized (mLock) { 351 mSupportedConfig = resources.getBoolean( 352 com.android.internal.R.bool.config_lowPowerStandbySupported); 353 354 if (!mSupportedConfig) { 355 return; 356 } 357 358 mAlarmManager = mContext.getSystemService(AlarmManager.class); 359 mPowerManager = mContext.getSystemService(PowerManager.class); 360 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); 361 362 mStandbyTimeoutConfig = resources.getInteger( 363 R.integer.config_lowPowerStandbyNonInteractiveTimeout); 364 mEnabledByDefaultConfig = resources.getBoolean( 365 R.bool.config_lowPowerStandbyEnabledByDefault); 366 367 mIsInteractive = mPowerManager.isInteractive(); 368 369 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 370 Settings.Global.LOW_POWER_STANDBY_ENABLED), 371 false, mSettingsObserver, UserHandle.USER_ALL); 372 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 373 Settings.Global.LOW_POWER_STANDBY_ACTIVE_DURING_MAINTENANCE), 374 false, mSettingsObserver, UserHandle.USER_ALL); 375 376 mDeviceConfig.registerPropertyUpdateListener(mContext.getMainExecutor(), 377 properties -> onDeviceConfigFlagsChanged()); 378 mEnableCustomPolicy = mDeviceConfig.enableCustomPolicy(); 379 mEnableStandbyPorts = mDeviceConfig.enableStandbyPorts(); 380 381 if (mEnableCustomPolicy) { 382 mPolicy = loadPolicy(); 383 } else { 384 mPolicy = DEFAULT_POLICY; 385 } 386 initSettingsLocked(); 387 updateSettingsLocked(); 388 389 if (mIsEnabled) { 390 registerListeners(); 391 } 392 } 393 394 LocalServices.addService(LowPowerStandbyControllerInternal.class, mLocalService); 395 } 396 onDeviceConfigFlagsChanged()397 private void onDeviceConfigFlagsChanged() { 398 synchronized (mLock) { 399 boolean enableCustomPolicy = mDeviceConfig.enableCustomPolicy(); 400 if (mEnableCustomPolicy != enableCustomPolicy) { 401 enqueueNotifyPolicyChangedLocked(); 402 enqueueNotifyAllowlistChangedLocked(); 403 mEnableCustomPolicy = enableCustomPolicy; 404 } 405 406 mEnableStandbyPorts = mDeviceConfig.enableStandbyPorts(); 407 } 408 } 409 410 @GuardedBy("mLock") initSettingsLocked()411 private void initSettingsLocked() { 412 final ContentResolver resolver = mContext.getContentResolver(); 413 if (mSupportedConfig) { 414 final int enabledSetting = Settings.Global.getInt(resolver, 415 Settings.Global.LOW_POWER_STANDBY_ENABLED, /* def= */ -1); 416 417 // If the ENABLED setting hasn't been assigned yet, set it to its default value. 418 // This ensures reading the setting reflects the enabled state, without having to know 419 // the default value for this device. 420 if (enabledSetting == -1) { 421 Settings.Global.putInt(resolver, Settings.Global.LOW_POWER_STANDBY_ENABLED, 422 /* value= */ mEnabledByDefaultConfig ? 1 : 0); 423 } 424 } 425 } 426 427 @GuardedBy("mLock") updateSettingsLocked()428 private void updateSettingsLocked() { 429 final ContentResolver resolver = mContext.getContentResolver(); 430 mIsEnabled = mSupportedConfig && Settings.Global.getInt(resolver, 431 Settings.Global.LOW_POWER_STANDBY_ENABLED, 432 mEnabledByDefaultConfig ? 1 : 0) != 0; 433 mActiveDuringMaintenance = Settings.Global.getInt(resolver, 434 Settings.Global.LOW_POWER_STANDBY_ACTIVE_DURING_MAINTENANCE, 435 DEFAULT_ACTIVE_DURING_MAINTENANCE ? 1 : 0) != 0; 436 437 updateActiveLocked(); 438 } 439 440 @Nullable loadPolicy()441 private LowPowerStandbyPolicy loadPolicy() { 442 final AtomicFile file = getPolicyFile(); 443 if (!file.exists()) { 444 return null; 445 } 446 if (DEBUG) { 447 Slog.d(TAG, "Loading policy from " + file.getBaseFile()); 448 } 449 450 try (FileInputStream in = file.openRead()) { 451 String identifier = null; 452 Set<String> exemptPackages = new ArraySet<>(); 453 int allowedReasons = 0; 454 Set<String> allowedFeatures = new ArraySet<>(); 455 456 TypedXmlPullParser parser = Xml.resolvePullParser(in); 457 458 int type; 459 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { 460 if (type != XmlPullParser.START_TAG) { 461 continue; 462 } 463 final int depth = parser.getDepth(); 464 // Check the root tag 465 final String tag = parser.getName(); 466 if (depth == 1) { 467 if (!TAG_ROOT.equals(tag)) { 468 Slog.e(TAG, "Invalid root tag: " + tag); 469 return null; 470 } 471 continue; 472 } 473 // Assume depth == 2 474 switch (tag) { 475 case TAG_IDENTIFIER: 476 identifier = parser.getAttributeValue(null, ATTR_VALUE); 477 break; 478 case TAG_EXEMPT_PACKAGE: 479 exemptPackages.add(parser.getAttributeValue(null, ATTR_VALUE)); 480 break; 481 case TAG_ALLOWED_REASONS: 482 allowedReasons = parser.getAttributeInt(null, ATTR_VALUE); 483 break; 484 case TAG_ALLOWED_FEATURES: 485 allowedFeatures.add(parser.getAttributeValue(null, ATTR_VALUE)); 486 break; 487 default: 488 Slog.e(TAG, "Invalid tag: " + tag); 489 break; 490 } 491 } 492 493 final LowPowerStandbyPolicy policy = new LowPowerStandbyPolicy(identifier, 494 exemptPackages, allowedReasons, allowedFeatures); 495 if (DEBUG) { 496 Slog.d(TAG, "Loaded policy: " + policy); 497 } 498 return policy; 499 } catch (FileNotFoundException e) { 500 // Use the default 501 return null; 502 } catch (IOException | NullPointerException | IllegalArgumentException 503 | XmlPullParserException e) { 504 Slog.e(TAG, "Failed to read policy file " + file.getBaseFile(), e); 505 return null; 506 } 507 } 508 writeTagValue(TypedXmlSerializer out, String tag, String value)509 static void writeTagValue(TypedXmlSerializer out, String tag, String value) throws IOException { 510 if (TextUtils.isEmpty(value)) return; 511 512 out.startTag(null, tag); 513 out.attribute(null, ATTR_VALUE, value); 514 out.endTag(null, tag); 515 } 516 writeTagValue(TypedXmlSerializer out, String tag, int value)517 static void writeTagValue(TypedXmlSerializer out, String tag, int value) throws IOException { 518 out.startTag(null, tag); 519 out.attributeInt(null, ATTR_VALUE, value); 520 out.endTag(null, tag); 521 } 522 savePolicy(@ullable LowPowerStandbyPolicy policy)523 private void savePolicy(@Nullable LowPowerStandbyPolicy policy) { 524 final AtomicFile file = getPolicyFile(); 525 if (DEBUG) { 526 Slog.d(TAG, "Saving policy to " + file.getBaseFile()); 527 } 528 if (policy == null) { 529 file.delete(); 530 return; 531 } 532 533 FileOutputStream outs = null; 534 try { 535 file.getBaseFile().mkdirs(); 536 outs = file.startWrite(); 537 538 // Write to XML 539 TypedXmlSerializer out = Xml.resolveSerializer(outs); 540 out.startDocument(null, true); 541 out.startTag(null, TAG_ROOT); 542 543 // Body. 544 writeTagValue(out, TAG_IDENTIFIER, policy.getIdentifier()); 545 for (String exemptPackage : policy.getExemptPackages()) { 546 writeTagValue(out, TAG_EXEMPT_PACKAGE, exemptPackage); 547 } 548 writeTagValue(out, TAG_ALLOWED_REASONS, policy.getAllowedReasons()); 549 for (String allowedFeature : policy.getAllowedFeatures()) { 550 writeTagValue(out, TAG_ALLOWED_FEATURES, allowedFeature); 551 } 552 553 // Epilogue. 554 out.endTag(null, TAG_ROOT); 555 out.endDocument(); 556 557 // Close. 558 file.finishWrite(outs); 559 } catch (IOException e) { 560 Slog.e(TAG, "Failed to write policy to file " + file.getBaseFile(), e); 561 file.failWrite(outs); 562 } 563 } 564 enqueueSavePolicy(@ullable LowPowerStandbyPolicy policy)565 private void enqueueSavePolicy(@Nullable LowPowerStandbyPolicy policy) { 566 mHandler.post(() -> savePolicy(policy)); 567 } 568 getPolicyFile()569 private AtomicFile getPolicyFile() { 570 return new AtomicFile(mPolicyFile); 571 } 572 573 @GuardedBy("mLock") updateActiveLocked()574 private void updateActiveLocked() { 575 final long now = mClock.elapsedRealtime(); 576 final boolean standbyTimeoutExpired = 577 (now - mLastInteractiveTimeElapsed) >= mStandbyTimeoutConfig; 578 final boolean maintenanceMode = mIdleSinceNonInteractive && !mIsDeviceIdle; 579 final boolean newActive = 580 mForceActive || (mIsEnabled && !mIsInteractive && standbyTimeoutExpired 581 && (!maintenanceMode || mActiveDuringMaintenance)); 582 if (DEBUG) { 583 Slog.d(TAG, "updateActiveLocked: mIsEnabled=" + mIsEnabled + ", mIsInteractive=" 584 + mIsInteractive + ", standbyTimeoutExpired=" + standbyTimeoutExpired 585 + ", mIdleSinceNonInteractive=" + mIdleSinceNonInteractive + ", mIsDeviceIdle=" 586 + mIsDeviceIdle + ", mActiveDuringMaintenance=" + mActiveDuringMaintenance 587 + ", mForceActive=" + mForceActive + ", mIsActive=" + mIsActive + ", newActive=" 588 + newActive); 589 } 590 if (mIsActive != newActive) { 591 mIsActive = newActive; 592 if (DEBUG) { 593 Slog.d(TAG, "mIsActive changed, mIsActive=" + mIsActive); 594 } 595 enqueueNotifyActiveChangedLocked(); 596 } 597 } 598 onNonInteractive()599 private void onNonInteractive() { 600 if (DEBUG) { 601 Slog.d(TAG, "onNonInteractive"); 602 } 603 final long now = mClock.elapsedRealtime(); 604 synchronized (mLock) { 605 mIsInteractive = false; 606 mIsDeviceIdle = false; 607 mLastInteractiveTimeElapsed = now; 608 609 if (mStandbyTimeoutConfig > 0) { 610 scheduleStandbyTimeoutAlarmLocked(); 611 } 612 613 updateActiveLocked(); 614 } 615 } 616 onInteractive()617 private void onInteractive() { 618 if (DEBUG) { 619 Slog.d(TAG, "onInteractive"); 620 } 621 622 synchronized (mLock) { 623 cancelStandbyTimeoutAlarmLocked(); 624 mIsInteractive = true; 625 mIsDeviceIdle = false; 626 mIdleSinceNonInteractive = false; 627 updateActiveLocked(); 628 } 629 } 630 631 @GuardedBy("mLock") scheduleStandbyTimeoutAlarmLocked()632 private void scheduleStandbyTimeoutAlarmLocked() { 633 final long nextAlarmTime = SystemClock.elapsedRealtime() + mStandbyTimeoutConfig; 634 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 635 nextAlarmTime, "LowPowerStandbyController.StandbyTimeout", 636 mOnStandbyTimeoutExpired, mHandler); 637 } 638 639 @GuardedBy("mLock") cancelStandbyTimeoutAlarmLocked()640 private void cancelStandbyTimeoutAlarmLocked() { 641 mAlarmManager.cancel(mOnStandbyTimeoutExpired); 642 } 643 onDeviceIdleModeChanged()644 private void onDeviceIdleModeChanged() { 645 synchronized (mLock) { 646 mIsDeviceIdle = mPowerManager.isDeviceIdleMode(); 647 if (DEBUG) { 648 Slog.d(TAG, "onDeviceIdleModeChanged, mIsDeviceIdle=" + mIsDeviceIdle); 649 } 650 651 mIdleSinceNonInteractive = mIdleSinceNonInteractive || mIsDeviceIdle; 652 updateActiveLocked(); 653 } 654 } 655 656 @GuardedBy("mLock") onEnabledLocked()657 private void onEnabledLocked() { 658 if (DEBUG) { 659 Slog.d(TAG, "onEnabledLocked"); 660 } 661 662 if (mPowerManager.isInteractive()) { 663 onInteractive(); 664 } else { 665 onNonInteractive(); 666 } 667 668 registerListeners(); 669 } 670 671 @GuardedBy("mLock") onDisabledLocked()672 private void onDisabledLocked() { 673 if (DEBUG) { 674 Slog.d(TAG, "onDisabledLocked"); 675 } 676 677 cancelStandbyTimeoutAlarmLocked(); 678 unregisterListeners(); 679 updateActiveLocked(); 680 } 681 682 @VisibleForTesting onSettingsChanged()683 void onSettingsChanged() { 684 if (DEBUG) { 685 Slog.d(TAG, "onSettingsChanged"); 686 } 687 synchronized (mLock) { 688 final boolean oldEnabled = mIsEnabled; 689 updateSettingsLocked(); 690 691 if (mIsEnabled != oldEnabled) { 692 if (mIsEnabled) { 693 onEnabledLocked(); 694 } else { 695 onDisabledLocked(); 696 } 697 698 notifyEnabledChangedLocked(); 699 } 700 } 701 } 702 registerListeners()703 private void registerListeners() { 704 IntentFilter intentFilter = new IntentFilter(); 705 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 706 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 707 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 708 709 mContext.registerReceiver(mBroadcastReceiver, intentFilter); 710 711 IntentFilter packageFilter = new IntentFilter(); 712 packageFilter.addDataScheme(IntentFilter.SCHEME_PACKAGE); 713 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 714 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 715 packageFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 716 mContext.registerReceiver(mPackageBroadcastReceiver, packageFilter); 717 718 final IntentFilter userFilter = new IntentFilter(); 719 userFilter.addAction(Intent.ACTION_USER_ADDED); 720 userFilter.addAction(Intent.ACTION_USER_REMOVED); 721 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); 722 723 PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class); 724 pai.registerTempAllowlistChangeListener(mTempAllowlistChangeListener); 725 726 mPhoneCallServiceTracker.register(); 727 } 728 unregisterListeners()729 private void unregisterListeners() { 730 mContext.unregisterReceiver(mBroadcastReceiver); 731 mContext.unregisterReceiver(mPackageBroadcastReceiver); 732 mContext.unregisterReceiver(mUserReceiver); 733 734 PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class); 735 pai.unregisterTempAllowlistChangeListener(mTempAllowlistChangeListener); 736 } 737 738 @GuardedBy("mLock") notifyEnabledChangedLocked()739 private void notifyEnabledChangedLocked() { 740 if (DEBUG) { 741 Slog.d(TAG, "notifyEnabledChangedLocked, mIsEnabled=" + mIsEnabled); 742 } 743 744 final Intent intent = new Intent(PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED); 745 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); 746 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 747 } 748 749 @GuardedBy("mLock") enqueueNotifyPolicyChangedLocked()750 private void enqueueNotifyPolicyChangedLocked() { 751 final long now = mClock.elapsedRealtime(); 752 final Message msg = mHandler.obtainMessage(MSG_NOTIFY_POLICY_CHANGED, getPolicy()); 753 mHandler.sendMessageAtTime(msg, now); 754 } 755 notifyPolicyChanged(LowPowerStandbyPolicy policy)756 private void notifyPolicyChanged(LowPowerStandbyPolicy policy) { 757 if (DEBUG) { 758 Slog.d(TAG, "notifyPolicyChanged, policy=" + policy); 759 } 760 761 final Intent intent = new Intent( 762 PowerManager.ACTION_LOW_POWER_STANDBY_POLICY_CHANGED); 763 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); 764 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 765 } 766 onStandbyTimeoutExpired()767 private void onStandbyTimeoutExpired() { 768 if (DEBUG) { 769 Slog.d(TAG, "onStandbyTimeoutExpired"); 770 } 771 synchronized (mLock) { 772 updateActiveLocked(); 773 } 774 } 775 776 @GuardedBy("mLock") enqueueNotifyActiveChangedLocked()777 private void enqueueNotifyActiveChangedLocked() { 778 final long now = mClock.elapsedRealtime(); 779 final Message msg = mHandler.obtainMessage(MSG_NOTIFY_ACTIVE_CHANGED, mIsActive); 780 mHandler.sendMessageAtTime(msg, now); 781 } 782 783 /** Notify other system components about the updated Low Power Standby active state */ notifyActiveChanged(boolean active)784 private void notifyActiveChanged(boolean active) { 785 if (DEBUG) { 786 Slog.d(TAG, "notifyActiveChanged, active=" + active); 787 } 788 final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class); 789 final NetworkPolicyManagerInternal npmi = LocalServices.getService( 790 NetworkPolicyManagerInternal.class); 791 792 pmi.setLowPowerStandbyActive(active); 793 npmi.setLowPowerStandbyActive(active); 794 } 795 796 @VisibleForTesting isActive()797 boolean isActive() { 798 synchronized (mLock) { 799 return mIsActive; 800 } 801 } 802 isSupported()803 boolean isSupported() { 804 synchronized (mLock) { 805 return mSupportedConfig; 806 } 807 } 808 isEnabled()809 boolean isEnabled() { 810 synchronized (mLock) { 811 return mSupportedConfig && mIsEnabled; 812 } 813 } 814 setEnabled(boolean enabled)815 void setEnabled(boolean enabled) { 816 synchronized (mLock) { 817 if (!mSupportedConfig) { 818 Slog.w(TAG, "Low Power Standby cannot be enabled " 819 + "because it is not supported on this device"); 820 return; 821 } 822 823 Settings.Global.putInt(mContext.getContentResolver(), 824 Settings.Global.LOW_POWER_STANDBY_ENABLED, enabled ? 1 : 0); 825 onSettingsChanged(); 826 } 827 } 828 829 /** Set whether Low Power Standby should be active during doze maintenance mode. */ 830 @VisibleForTesting setActiveDuringMaintenance(boolean activeDuringMaintenance)831 public void setActiveDuringMaintenance(boolean activeDuringMaintenance) { 832 synchronized (mLock) { 833 if (!mSupportedConfig) { 834 Slog.w(TAG, "Low Power Standby settings cannot be changed " 835 + "because it is not supported on this device"); 836 return; 837 } 838 839 Settings.Global.putInt(mContext.getContentResolver(), 840 Settings.Global.LOW_POWER_STANDBY_ACTIVE_DURING_MAINTENANCE, 841 activeDuringMaintenance ? 1 : 0); 842 onSettingsChanged(); 843 } 844 } 845 forceActive(boolean active)846 void forceActive(boolean active) { 847 synchronized (mLock) { 848 mForceActive = active; 849 updateActiveLocked(); 850 } 851 } 852 setPolicy(@ullable LowPowerStandbyPolicy policy)853 void setPolicy(@Nullable LowPowerStandbyPolicy policy) { 854 synchronized (mLock) { 855 if (!mSupportedConfig) { 856 Slog.w(TAG, "Low Power Standby policy cannot be changed " 857 + "because it is not supported on this device"); 858 return; 859 } 860 861 if (!mEnableCustomPolicy) { 862 Slog.d(TAG, "Custom policies are not enabled."); 863 return; 864 } 865 866 if (DEBUG) { 867 Slog.d(TAG, "setPolicy: policy=" + policy); 868 } 869 if (Objects.equals(mPolicy, policy)) { 870 return; 871 } 872 873 boolean allowlistChanged = policyChangeAffectsAllowlistLocked(mPolicy, policy); 874 mPolicy = policy; 875 enqueueSavePolicy(mPolicy); 876 if (allowlistChanged) { 877 enqueueNotifyAllowlistChangedLocked(); 878 } 879 enqueueNotifyPolicyChangedLocked(); 880 } 881 } 882 883 @Nullable getPolicy()884 LowPowerStandbyPolicy getPolicy() { 885 synchronized (mLock) { 886 if (!mSupportedConfig) { 887 return null; 888 } else if (mEnableCustomPolicy) { 889 return policyOrDefault(mPolicy); 890 } else { 891 return DEFAULT_POLICY; 892 } 893 } 894 } 895 896 @NonNull policyOrDefault(@ullable LowPowerStandbyPolicy policy)897 private LowPowerStandbyPolicy policyOrDefault(@Nullable LowPowerStandbyPolicy policy) { 898 if (policy == null) { 899 return DEFAULT_POLICY; 900 } 901 return policy; 902 } 903 isPackageExempt(int uid)904 boolean isPackageExempt(int uid) { 905 synchronized (mLock) { 906 if (!isEnabled()) { 907 return true; 908 } 909 910 return getExemptPackageAppIdsLocked().contains(UserHandle.getAppId(uid)); 911 } 912 } 913 isAllowed(@owPowerStandbyAllowedReason int reason)914 boolean isAllowed(@LowPowerStandbyAllowedReason int reason) { 915 synchronized (mLock) { 916 if (!isEnabled()) { 917 return true; 918 } 919 920 return (getPolicy().getAllowedReasons() & reason) != 0; 921 } 922 } 923 isAllowed(String feature)924 boolean isAllowed(String feature) { 925 synchronized (mLock) { 926 if (!mSupportedConfig) { 927 return true; 928 } 929 930 return !isEnabled() || getPolicy().getAllowedFeatures().contains(feature); 931 } 932 } 933 findIndexOfStandbyPorts(@onNull IBinder token)934 private int findIndexOfStandbyPorts(@NonNull IBinder token) { 935 for (int i = 0; i < mStandbyPortLocks.size(); i++) { 936 if (mStandbyPortLocks.get(i).getToken() == token) { 937 return i; 938 } 939 } 940 return -1; 941 } 942 acquireStandbyPorts(@onNull IBinder token, int uid, @NonNull List<LowPowerStandbyPortDescription> ports)943 void acquireStandbyPorts(@NonNull IBinder token, int uid, 944 @NonNull List<LowPowerStandbyPortDescription> ports) { 945 validatePorts(ports); 946 947 StandbyPortsLock standbyPortsLock = new StandbyPortsLock(token, uid, ports); 948 synchronized (mLock) { 949 if (findIndexOfStandbyPorts(token) != -1) { 950 return; 951 } 952 953 if (standbyPortsLock.linkToDeath()) { 954 mStandbyPortLocks.add(standbyPortsLock); 955 if (mEnableStandbyPorts && isEnabled() && isPackageExempt(uid)) { 956 enqueueNotifyStandbyPortsChangedLocked(); 957 } 958 } 959 } 960 } 961 validatePorts(@onNull List<LowPowerStandbyPortDescription> ports)962 void validatePorts(@NonNull List<LowPowerStandbyPortDescription> ports) { 963 for (LowPowerStandbyPortDescription portDescription : ports) { 964 int port = portDescription.getPortNumber(); 965 if (port < 0 || port > 0xFFFF) { 966 throw new IllegalArgumentException("port out of range:" + port); 967 } 968 } 969 } 970 releaseStandbyPorts(@onNull IBinder token)971 void releaseStandbyPorts(@NonNull IBinder token) { 972 synchronized (mLock) { 973 int index = findIndexOfStandbyPorts(token); 974 if (index == -1) { 975 return; 976 } 977 978 StandbyPortsLock standbyPortsLock = mStandbyPortLocks.remove(index); 979 standbyPortsLock.unlinkToDeath(); 980 if (mEnableStandbyPorts && isEnabled() && isPackageExempt(standbyPortsLock.getUid())) { 981 enqueueNotifyStandbyPortsChangedLocked(); 982 } 983 } 984 } 985 986 @NonNull getActiveStandbyPorts()987 List<LowPowerStandbyPortDescription> getActiveStandbyPorts() { 988 List<LowPowerStandbyPortDescription> activeStandbyPorts = new ArrayList<>(); 989 synchronized (mLock) { 990 if (!isEnabled() || !mEnableStandbyPorts) { 991 return activeStandbyPorts; 992 } 993 994 List<Integer> exemptPackageAppIds = getExemptPackageAppIdsLocked(); 995 for (StandbyPortsLock standbyPortsLock : mStandbyPortLocks) { 996 int standbyPortsAppid = UserHandle.getAppId(standbyPortsLock.getUid()); 997 if (exemptPackageAppIds.contains(standbyPortsAppid)) { 998 activeStandbyPorts.addAll(standbyPortsLock.getPorts()); 999 } 1000 } 1001 1002 return activeStandbyPorts; 1003 } 1004 } 1005 policyChangeAffectsAllowlistLocked( @ullable LowPowerStandbyPolicy oldPolicy, @Nullable LowPowerStandbyPolicy newPolicy)1006 private boolean policyChangeAffectsAllowlistLocked( 1007 @Nullable LowPowerStandbyPolicy oldPolicy, @Nullable LowPowerStandbyPolicy newPolicy) { 1008 final LowPowerStandbyPolicy policyA = policyOrDefault(oldPolicy); 1009 final LowPowerStandbyPolicy policyB = policyOrDefault(newPolicy); 1010 int allowedReasonsInUse = 0; 1011 for (int i = 0; i < mUidAllowedReasons.size(); i++) { 1012 allowedReasonsInUse |= mUidAllowedReasons.valueAt(i); 1013 } 1014 1015 int policyAllowedReasonsChanged = policyA.getAllowedReasons() ^ policyB.getAllowedReasons(); 1016 1017 boolean exemptPackagesChanged = !policyA.getExemptPackages().equals( 1018 policyB.getExemptPackages()); 1019 1020 return (policyAllowedReasonsChanged & allowedReasonsInUse) != 0 || exemptPackagesChanged; 1021 } 1022 dump(PrintWriter pw)1023 void dump(PrintWriter pw) { 1024 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); 1025 1026 ipw.println(); 1027 ipw.println("Low Power Standby Controller:"); 1028 ipw.increaseIndent(); 1029 synchronized (mLock) { 1030 ipw.print("mIsActive="); 1031 ipw.println(mIsActive); 1032 ipw.print("mIsEnabled="); 1033 ipw.println(mIsEnabled); 1034 ipw.print("mSupportedConfig="); 1035 ipw.println(mSupportedConfig); 1036 ipw.print("mEnabledByDefaultConfig="); 1037 ipw.println(mEnabledByDefaultConfig); 1038 ipw.print("mStandbyTimeoutConfig="); 1039 ipw.println(mStandbyTimeoutConfig); 1040 ipw.print("mEnableCustomPolicy="); 1041 ipw.println(mEnableCustomPolicy); 1042 1043 if (mIsActive || mIsEnabled) { 1044 ipw.print("mIsInteractive="); 1045 ipw.println(mIsInteractive); 1046 ipw.print("mLastInteractiveTime="); 1047 ipw.println(mLastInteractiveTimeElapsed); 1048 ipw.print("mIdleSinceNonInteractive="); 1049 ipw.println(mIdleSinceNonInteractive); 1050 ipw.print("mIsDeviceIdle="); 1051 ipw.println(mIsDeviceIdle); 1052 } 1053 1054 final int[] allowlistUids = getAllowlistUidsLocked(); 1055 ipw.print("Allowed UIDs="); 1056 ipw.println(Arrays.toString(allowlistUids)); 1057 1058 final LowPowerStandbyPolicy policy = getPolicy(); 1059 if (policy != null) { 1060 ipw.println(); 1061 ipw.println("mPolicy:"); 1062 ipw.increaseIndent(); 1063 ipw.print("mIdentifier="); 1064 ipw.println(policy.getIdentifier()); 1065 ipw.print("mExemptPackages="); 1066 ipw.println(String.join(",", policy.getExemptPackages())); 1067 ipw.print("mAllowedReasons="); 1068 ipw.println(lowPowerStandbyAllowedReasonsToString(policy.getAllowedReasons())); 1069 ipw.print("mAllowedFeatures="); 1070 ipw.println(String.join(",", policy.getAllowedFeatures())); 1071 ipw.decreaseIndent(); 1072 } 1073 1074 ipw.println(); 1075 ipw.println("UID allowed reasons:"); 1076 ipw.increaseIndent(); 1077 for (int i = 0; i < mUidAllowedReasons.size(); i++) { 1078 if (mUidAllowedReasons.valueAt(i) > 0) { 1079 ipw.print(mUidAllowedReasons.keyAt(i)); 1080 ipw.print(": "); 1081 ipw.println( 1082 lowPowerStandbyAllowedReasonsToString(mUidAllowedReasons.valueAt(i))); 1083 } 1084 } 1085 ipw.decreaseIndent(); 1086 1087 final List<LowPowerStandbyPortDescription> activeStandbyPorts = getActiveStandbyPorts(); 1088 if (!activeStandbyPorts.isEmpty()) { 1089 ipw.println(); 1090 ipw.println("Active standby ports locks:"); 1091 ipw.increaseIndent(); 1092 for (LowPowerStandbyPortDescription portDescription : activeStandbyPorts) { 1093 ipw.print(portDescription.toString()); 1094 } 1095 ipw.decreaseIndent(); 1096 } 1097 } 1098 ipw.decreaseIndent(); 1099 } 1100 dumpProto(ProtoOutputStream proto, long tag)1101 void dumpProto(ProtoOutputStream proto, long tag) { 1102 synchronized (mLock) { 1103 final long token = proto.start(tag); 1104 proto.write(LowPowerStandbyControllerDumpProto.IS_ACTIVE, mIsActive); 1105 proto.write(LowPowerStandbyControllerDumpProto.IS_ENABLED, mIsEnabled); 1106 proto.write(LowPowerStandbyControllerDumpProto.IS_SUPPORTED_CONFIG, mSupportedConfig); 1107 proto.write(LowPowerStandbyControllerDumpProto.IS_ENABLED_BY_DEFAULT_CONFIG, 1108 mEnabledByDefaultConfig); 1109 proto.write(LowPowerStandbyControllerDumpProto.IS_INTERACTIVE, mIsInteractive); 1110 proto.write(LowPowerStandbyControllerDumpProto.LAST_INTERACTIVE_TIME, 1111 mLastInteractiveTimeElapsed); 1112 proto.write(LowPowerStandbyControllerDumpProto.STANDBY_TIMEOUT_CONFIG, 1113 mStandbyTimeoutConfig); 1114 proto.write(LowPowerStandbyControllerDumpProto.IDLE_SINCE_NON_INTERACTIVE, 1115 mIdleSinceNonInteractive); 1116 proto.write(LowPowerStandbyControllerDumpProto.IS_DEVICE_IDLE, mIsDeviceIdle); 1117 1118 final int[] allowlistUids = getAllowlistUidsLocked(); 1119 for (int appId : allowlistUids) { 1120 proto.write(LowPowerStandbyControllerDumpProto.ALLOWLIST, appId); 1121 } 1122 1123 final LowPowerStandbyPolicy policy = getPolicy(); 1124 if (policy != null) { 1125 long policyToken = proto.start(LowPowerStandbyControllerDumpProto.POLICY); 1126 proto.write(LowPowerStandbyPolicyProto.IDENTIFIER, policy.getIdentifier()); 1127 for (String exemptPackage : policy.getExemptPackages()) { 1128 proto.write(LowPowerStandbyPolicyProto.EXEMPT_PACKAGES, exemptPackage); 1129 } 1130 proto.write(LowPowerStandbyPolicyProto.ALLOWED_REASONS, policy.getAllowedReasons()); 1131 for (String feature : policy.getAllowedFeatures()) { 1132 proto.write(LowPowerStandbyPolicyProto.ALLOWED_FEATURES, feature); 1133 } 1134 proto.end(policyToken); 1135 } 1136 proto.end(token); 1137 } 1138 } 1139 1140 private class LowPowerStandbyHandler extends Handler { LowPowerStandbyHandler(Looper looper)1141 LowPowerStandbyHandler(Looper looper) { 1142 super(looper); 1143 } 1144 1145 @Override handleMessage(Message msg)1146 public void handleMessage(Message msg) { 1147 switch (msg.what) { 1148 case MSG_STANDBY_TIMEOUT: 1149 onStandbyTimeoutExpired(); 1150 break; 1151 case MSG_NOTIFY_ACTIVE_CHANGED: 1152 boolean active = (boolean) msg.obj; 1153 notifyActiveChanged(active); 1154 break; 1155 case MSG_NOTIFY_ALLOWLIST_CHANGED: 1156 final int[] allowlistUids = (int[]) msg.obj; 1157 notifyAllowlistChanged(allowlistUids); 1158 break; 1159 case MSG_NOTIFY_POLICY_CHANGED: 1160 notifyPolicyChanged((LowPowerStandbyPolicy) msg.obj); 1161 break; 1162 case MSG_FOREGROUND_SERVICE_STATE_CHANGED: 1163 final int uid = msg.arg1; 1164 mPhoneCallServiceTracker.foregroundServiceStateChanged(uid); 1165 break; 1166 case MSG_NOTIFY_STANDBY_PORTS_CHANGED: 1167 notifyStandbyPortsChanged(); 1168 break; 1169 } 1170 } 1171 } 1172 1173 @GuardedBy("mLock") hasAllowedReasonLocked(int uid, @LowPowerStandbyAllowedReason int allowedReason)1174 private boolean hasAllowedReasonLocked(int uid, 1175 @LowPowerStandbyAllowedReason int allowedReason) { 1176 int allowedReasons = mUidAllowedReasons.get(uid); 1177 return (allowedReasons & allowedReason) != 0; 1178 } 1179 1180 @GuardedBy("mLock") addAllowedReasonLocked(int uid, @LowPowerStandbyAllowedReason int allowedReason)1181 private boolean addAllowedReasonLocked(int uid, 1182 @LowPowerStandbyAllowedReason int allowedReason) { 1183 int allowedReasons = mUidAllowedReasons.get(uid); 1184 final int newAllowReasons = allowedReasons | allowedReason; 1185 mUidAllowedReasons.put(uid, newAllowReasons); 1186 return allowedReasons != newAllowReasons; 1187 } 1188 1189 @GuardedBy("mLock") removeAllowedReasonLocked(int uid, @LowPowerStandbyAllowedReason int allowedReason)1190 private boolean removeAllowedReasonLocked(int uid, 1191 @LowPowerStandbyAllowedReason int allowedReason) { 1192 int allowedReasons = mUidAllowedReasons.get(uid); 1193 if (allowedReasons == 0) { 1194 return false; 1195 } 1196 1197 final int newAllowedReasons = allowedReasons & ~allowedReason; 1198 if (newAllowedReasons == 0) { 1199 mUidAllowedReasons.removeAt(mUidAllowedReasons.indexOfKey(uid)); 1200 } else { 1201 mUidAllowedReasons.put(uid, newAllowedReasons); 1202 } 1203 return allowedReasons != newAllowedReasons; 1204 } 1205 addToAllowlistInternal(int uid, @LowPowerStandbyAllowedReason int allowedReason)1206 private void addToAllowlistInternal(int uid, @LowPowerStandbyAllowedReason int allowedReason) { 1207 if (DEBUG) { 1208 Slog.i(TAG, 1209 "Adding to allowlist: uid=" + uid + ", allowedReason=" + allowedReason); 1210 } 1211 synchronized (mLock) { 1212 if (!mSupportedConfig) { 1213 return; 1214 } 1215 if (allowedReason != 0 && !hasAllowedReasonLocked(uid, allowedReason)) { 1216 addAllowedReasonLocked(uid, allowedReason); 1217 if ((getPolicy().getAllowedReasons() & allowedReason) != 0) { 1218 enqueueNotifyAllowlistChangedLocked(); 1219 } 1220 } 1221 } 1222 } 1223 removeFromAllowlistInternal(int uid, @LowPowerStandbyAllowedReason int allowedReason)1224 private void removeFromAllowlistInternal(int uid, 1225 @LowPowerStandbyAllowedReason int allowedReason) { 1226 if (DEBUG) { 1227 Slog.i(TAG, "Removing from allowlist: uid=" + uid + ", allowedReason=" + allowedReason); 1228 } 1229 synchronized (mLock) { 1230 if (!mSupportedConfig) { 1231 return; 1232 } 1233 if (allowedReason != 0 && hasAllowedReasonLocked(uid, allowedReason)) { 1234 removeAllowedReasonLocked(uid, allowedReason); 1235 if ((getPolicy().getAllowedReasons() & allowedReason) != 0) { 1236 enqueueNotifyAllowlistChangedLocked(); 1237 } 1238 } 1239 } 1240 } 1241 1242 @GuardedBy("mLock") 1243 @NonNull getExemptPackageAppIdsLocked()1244 private List<Integer> getExemptPackageAppIdsLocked() { 1245 final PackageManager packageManager = mContext.getPackageManager(); 1246 final LowPowerStandbyPolicy policy = getPolicy(); 1247 final List<Integer> appIds = new ArrayList<>(); 1248 if (policy == null) { 1249 return appIds; 1250 } 1251 1252 for (String packageName : policy.getExemptPackages()) { 1253 try { 1254 int packageUid = packageManager.getPackageUid(packageName, 1255 PackageManager.PackageInfoFlags.of(0)); 1256 int appId = UserHandle.getAppId(packageUid); 1257 appIds.add(appId); 1258 } catch (PackageManager.NameNotFoundException e) { 1259 if (DEBUG) { 1260 Slog.d(TAG, "Package UID cannot be resolved: packageName=" + packageName); 1261 } 1262 } 1263 } 1264 1265 return appIds; 1266 } 1267 1268 @GuardedBy("mLock") getAllowlistUidsLocked()1269 private int[] getAllowlistUidsLocked() { 1270 final UserManager userManager = mContext.getSystemService(UserManager.class); 1271 final List<UserHandle> userHandles = userManager.getUserHandles(true); 1272 final ArraySet<Integer> uids = new ArraySet<>(mUidAllowedReasons.size()); 1273 final LowPowerStandbyPolicy policy = getPolicy(); 1274 if (policy == null) { 1275 return new int[0]; 1276 } 1277 1278 final int policyAllowedReasons = policy.getAllowedReasons(); 1279 for (int i = 0; i < mUidAllowedReasons.size(); i++) { 1280 Integer uid = mUidAllowedReasons.keyAt(i); 1281 if ((mUidAllowedReasons.valueAt(i) & policyAllowedReasons) != 0) { 1282 uids.add(uid); 1283 } 1284 } 1285 1286 for (int appId : getExemptPackageAppIdsLocked()) { 1287 for (int uid : uidsForAppId(appId, userHandles)) { 1288 uids.add(uid); 1289 } 1290 } 1291 1292 int[] allowlistUids = new int[uids.size()]; 1293 for (int i = 0; i < uids.size(); i++) { 1294 allowlistUids[i] = uids.valueAt(i); 1295 } 1296 Arrays.sort(allowlistUids); 1297 return allowlistUids; 1298 } 1299 uidsForAppId(int appUid, List<UserHandle> userHandles)1300 private int[] uidsForAppId(int appUid, List<UserHandle> userHandles) { 1301 final int appId = UserHandle.getAppId(appUid); 1302 final int[] uids = new int[userHandles.size()]; 1303 for (int i = 0; i < userHandles.size(); i++) { 1304 uids[i] = userHandles.get(i).getUid(appId); 1305 } 1306 return uids; 1307 } 1308 1309 @GuardedBy("mLock") enqueueNotifyAllowlistChangedLocked()1310 private void enqueueNotifyAllowlistChangedLocked() { 1311 final long now = mClock.elapsedRealtime(); 1312 final int[] allowlistUids = getAllowlistUidsLocked(); 1313 1314 if (DEBUG) { 1315 Slog.d(TAG, "enqueueNotifyAllowlistChangedLocked: allowlistUids=" + Arrays.toString( 1316 allowlistUids)); 1317 } 1318 1319 final Message msg = mHandler.obtainMessage(MSG_NOTIFY_ALLOWLIST_CHANGED, allowlistUids); 1320 mHandler.sendMessageAtTime(msg, now); 1321 } 1322 notifyAllowlistChanged(int[] allowlistUids)1323 private void notifyAllowlistChanged(int[] allowlistUids) { 1324 if (DEBUG) { 1325 Slog.d(TAG, "notifyAllowlistChanged: " + Arrays.toString(allowlistUids)); 1326 } 1327 1328 final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class); 1329 final NetworkPolicyManagerInternal npmi = LocalServices.getService( 1330 NetworkPolicyManagerInternal.class); 1331 pmi.setLowPowerStandbyAllowlist(allowlistUids); 1332 npmi.setLowPowerStandbyAllowlist(allowlistUids); 1333 } 1334 1335 @GuardedBy("mLock") enqueueNotifyStandbyPortsChangedLocked()1336 private void enqueueNotifyStandbyPortsChangedLocked() { 1337 final long now = mClock.elapsedRealtime(); 1338 1339 if (DEBUG) { 1340 Slog.d(TAG, "enqueueNotifyStandbyPortsChangedLocked"); 1341 } 1342 1343 final Message msg = mHandler.obtainMessage(MSG_NOTIFY_STANDBY_PORTS_CHANGED); 1344 mHandler.sendMessageAtTime(msg, now); 1345 } 1346 notifyStandbyPortsChanged()1347 private void notifyStandbyPortsChanged() { 1348 if (DEBUG) { 1349 Slog.d(TAG, "notifyStandbyPortsChanged"); 1350 } 1351 1352 final Intent intent = new Intent(PowerManager.ACTION_LOW_POWER_STANDBY_PORTS_CHANGED); 1353 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); 1354 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 1355 Manifest.permission.MANAGE_LOW_POWER_STANDBY); 1356 } 1357 1358 /** 1359 * Class that is used to read device config for low power standby configuration. 1360 */ 1361 @VisibleForTesting 1362 public static class DeviceConfigWrapper { 1363 public static final String NAMESPACE = "low_power_standby"; 1364 public static final String FEATURE_FLAG_ENABLE_POLICY = "enable_policy"; 1365 public static final String FEATURE_FLAG_ENABLE_STANDBY_PORTS = "enable_standby_ports"; 1366 1367 /** 1368 * Returns true if custom policies are enabled. 1369 * Otherwise, returns false, and the default policy will be used. 1370 */ enableCustomPolicy()1371 public boolean enableCustomPolicy() { 1372 return DeviceConfig.getBoolean(NAMESPACE, FEATURE_FLAG_ENABLE_POLICY, false); 1373 } 1374 1375 /** 1376 * Returns true if standby ports are enabled. 1377 * Otherwise, returns false, and {@link #getActiveStandbyPorts()} will always be empty. 1378 */ enableStandbyPorts()1379 public boolean enableStandbyPorts() { 1380 return DeviceConfig.getBoolean(NAMESPACE, FEATURE_FLAG_ENABLE_STANDBY_PORTS, false); 1381 } 1382 1383 /** 1384 * Registers a DeviceConfig update listener. 1385 */ registerPropertyUpdateListener( @onNull Executor executor, @NonNull DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener)1386 public void registerPropertyUpdateListener( 1387 @NonNull Executor executor, 1388 @NonNull DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener) { 1389 DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, executor, 1390 onPropertiesChangedListener); 1391 } 1392 } 1393 1394 private final class LocalService extends LowPowerStandbyControllerInternal { 1395 @Override addToAllowlist(int uid, @LowPowerStandbyAllowedReason int allowedReason)1396 public void addToAllowlist(int uid, @LowPowerStandbyAllowedReason int allowedReason) { 1397 addToAllowlistInternal(uid, allowedReason); 1398 } 1399 1400 @Override removeFromAllowlist(int uid, @LowPowerStandbyAllowedReason int allowedReason)1401 public void removeFromAllowlist(int uid, @LowPowerStandbyAllowedReason int allowedReason) { 1402 removeFromAllowlistInternal(uid, allowedReason); 1403 } 1404 } 1405 1406 private final class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler)1407 SettingsObserver(Handler handler) { 1408 super(handler); 1409 } 1410 1411 @Override onChange(boolean selfChange, Uri uri)1412 public void onChange(boolean selfChange, Uri uri) { 1413 onSettingsChanged(); 1414 } 1415 } 1416 1417 final class TempAllowlistChangeListener implements 1418 PowerAllowlistInternal.TempAllowlistChangeListener { 1419 @Override onAppAdded(int uid)1420 public void onAppAdded(int uid) { 1421 addToAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST); 1422 } 1423 1424 @Override onAppRemoved(int uid)1425 public void onAppRemoved(int uid) { 1426 removeFromAllowlistInternal(uid, 1427 LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST); 1428 } 1429 } 1430 1431 final class PhoneCallServiceTracker extends IForegroundServiceObserver.Stub { 1432 private boolean mRegistered = false; 1433 private final SparseBooleanArray mUidsWithPhoneCallService = new SparseBooleanArray(); 1434 register()1435 public void register() { 1436 if (mRegistered) { 1437 return; 1438 } 1439 try { 1440 mActivityManager.get().registerForegroundServiceObserver(this); 1441 mRegistered = true; 1442 } catch (RemoteException e) { 1443 // call within system server 1444 } 1445 } 1446 1447 @Override onForegroundStateChanged(IBinder serviceToken, String packageName, int userId, boolean isForeground)1448 public void onForegroundStateChanged(IBinder serviceToken, String packageName, 1449 int userId, boolean isForeground) { 1450 try { 1451 final long now = mClock.elapsedRealtime(); 1452 final int uid = mContext.getPackageManager() 1453 .getPackageUidAsUser(packageName, userId); 1454 final Message message = 1455 mHandler.obtainMessage(MSG_FOREGROUND_SERVICE_STATE_CHANGED, uid, 0); 1456 mHandler.sendMessageAtTime(message, now); 1457 } catch (PackageManager.NameNotFoundException e) { 1458 if (DEBUG) { 1459 Slog.d(TAG, "onForegroundStateChanged: Unknown package: " + packageName 1460 + ", userId=" + userId); 1461 } 1462 } 1463 } 1464 foregroundServiceStateChanged(int uid)1465 public void foregroundServiceStateChanged(int uid) { 1466 if (DEBUG) { 1467 Slog.d(TAG, "foregroundServiceStateChanged: uid=" + uid); 1468 } 1469 1470 final boolean hadPhoneCallService = mUidsWithPhoneCallService.get(uid); 1471 final boolean hasPhoneCallService = 1472 mActivityManagerInternal.hasRunningForegroundService(uid, 1473 ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL); 1474 1475 if (DEBUG) { 1476 Slog.d(TAG, "uid=" + uid + ", hasPhoneCallService=" + hasPhoneCallService 1477 + ", hadPhoneCallService=" + hadPhoneCallService); 1478 } 1479 1480 if (hasPhoneCallService == hadPhoneCallService) { 1481 return; 1482 } 1483 1484 if (hasPhoneCallService) { 1485 mUidsWithPhoneCallService.append(uid, true); 1486 uidStartedPhoneCallService(uid); 1487 } else { 1488 mUidsWithPhoneCallService.delete(uid); 1489 uidStoppedPhoneCallService(uid); 1490 } 1491 } 1492 uidStartedPhoneCallService(int uid)1493 private void uidStartedPhoneCallService(int uid) { 1494 if (DEBUG) { 1495 Slog.d(TAG, "FGS of type phoneCall started: uid=" + uid); 1496 } 1497 addToAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL); 1498 } 1499 uidStoppedPhoneCallService(int uid)1500 private void uidStoppedPhoneCallService(int uid) { 1501 if (DEBUG) { 1502 Slog.d(TAG, "FGSs of type phoneCall stopped: uid=" + uid); 1503 } 1504 removeFromAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_ONGOING_CALL); 1505 } 1506 } 1507 } 1508