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