1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server; 17 18 import android.annotation.NonNull; 19 import android.app.ActivityManager; 20 import android.app.ActivityManagerInternal; 21 import android.app.ActivityManagerInternal.AppBackgroundRestrictionListener; 22 import android.app.AppOpsManager; 23 import android.app.AppOpsManager.PackageOps; 24 import android.app.IActivityManager; 25 import android.app.IUidObserver; 26 import android.app.usage.UsageStatsManager; 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.IntentFilter; 31 import android.database.ContentObserver; 32 import android.net.Uri; 33 import android.os.BatteryManager; 34 import android.os.Handler; 35 import android.os.Looper; 36 import android.os.Message; 37 import android.os.PowerManager.ServiceType; 38 import android.os.PowerManagerInternal; 39 import android.os.RemoteException; 40 import android.os.ServiceManager; 41 import android.os.UserHandle; 42 import android.provider.Settings; 43 import android.util.ArraySet; 44 import android.util.IndentingPrintWriter; 45 import android.util.Pair; 46 import android.util.Slog; 47 import android.util.SparseBooleanArray; 48 import android.util.SparseSetArray; 49 import android.util.proto.ProtoOutputStream; 50 51 import com.android.internal.annotations.GuardedBy; 52 import com.android.internal.annotations.VisibleForTesting; 53 import com.android.internal.app.IAppOpsCallback; 54 import com.android.internal.app.IAppOpsService; 55 import com.android.internal.util.ArrayUtils; 56 import com.android.internal.util.StatLogger; 57 import com.android.server.AppStateTrackerProto.ExemptedPackage; 58 import com.android.server.AppStateTrackerProto.RunAnyInBackgroundRestrictedPackages; 59 import com.android.server.usage.AppStandbyInternal; 60 import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener; 61 62 import java.io.PrintWriter; 63 import java.util.Arrays; 64 import java.util.Collections; 65 import java.util.List; 66 import java.util.Objects; 67 import java.util.Set; 68 69 /** 70 * Class to keep track of the information related to "force app standby", which includes: 71 * - OP_RUN_ANY_IN_BACKGROUND for each package 72 * - UID foreground/active state 73 * - User+system power save exemption list 74 * - Temporary power save exemption list 75 * - Global "force all apps standby" mode enforced by battery saver. 76 * 77 * Test: atest com.android.server.AppStateTrackerTest 78 */ 79 public class AppStateTrackerImpl implements AppStateTracker { 80 private static final boolean DEBUG = false; 81 82 private final Object mLock = new Object(); 83 private final Context mContext; 84 85 @VisibleForTesting 86 static final int TARGET_OP = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND; 87 88 IActivityManager mIActivityManager; 89 ActivityManagerInternal mActivityManagerInternal; 90 AppOpsManager mAppOpsManager; 91 IAppOpsService mAppOpsService; 92 PowerManagerInternal mPowerManagerInternal; 93 StandbyTracker mStandbyTracker; 94 AppStandbyInternal mAppStandbyInternal; 95 96 private final MyHandler mHandler; 97 98 @VisibleForTesting 99 FeatureFlagsObserver mFlagsObserver; 100 101 /** 102 * Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed. 103 */ 104 @GuardedBy("mLock") 105 final ArraySet<Pair<Integer, String>> mRunAnyRestrictedPackages = new ArraySet<>(); 106 107 /** UIDs that are active. */ 108 @GuardedBy("mLock") 109 final SparseBooleanArray mActiveUids = new SparseBooleanArray(); 110 111 /** 112 * System except-idle + user exemption list in the device idle controller. 113 */ 114 @GuardedBy("mLock") 115 private int[] mPowerExemptAllAppIds = new int[0]; 116 117 /** 118 * User exempted apps in the device idle controller. 119 */ 120 @GuardedBy("mLock") 121 private int[] mPowerExemptUserAppIds = new int[0]; 122 123 @GuardedBy("mLock") 124 private int[] mTempExemptAppIds = mPowerExemptAllAppIds; 125 126 /** 127 * Per-user packages that are in the EXEMPTED bucket. 128 */ 129 @GuardedBy("mLock") 130 @VisibleForTesting 131 final SparseSetArray<String> mExemptedBucketPackages = new SparseSetArray<>(); 132 133 @GuardedBy("mLock") 134 final ArraySet<Listener> mListeners = new ArraySet<>(); 135 136 @GuardedBy("mLock") 137 boolean mStarted; 138 139 /** 140 * Only used for small battery use-case. 141 */ 142 @GuardedBy("mLock") 143 boolean mIsPluggedIn; 144 145 @GuardedBy("mLock") 146 boolean mBatterySaverEnabled; 147 148 /** 149 * True if the forced app standby is currently enabled 150 */ 151 @GuardedBy("mLock") 152 boolean mForceAllAppsStandby; 153 154 /** 155 * True if the forced app standby for small battery devices feature is enabled in settings 156 */ 157 @GuardedBy("mLock") 158 boolean mForceAllAppStandbyForSmallBattery; 159 160 /** 161 * True if the forced app standby feature is enabled in settings 162 */ 163 @GuardedBy("mLock") 164 boolean mForcedAppStandbyEnabled; 165 166 /** 167 * A lock-free set of (uid, packageName) pairs in background restricted mode. 168 * 169 * <p> 170 * It's bascially shadowing the {@link #mRunAnyRestrictedPackages} together with 171 * the {@link #mForcedAppStandbyEnabled} - mutations on them would result in copy-on-write. 172 * </p> 173 */ 174 volatile Set<Pair<Integer, String>> mBackgroundRestrictedUidPackages = Collections.emptySet(); 175 176 @Override addBackgroundRestrictedAppListener( @onNull BackgroundRestrictedAppListener listener)177 public void addBackgroundRestrictedAppListener( 178 @NonNull BackgroundRestrictedAppListener listener) { 179 addListener(new Listener() { 180 @Override 181 public void updateBackgroundRestrictedForUidPackage(int uid, String packageName, 182 boolean restricted) { 183 listener.updateBackgroundRestrictedForUidPackage(uid, packageName, restricted); 184 } 185 }); 186 } 187 188 @Override isAppBackgroundRestricted(int uid, @NonNull String packageName)189 public boolean isAppBackgroundRestricted(int uid, @NonNull String packageName) { 190 final Set<Pair<Integer, String>> bgRestrictedUidPkgs = mBackgroundRestrictedUidPackages; 191 return bgRestrictedUidPkgs.contains(Pair.create(uid, packageName)); 192 } 193 194 interface Stats { 195 int UID_FG_STATE_CHANGED = 0; 196 int UID_ACTIVE_STATE_CHANGED = 1; 197 int RUN_ANY_CHANGED = 2; 198 int ALL_UNEXEMPTED = 3; 199 int ALL_EXEMPTION_LIST_CHANGED = 4; 200 int TEMP_EXEMPTION_LIST_CHANGED = 5; 201 int EXEMPTED_BUCKET_CHANGED = 6; 202 int FORCE_ALL_CHANGED = 7; 203 int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8; 204 205 int IS_UID_ACTIVE_CACHED = 9; 206 int IS_UID_ACTIVE_RAW = 10; 207 } 208 209 private final StatLogger mStatLogger = new StatLogger(new String[] { 210 "UID_FG_STATE_CHANGED", 211 "UID_ACTIVE_STATE_CHANGED", 212 "RUN_ANY_CHANGED", 213 "ALL_UNEXEMPTED", 214 "ALL_EXEMPTION_LIST_CHANGED", 215 "TEMP_EXEMPTION_LIST_CHANGED", 216 "EXEMPTED_BUCKET_CHANGED", 217 "FORCE_ALL_CHANGED", 218 "FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED", 219 220 "IS_UID_ACTIVE_CACHED", 221 "IS_UID_ACTIVE_RAW", 222 }); 223 224 @VisibleForTesting 225 class FeatureFlagsObserver extends ContentObserver { FeatureFlagsObserver()226 FeatureFlagsObserver() { 227 super(null); 228 } 229 register()230 void register() { 231 mContext.getContentResolver().registerContentObserver( 232 Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED), 233 false, this); 234 235 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 236 Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED), false, this); 237 } 238 isForcedAppStandbyEnabled()239 boolean isForcedAppStandbyEnabled() { 240 return injectGetGlobalSettingInt(Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1; 241 } 242 isForcedAppStandbyForSmallBatteryEnabled()243 boolean isForcedAppStandbyForSmallBatteryEnabled() { 244 return injectGetGlobalSettingInt( 245 Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 0) == 1; 246 } 247 248 @Override onChange(boolean selfChange, Uri uri)249 public void onChange(boolean selfChange, Uri uri) { 250 if (Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED).equals(uri)) { 251 final boolean enabled = isForcedAppStandbyEnabled(); 252 synchronized (mLock) { 253 if (mForcedAppStandbyEnabled == enabled) { 254 return; 255 } 256 mForcedAppStandbyEnabled = enabled; 257 updateBackgroundRestrictedUidPackagesLocked(); 258 if (DEBUG) { 259 Slog.d(TAG, "Forced app standby feature flag changed: " 260 + mForcedAppStandbyEnabled); 261 } 262 } 263 mHandler.notifyForcedAppStandbyFeatureFlagChanged(); 264 } else if (Settings.Global.getUriFor( 265 Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED).equals(uri)) { 266 final boolean enabled = isForcedAppStandbyForSmallBatteryEnabled(); 267 synchronized (mLock) { 268 if (mForceAllAppStandbyForSmallBattery == enabled) { 269 return; 270 } 271 mForceAllAppStandbyForSmallBattery = enabled; 272 if (DEBUG) { 273 Slog.d(TAG, "Forced app standby for small battery feature flag changed: " 274 + mForceAllAppStandbyForSmallBattery); 275 } 276 updateForceAllAppStandbyState(); 277 } 278 } else { 279 Slog.w(TAG, "Unexpected feature flag uri encountered: " + uri); 280 } 281 } 282 } 283 284 private final AppBackgroundRestrictionListener mAppBackgroundRestrictionListener = 285 new AppBackgroundRestrictionListener() { 286 @Override 287 public void onAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket) { 288 mHandler.notifyAutoRestrictedBucketFeatureFlagChanged(autoRestrictedBucket); 289 } 290 }; 291 292 /** 293 * Listener for any state changes that affect any app's eligibility to run. 294 */ 295 public abstract static class Listener { 296 /** 297 * This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package. 298 */ onRunAnyAppOpsChanged(AppStateTrackerImpl sender, int uid, @NonNull String packageName)299 private void onRunAnyAppOpsChanged(AppStateTrackerImpl sender, 300 int uid, @NonNull String packageName) { 301 updateJobsForUidPackage(uid, packageName, sender.isUidActive(uid)); 302 303 if (!sender.areAlarmsRestricted(uid, packageName)) { 304 unblockAlarmsForUidPackage(uid, packageName); 305 } 306 307 if (!sender.isRunAnyInBackgroundAppOpsAllowed(uid, packageName)) { 308 Slog.v(TAG, "Package " + packageName + "/" + uid 309 + " toggled into fg service restriction"); 310 updateBackgroundRestrictedForUidPackage(uid, packageName, true); 311 } else { 312 Slog.v(TAG, "Package " + packageName + "/" + uid 313 + " toggled out of fg service restriction"); 314 updateBackgroundRestrictedForUidPackage(uid, packageName, false); 315 } 316 } 317 318 /** 319 * This is called when the active/idle state changed for a UID. 320 */ onUidActiveStateChanged(AppStateTrackerImpl sender, int uid)321 private void onUidActiveStateChanged(AppStateTrackerImpl sender, int uid) { 322 final boolean isActive = sender.isUidActive(uid); 323 324 updateJobsForUid(uid, isActive); 325 updateAlarmsForUid(uid); 326 327 if (isActive) { 328 unblockAlarmsForUid(uid); 329 } 330 } 331 332 /** 333 * This is called when an app-id(s) is removed from the power save allow-list. 334 */ onPowerSaveUnexempted(AppStateTrackerImpl sender)335 private void onPowerSaveUnexempted(AppStateTrackerImpl sender) { 336 updateAllJobs(); 337 updateAllAlarms(); 338 } 339 340 /** 341 * This is called when the power save exemption list changes, excluding the 342 * {@link #onPowerSaveUnexempted} case. 343 */ onPowerSaveExemptionListChanged(AppStateTrackerImpl sender)344 private void onPowerSaveExemptionListChanged(AppStateTrackerImpl sender) { 345 updateAllJobs(); 346 updateAllAlarms(); 347 unblockAllUnrestrictedAlarms(); 348 } 349 350 /** 351 * This is called when the temp exemption list changes. 352 */ onTempPowerSaveExemptionListChanged(AppStateTrackerImpl sender)353 private void onTempPowerSaveExemptionListChanged(AppStateTrackerImpl sender) { 354 355 // TODO This case happens rather frequently; consider optimizing and update jobs 356 // only for affected app-ids. 357 358 updateAllJobs(); 359 360 // Note when an app is just put in the temp exemption list, we do *not* drain pending 361 // alarms. 362 } 363 364 /** 365 * This is called when the EXEMPTED bucket is updated. 366 */ onExemptedBucketChanged(AppStateTrackerImpl sender)367 private void onExemptedBucketChanged(AppStateTrackerImpl sender) { 368 // This doesn't happen very often, so just re-evaluate all jobs / alarms. 369 updateAllJobs(); 370 updateAllAlarms(); 371 } 372 373 /** 374 * This is called when the global "force all apps standby" flag changes. 375 */ onForceAllAppsStandbyChanged(AppStateTrackerImpl sender)376 private void onForceAllAppsStandbyChanged(AppStateTrackerImpl sender) { 377 updateAllJobs(); 378 updateAllAlarms(); 379 } 380 381 /** 382 * Called when toggling the feature flag of moving to restricted standby bucket 383 * automatically on background-restricted. 384 */ onAutoRestrictedBucketFeatureFlagChanged(AppStateTrackerImpl sender, boolean autoRestrictedBucket)385 private void onAutoRestrictedBucketFeatureFlagChanged(AppStateTrackerImpl sender, 386 boolean autoRestrictedBucket) { 387 updateAllJobs(); 388 if (autoRestrictedBucket) { 389 unblockAllUnrestrictedAlarms(); 390 } 391 } 392 393 /** 394 * Called when the job restrictions for multiple UIDs might have changed, so the job 395 * scheduler should re-evaluate all restrictions for all jobs. 396 */ updateAllJobs()397 public void updateAllJobs() { 398 } 399 400 /** 401 * Called when the job restrictions for a UID might have changed, so the job 402 * scheduler should re-evaluate all restrictions for all jobs. 403 */ updateJobsForUid(int uid, boolean isNowActive)404 public void updateJobsForUid(int uid, boolean isNowActive) { 405 } 406 407 /** 408 * Called when the job restrictions for a UID - package might have changed, so the job 409 * scheduler should re-evaluate all restrictions for all jobs. 410 */ updateJobsForUidPackage(int uid, String packageName, boolean isNowActive)411 public void updateJobsForUidPackage(int uid, String packageName, boolean isNowActive) { 412 } 413 414 /** 415 * Called when an app goes in/out of background restricted mode. 416 */ updateBackgroundRestrictedForUidPackage(int uid, String packageName, boolean restricted)417 public void updateBackgroundRestrictedForUidPackage(int uid, String packageName, 418 boolean restricted) { 419 } 420 421 /** 422 * Called when all alarms need to be re-evaluated for eligibility based on 423 * {@link #areAlarmsRestrictedByBatterySaver}. 424 */ updateAllAlarms()425 public void updateAllAlarms() { 426 } 427 428 /** 429 * Called when the given uid state changes to active / idle. 430 */ updateAlarmsForUid(int uid)431 public void updateAlarmsForUid(int uid) { 432 } 433 434 /** 435 * Called when the job restrictions for multiple UIDs might have changed, so the alarm 436 * manager should re-evaluate all restrictions for all blocked jobs. 437 */ unblockAllUnrestrictedAlarms()438 public void unblockAllUnrestrictedAlarms() { 439 } 440 441 /** 442 * Called when all jobs for a specific UID are unblocked. 443 */ unblockAlarmsForUid(int uid)444 public void unblockAlarmsForUid(int uid) { 445 } 446 447 /** 448 * Called when all alarms for a specific UID - package are unblocked. 449 */ unblockAlarmsForUidPackage(int uid, String packageName)450 public void unblockAlarmsForUidPackage(int uid, String packageName) { 451 } 452 453 /** 454 * Called when an ephemeral uid goes to the background, so its alarms need to be removed. 455 */ removeAlarmsForUid(int uid)456 public void removeAlarmsForUid(int uid) { 457 } 458 } 459 AppStateTrackerImpl(Context context, Looper looper)460 public AppStateTrackerImpl(Context context, Looper looper) { 461 mContext = context; 462 mHandler = new MyHandler(looper); 463 } 464 465 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 466 @Override 467 public void onReceive(Context context, Intent intent) { 468 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 469 switch (intent.getAction()) { 470 case Intent.ACTION_USER_REMOVED: 471 if (userId > 0) { 472 mHandler.doUserRemoved(userId); 473 } 474 break; 475 case Intent.ACTION_BATTERY_CHANGED: 476 synchronized (mLock) { 477 mIsPluggedIn = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0); 478 } 479 updateForceAllAppStandbyState(); 480 break; 481 case Intent.ACTION_PACKAGE_REMOVED: 482 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 483 final String pkgName = intent.getData().getSchemeSpecificPart(); 484 final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 485 // No need to notify for state change as all the alarms and jobs should be 486 // removed too. 487 synchronized (mLock) { 488 mExemptedBucketPackages.remove(userId, pkgName); 489 mRunAnyRestrictedPackages.remove(Pair.create(uid, pkgName)); 490 updateBackgroundRestrictedUidPackagesLocked(); 491 mActiveUids.delete(uid); 492 } 493 } 494 break; 495 } 496 } 497 }; 498 499 /** 500 * Call it when the system is ready. 501 */ onSystemServicesReady()502 public void onSystemServicesReady() { 503 synchronized (mLock) { 504 if (mStarted) { 505 return; 506 } 507 mStarted = true; 508 509 mIActivityManager = Objects.requireNonNull(injectIActivityManager()); 510 mActivityManagerInternal = Objects.requireNonNull(injectActivityManagerInternal()); 511 mAppOpsManager = Objects.requireNonNull(injectAppOpsManager()); 512 mAppOpsService = Objects.requireNonNull(injectIAppOpsService()); 513 mPowerManagerInternal = Objects.requireNonNull(injectPowerManagerInternal()); 514 mAppStandbyInternal = Objects.requireNonNull(injectAppStandbyInternal()); 515 516 mFlagsObserver = new FeatureFlagsObserver(); 517 mFlagsObserver.register(); 518 mForcedAppStandbyEnabled = mFlagsObserver.isForcedAppStandbyEnabled(); 519 mForceAllAppStandbyForSmallBattery = 520 mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled(); 521 mStandbyTracker = new StandbyTracker(); 522 mAppStandbyInternal.addListener(mStandbyTracker); 523 mActivityManagerInternal.addAppBackgroundRestrictionListener( 524 mAppBackgroundRestrictionListener); 525 526 try { 527 mIActivityManager.registerUidObserver(new UidObserver(), 528 ActivityManager.UID_OBSERVER_GONE 529 | ActivityManager.UID_OBSERVER_IDLE 530 | ActivityManager.UID_OBSERVER_ACTIVE, 531 ActivityManager.PROCESS_STATE_UNKNOWN, null); 532 mAppOpsService.startWatchingMode(TARGET_OP, null, 533 new AppOpsWatcher()); 534 } catch (RemoteException e) { 535 // shouldn't happen. 536 } 537 538 IntentFilter filter = new IntentFilter(); 539 filter.addAction(Intent.ACTION_USER_REMOVED); 540 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 541 mContext.registerReceiver(mReceiver, filter); 542 543 filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED); 544 filter.addDataScheme(IntentFilter.SCHEME_PACKAGE); 545 mContext.registerReceiver(mReceiver, filter); 546 547 refreshForcedAppStandbyUidPackagesLocked(); 548 549 mPowerManagerInternal.registerLowPowerModeObserver( 550 ServiceType.FORCE_ALL_APPS_STANDBY, 551 (state) -> { 552 synchronized (mLock) { 553 mBatterySaverEnabled = state.batterySaverEnabled; 554 updateForceAllAppStandbyState(); 555 } 556 }); 557 558 mBatterySaverEnabled = mPowerManagerInternal.getLowPowerState( 559 ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled; 560 561 updateForceAllAppStandbyState(); 562 } 563 } 564 565 @VisibleForTesting injectAppOpsManager()566 AppOpsManager injectAppOpsManager() { 567 return mContext.getSystemService(AppOpsManager.class); 568 } 569 570 @VisibleForTesting injectIAppOpsService()571 IAppOpsService injectIAppOpsService() { 572 return IAppOpsService.Stub.asInterface( 573 ServiceManager.getService(Context.APP_OPS_SERVICE)); 574 } 575 576 @VisibleForTesting injectIActivityManager()577 IActivityManager injectIActivityManager() { 578 return ActivityManager.getService(); 579 } 580 581 @VisibleForTesting injectActivityManagerInternal()582 ActivityManagerInternal injectActivityManagerInternal() { 583 return LocalServices.getService(ActivityManagerInternal.class); 584 } 585 586 @VisibleForTesting injectPowerManagerInternal()587 PowerManagerInternal injectPowerManagerInternal() { 588 return LocalServices.getService(PowerManagerInternal.class); 589 } 590 591 @VisibleForTesting injectAppStandbyInternal()592 AppStandbyInternal injectAppStandbyInternal() { 593 return LocalServices.getService(AppStandbyInternal.class); 594 } 595 596 @VisibleForTesting isSmallBatteryDevice()597 boolean isSmallBatteryDevice() { 598 return ActivityManager.isSmallBatteryDevice(); 599 } 600 601 @VisibleForTesting injectGetGlobalSettingInt(String key, int def)602 int injectGetGlobalSettingInt(String key, int def) { 603 return Settings.Global.getInt(mContext.getContentResolver(), key, def); 604 } 605 606 /** 607 * Update {@link #mRunAnyRestrictedPackages} with the current app ops state. 608 */ 609 @GuardedBy("mLock") refreshForcedAppStandbyUidPackagesLocked()610 private void refreshForcedAppStandbyUidPackagesLocked() { 611 mRunAnyRestrictedPackages.clear(); 612 final List<PackageOps> ops = mAppOpsManager.getPackagesForOps( 613 new int[] {TARGET_OP}); 614 615 if (ops == null) { 616 return; 617 } 618 final int size = ops.size(); 619 for (int i = 0; i < size; i++) { 620 final AppOpsManager.PackageOps pkg = ops.get(i); 621 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps(); 622 623 for (int j = 0; j < entries.size(); j++) { 624 AppOpsManager.OpEntry ent = entries.get(j); 625 if (ent.getOp() != TARGET_OP) { 626 continue; 627 } 628 if (ent.getMode() != AppOpsManager.MODE_ALLOWED) { 629 mRunAnyRestrictedPackages.add(Pair.create( 630 pkg.getUid(), pkg.getPackageName())); 631 } 632 } 633 } 634 updateBackgroundRestrictedUidPackagesLocked(); 635 } 636 637 /** 638 * Update the {@link #mBackgroundRestrictedUidPackages} upon mutations on 639 * {@link #mRunAnyRestrictedPackages} or {@link #mForcedAppStandbyEnabled}. 640 */ 641 @GuardedBy("mLock") updateBackgroundRestrictedUidPackagesLocked()642 private void updateBackgroundRestrictedUidPackagesLocked() { 643 if (!mForcedAppStandbyEnabled) { 644 mBackgroundRestrictedUidPackages = Collections.emptySet(); 645 return; 646 } 647 Set<Pair<Integer, String>> fasUidPkgs = new ArraySet<>(); 648 for (int i = 0, size = mRunAnyRestrictedPackages.size(); i < size; i++) { 649 fasUidPkgs.add(mRunAnyRestrictedPackages.valueAt(i)); 650 } 651 mBackgroundRestrictedUidPackages = Collections.unmodifiableSet(fasUidPkgs); 652 } 653 updateForceAllAppStandbyState()654 private void updateForceAllAppStandbyState() { 655 synchronized (mLock) { 656 if (mForceAllAppStandbyForSmallBattery && isSmallBatteryDevice()) { 657 toggleForceAllAppsStandbyLocked(!mIsPluggedIn); 658 } else { 659 toggleForceAllAppsStandbyLocked(mBatterySaverEnabled); 660 } 661 } 662 } 663 664 /** 665 * Update {@link #mForceAllAppsStandby} and notifies the listeners. 666 */ 667 @GuardedBy("mLock") toggleForceAllAppsStandbyLocked(boolean enable)668 private void toggleForceAllAppsStandbyLocked(boolean enable) { 669 if (enable == mForceAllAppsStandby) { 670 return; 671 } 672 mForceAllAppsStandby = enable; 673 674 mHandler.notifyForceAllAppsStandbyChanged(); 675 } 676 677 @GuardedBy("mLock") findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName)678 private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) { 679 final int size = mRunAnyRestrictedPackages.size(); 680 if (size > 8) { 681 return mRunAnyRestrictedPackages.indexOf(Pair.create(uid, packageName)); 682 } 683 for (int i = 0; i < size; i++) { 684 final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i); 685 686 if ((pair.first == uid) && packageName.equals(pair.second)) { 687 return i; 688 } 689 } 690 return -1; 691 } 692 693 /** 694 * @return whether a uid package-name pair is in mRunAnyRestrictedPackages. 695 */ 696 @GuardedBy("mLock") isRunAnyRestrictedLocked(int uid, @NonNull String packageName)697 boolean isRunAnyRestrictedLocked(int uid, @NonNull String packageName) { 698 return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0; 699 } 700 701 /** 702 * Add to / remove from {@link #mRunAnyRestrictedPackages}. 703 */ 704 @GuardedBy("mLock") updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName, boolean restricted)705 boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName, 706 boolean restricted) { 707 final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName); 708 final boolean wasRestricted = index >= 0; 709 if (wasRestricted == restricted) { 710 return false; 711 } 712 if (restricted) { 713 mRunAnyRestrictedPackages.add(Pair.create(uid, packageName)); 714 } else { 715 mRunAnyRestrictedPackages.removeAt(index); 716 } 717 updateBackgroundRestrictedUidPackagesLocked(); 718 return true; 719 } 720 addUidToArray(SparseBooleanArray array, int uid)721 private static boolean addUidToArray(SparseBooleanArray array, int uid) { 722 if (UserHandle.isCore(uid)) { 723 return false; 724 } 725 if (array.get(uid)) { 726 return false; 727 } 728 array.put(uid, true); 729 return true; 730 } 731 removeUidFromArray(SparseBooleanArray array, int uid, boolean remove)732 private static boolean removeUidFromArray(SparseBooleanArray array, int uid, boolean remove) { 733 if (UserHandle.isCore(uid)) { 734 return false; 735 } 736 if (!array.get(uid)) { 737 return false; 738 } 739 if (remove) { 740 array.delete(uid); 741 } else { 742 array.put(uid, false); 743 } 744 return true; 745 } 746 747 private final class UidObserver extends IUidObserver.Stub { 748 @Override onUidStateChanged(int uid, int procState, long procStateSeq, int capability)749 public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) { 750 } 751 752 @Override onUidActive(int uid)753 public void onUidActive(int uid) { 754 mHandler.onUidActive(uid); 755 } 756 757 @Override onUidGone(int uid, boolean disabled)758 public void onUidGone(int uid, boolean disabled) { 759 mHandler.onUidGone(uid, disabled); 760 } 761 762 @Override onUidIdle(int uid, boolean disabled)763 public void onUidIdle(int uid, boolean disabled) { 764 mHandler.onUidIdle(uid, disabled); 765 } 766 767 @Override onUidCachedChanged(int uid, boolean cached)768 public void onUidCachedChanged(int uid, boolean cached) { 769 } 770 771 @Override onUidProcAdjChanged(int uid)772 public void onUidProcAdjChanged(int uid) { 773 } 774 } 775 776 private final class AppOpsWatcher extends IAppOpsCallback.Stub { 777 @Override opChanged(int op, int uid, String packageName)778 public void opChanged(int op, int uid, String packageName) throws RemoteException { 779 boolean restricted = false; 780 try { 781 restricted = mAppOpsService.checkOperation(TARGET_OP, 782 uid, packageName) != AppOpsManager.MODE_ALLOWED; 783 } catch (RemoteException e) { 784 // Shouldn't happen 785 } 786 synchronized (mLock) { 787 if (updateForcedAppStandbyUidPackageLocked(uid, packageName, restricted)) { 788 mHandler.notifyRunAnyAppOpsChanged(uid, packageName); 789 } 790 } 791 } 792 } 793 794 final class StandbyTracker extends AppIdleStateChangeListener { 795 @Override onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason)796 public void onAppIdleStateChanged(String packageName, int userId, boolean idle, 797 int bucket, int reason) { 798 if (DEBUG) { 799 Slog.d(TAG, "onAppIdleStateChanged: " + packageName + " u" + userId 800 + (idle ? " idle" : " active") + " " + bucket); 801 } 802 synchronized (mLock) { 803 final boolean changed; 804 if (bucket == UsageStatsManager.STANDBY_BUCKET_EXEMPTED) { 805 changed = mExemptedBucketPackages.add(userId, packageName); 806 } else { 807 changed = mExemptedBucketPackages.remove(userId, packageName); 808 } 809 if (changed) { 810 mHandler.notifyExemptedBucketChanged(); 811 } 812 } 813 } 814 } 815 cloneListeners()816 private Listener[] cloneListeners() { 817 synchronized (mLock) { 818 return mListeners.toArray(new Listener[mListeners.size()]); 819 } 820 } 821 822 private class MyHandler extends Handler { 823 private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0; 824 private static final int MSG_RUN_ANY_CHANGED = 3; 825 private static final int MSG_ALL_UNEXEMPTED = 4; 826 private static final int MSG_ALL_EXEMPTION_LIST_CHANGED = 5; 827 private static final int MSG_TEMP_EXEMPTION_LIST_CHANGED = 6; 828 private static final int MSG_FORCE_ALL_CHANGED = 7; 829 private static final int MSG_USER_REMOVED = 8; 830 private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9; 831 private static final int MSG_EXEMPTED_BUCKET_CHANGED = 10; 832 private static final int MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED = 11; 833 834 private static final int MSG_ON_UID_ACTIVE = 12; 835 private static final int MSG_ON_UID_GONE = 13; 836 private static final int MSG_ON_UID_IDLE = 14; 837 MyHandler(Looper looper)838 MyHandler(Looper looper) { 839 super(looper); 840 } 841 notifyUidActiveStateChanged(int uid)842 public void notifyUidActiveStateChanged(int uid) { 843 obtainMessage(MSG_UID_ACTIVE_STATE_CHANGED, uid, 0).sendToTarget(); 844 } 845 notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName)846 public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) { 847 obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget(); 848 } 849 notifyAllUnexempted()850 public void notifyAllUnexempted() { 851 removeMessages(MSG_ALL_UNEXEMPTED); 852 obtainMessage(MSG_ALL_UNEXEMPTED).sendToTarget(); 853 } 854 notifyAllExemptionListChanged()855 public void notifyAllExemptionListChanged() { 856 removeMessages(MSG_ALL_EXEMPTION_LIST_CHANGED); 857 obtainMessage(MSG_ALL_EXEMPTION_LIST_CHANGED).sendToTarget(); 858 } 859 notifyTempExemptionListChanged()860 public void notifyTempExemptionListChanged() { 861 removeMessages(MSG_TEMP_EXEMPTION_LIST_CHANGED); 862 obtainMessage(MSG_TEMP_EXEMPTION_LIST_CHANGED).sendToTarget(); 863 } 864 notifyForceAllAppsStandbyChanged()865 public void notifyForceAllAppsStandbyChanged() { 866 removeMessages(MSG_FORCE_ALL_CHANGED); 867 obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget(); 868 } 869 notifyForcedAppStandbyFeatureFlagChanged()870 public void notifyForcedAppStandbyFeatureFlagChanged() { 871 removeMessages(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED); 872 obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget(); 873 } 874 notifyExemptedBucketChanged()875 public void notifyExemptedBucketChanged() { 876 removeMessages(MSG_EXEMPTED_BUCKET_CHANGED); 877 obtainMessage(MSG_EXEMPTED_BUCKET_CHANGED).sendToTarget(); 878 } 879 notifyAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket)880 public void notifyAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket) { 881 removeMessages(MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED); 882 obtainMessage(MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED, 883 autoRestrictedBucket ? 1 : 0, 0).sendToTarget(); 884 } 885 doUserRemoved(int userId)886 public void doUserRemoved(int userId) { 887 obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget(); 888 } 889 onUidActive(int uid)890 public void onUidActive(int uid) { 891 obtainMessage(MSG_ON_UID_ACTIVE, uid, 0).sendToTarget(); 892 } 893 onUidGone(int uid, boolean disabled)894 public void onUidGone(int uid, boolean disabled) { 895 obtainMessage(MSG_ON_UID_GONE, uid, disabled ? 1 : 0).sendToTarget(); 896 } 897 onUidIdle(int uid, boolean disabled)898 public void onUidIdle(int uid, boolean disabled) { 899 obtainMessage(MSG_ON_UID_IDLE, uid, disabled ? 1 : 0).sendToTarget(); 900 } 901 902 @Override handleMessage(Message msg)903 public void handleMessage(Message msg) { 904 switch (msg.what) { 905 case MSG_USER_REMOVED: 906 handleUserRemoved(msg.arg1); 907 return; 908 } 909 910 // Only notify the listeners when started. 911 synchronized (mLock) { 912 if (!mStarted) { 913 return; 914 } 915 } 916 final AppStateTrackerImpl sender = AppStateTrackerImpl.this; 917 918 long start = mStatLogger.getTime(); 919 switch (msg.what) { 920 case MSG_UID_ACTIVE_STATE_CHANGED: 921 for (Listener l : cloneListeners()) { 922 l.onUidActiveStateChanged(sender, msg.arg1); 923 } 924 mStatLogger.logDurationStat(Stats.UID_ACTIVE_STATE_CHANGED, start); 925 return; 926 927 case MSG_RUN_ANY_CHANGED: 928 for (Listener l : cloneListeners()) { 929 l.onRunAnyAppOpsChanged(sender, msg.arg1, (String) msg.obj); 930 } 931 mStatLogger.logDurationStat(Stats.RUN_ANY_CHANGED, start); 932 return; 933 934 case MSG_ALL_UNEXEMPTED: 935 for (Listener l : cloneListeners()) { 936 l.onPowerSaveUnexempted(sender); 937 } 938 mStatLogger.logDurationStat(Stats.ALL_UNEXEMPTED, start); 939 return; 940 941 case MSG_ALL_EXEMPTION_LIST_CHANGED: 942 for (Listener l : cloneListeners()) { 943 l.onPowerSaveExemptionListChanged(sender); 944 } 945 mStatLogger.logDurationStat(Stats.ALL_EXEMPTION_LIST_CHANGED, start); 946 return; 947 948 case MSG_TEMP_EXEMPTION_LIST_CHANGED: 949 for (Listener l : cloneListeners()) { 950 l.onTempPowerSaveExemptionListChanged(sender); 951 } 952 mStatLogger.logDurationStat(Stats.TEMP_EXEMPTION_LIST_CHANGED, start); 953 return; 954 955 case MSG_EXEMPTED_BUCKET_CHANGED: 956 for (Listener l : cloneListeners()) { 957 l.onExemptedBucketChanged(sender); 958 } 959 mStatLogger.logDurationStat(Stats.EXEMPTED_BUCKET_CHANGED, start); 960 return; 961 962 case MSG_FORCE_ALL_CHANGED: 963 for (Listener l : cloneListeners()) { 964 l.onForceAllAppsStandbyChanged(sender); 965 } 966 mStatLogger.logDurationStat(Stats.FORCE_ALL_CHANGED, start); 967 return; 968 969 case MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED: 970 // Feature flag for forced app standby changed. 971 final boolean unblockAlarms; 972 synchronized (mLock) { 973 unblockAlarms = !mForcedAppStandbyEnabled; 974 } 975 for (Listener l : cloneListeners()) { 976 l.updateAllJobs(); 977 if (unblockAlarms) { 978 l.unblockAllUnrestrictedAlarms(); 979 } 980 } 981 mStatLogger.logDurationStat( 982 Stats.FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED, start); 983 return; 984 985 case MSG_USER_REMOVED: 986 handleUserRemoved(msg.arg1); 987 return; 988 989 case MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED: 990 final boolean autoRestrictedBucket = msg.arg1 == 1; 991 for (Listener l : cloneListeners()) { 992 l.onAutoRestrictedBucketFeatureFlagChanged(sender, autoRestrictedBucket); 993 } 994 return; 995 996 case MSG_ON_UID_ACTIVE: 997 handleUidActive(msg.arg1); 998 return; 999 case MSG_ON_UID_GONE: 1000 handleUidGone(msg.arg1); 1001 if (msg.arg2 != 0) { 1002 handleUidDisabled(msg.arg1); 1003 } 1004 return; 1005 case MSG_ON_UID_IDLE: 1006 handleUidIdle(msg.arg1); 1007 if (msg.arg2 != 0) { 1008 handleUidDisabled(msg.arg1); 1009 } 1010 return; 1011 } 1012 } 1013 handleUidDisabled(int uid)1014 private void handleUidDisabled(int uid) { 1015 for (Listener l : cloneListeners()) { 1016 l.removeAlarmsForUid(uid); 1017 } 1018 } 1019 handleUidActive(int uid)1020 public void handleUidActive(int uid) { 1021 synchronized (mLock) { 1022 if (addUidToArray(mActiveUids, uid)) { 1023 mHandler.notifyUidActiveStateChanged(uid); 1024 } 1025 } 1026 } 1027 handleUidGone(int uid)1028 public void handleUidGone(int uid) { 1029 removeUid(uid, true); 1030 } 1031 handleUidIdle(int uid)1032 public void handleUidIdle(int uid) { 1033 // Just to avoid excessive memcpy, don't remove from the array in this case. 1034 removeUid(uid, false); 1035 } 1036 removeUid(int uid, boolean remove)1037 private void removeUid(int uid, boolean remove) { 1038 synchronized (mLock) { 1039 if (removeUidFromArray(mActiveUids, uid, remove)) { 1040 mHandler.notifyUidActiveStateChanged(uid); 1041 } 1042 } 1043 } 1044 } 1045 handleUserRemoved(int removedUserId)1046 void handleUserRemoved(int removedUserId) { 1047 synchronized (mLock) { 1048 for (int i = mRunAnyRestrictedPackages.size() - 1; i >= 0; i--) { 1049 final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i); 1050 final int uid = pair.first; 1051 final int userId = UserHandle.getUserId(uid); 1052 1053 if (userId == removedUserId) { 1054 mRunAnyRestrictedPackages.removeAt(i); 1055 } 1056 } 1057 updateBackgroundRestrictedUidPackagesLocked(); 1058 cleanUpArrayForUser(mActiveUids, removedUserId); 1059 mExemptedBucketPackages.remove(removedUserId); 1060 } 1061 } 1062 cleanUpArrayForUser(SparseBooleanArray array, int removedUserId)1063 private void cleanUpArrayForUser(SparseBooleanArray array, int removedUserId) { 1064 for (int i = array.size() - 1; i >= 0; i--) { 1065 final int uid = array.keyAt(i); 1066 final int userId = UserHandle.getUserId(uid); 1067 1068 if (userId == removedUserId) { 1069 array.removeAt(i); 1070 } 1071 } 1072 } 1073 1074 /** 1075 * Called by device idle controller to update the power save exemption lists. 1076 */ setPowerSaveExemptionListAppIds( int[] powerSaveExemptionListExceptIdleAppIdArray, int[] powerSaveExemptionListUserAppIdArray, int[] tempExemptionListAppIdArray)1077 public void setPowerSaveExemptionListAppIds( 1078 int[] powerSaveExemptionListExceptIdleAppIdArray, 1079 int[] powerSaveExemptionListUserAppIdArray, 1080 int[] tempExemptionListAppIdArray) { 1081 synchronized (mLock) { 1082 final int[] previousExemptionList = mPowerExemptAllAppIds; 1083 final int[] previousTempExemptionList = mTempExemptAppIds; 1084 1085 mPowerExemptAllAppIds = powerSaveExemptionListExceptIdleAppIdArray; 1086 mTempExemptAppIds = tempExemptionListAppIdArray; 1087 mPowerExemptUserAppIds = powerSaveExemptionListUserAppIdArray; 1088 1089 if (isAnyAppIdUnexempt(previousExemptionList, mPowerExemptAllAppIds)) { 1090 mHandler.notifyAllUnexempted(); 1091 } else if (!Arrays.equals(previousExemptionList, mPowerExemptAllAppIds)) { 1092 mHandler.notifyAllExemptionListChanged(); 1093 } 1094 1095 if (!Arrays.equals(previousTempExemptionList, mTempExemptAppIds)) { 1096 mHandler.notifyTempExemptionListChanged(); 1097 } 1098 1099 } 1100 } 1101 1102 /** 1103 * @return true if a sorted app-id array {@code prevArray} has at least one element 1104 * that's not in a sorted app-id array {@code newArray}. 1105 */ 1106 @VisibleForTesting isAnyAppIdUnexempt(int[] prevArray, int[] newArray)1107 static boolean isAnyAppIdUnexempt(int[] prevArray, int[] newArray) { 1108 int i1 = 0; 1109 int i2 = 0; 1110 boolean prevFinished; 1111 boolean newFinished; 1112 1113 for (;;) { 1114 prevFinished = i1 >= prevArray.length; 1115 newFinished = i2 >= newArray.length; 1116 if (prevFinished || newFinished) { 1117 break; 1118 } 1119 int a1 = prevArray[i1]; 1120 int a2 = newArray[i2]; 1121 1122 if (a1 == a2) { 1123 i1++; 1124 i2++; 1125 continue; 1126 } 1127 if (a1 < a2) { 1128 // prevArray has an element that's not in a2. 1129 return true; 1130 } 1131 i2++; 1132 } 1133 if (prevFinished) { 1134 return false; 1135 } 1136 return newFinished; 1137 } 1138 1139 // Public interface. 1140 1141 /** 1142 * Register a listener to get callbacks when any state changes. 1143 */ addListener(@onNull Listener listener)1144 public void addListener(@NonNull Listener listener) { 1145 synchronized (mLock) { 1146 mListeners.add(listener); 1147 } 1148 } 1149 1150 /** 1151 * @return whether alarms should be restricted for a UID package-name, due to explicit 1152 * user-forced app standby. Use {{@link #areAlarmsRestrictedByBatterySaver} to check for 1153 * restrictions induced by battery saver. 1154 */ areAlarmsRestricted(int uid, @NonNull String packageName)1155 public boolean areAlarmsRestricted(int uid, @NonNull String packageName) { 1156 if (isUidActive(uid)) { 1157 return false; 1158 } 1159 synchronized (mLock) { 1160 final int appId = UserHandle.getAppId(uid); 1161 if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) { 1162 return false; 1163 } 1164 // If apps will be put into restricted standby bucket automatically on user-forced 1165 // app standby, instead of blocking alarms completely, let the restricted standby bucket 1166 // policy take care of it. 1167 return (mForcedAppStandbyEnabled 1168 && !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled() 1169 && isRunAnyRestrictedLocked(uid, packageName)); 1170 } 1171 } 1172 1173 /** 1174 * @return whether alarms should be restricted when due to battery saver. 1175 */ areAlarmsRestrictedByBatterySaver(int uid, @NonNull String packageName)1176 public boolean areAlarmsRestrictedByBatterySaver(int uid, @NonNull String packageName) { 1177 if (isUidActive(uid)) { 1178 return false; 1179 } 1180 synchronized (mLock) { 1181 final int appId = UserHandle.getAppId(uid); 1182 if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) { 1183 return false; 1184 } 1185 final int userId = UserHandle.getUserId(uid); 1186 if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole() 1187 && mExemptedBucketPackages.contains(userId, packageName)) { 1188 return false; 1189 } 1190 return mForceAllAppsStandby; 1191 } 1192 } 1193 1194 1195 /** 1196 * @return whether jobs should be restricted for a UID package-name. This could be due to 1197 * battery saver or user-forced app standby 1198 */ areJobsRestricted(int uid, @NonNull String packageName, boolean hasForegroundExemption)1199 public boolean areJobsRestricted(int uid, @NonNull String packageName, 1200 boolean hasForegroundExemption) { 1201 if (isUidActive(uid)) { 1202 return false; 1203 } 1204 synchronized (mLock) { 1205 final int appId = UserHandle.getAppId(uid); 1206 if (ArrayUtils.contains(mPowerExemptAllAppIds, appId) 1207 || ArrayUtils.contains(mTempExemptAppIds, appId)) { 1208 return false; 1209 } 1210 // If apps will be put into restricted standby bucket automatically on user-forced 1211 // app standby, instead of blocking jobs completely, let the restricted standby bucket 1212 // policy take care of it. 1213 if (mForcedAppStandbyEnabled 1214 && !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled() 1215 && isRunAnyRestrictedLocked(uid, packageName)) { 1216 return true; 1217 } 1218 if (hasForegroundExemption) { 1219 return false; 1220 } 1221 final int userId = UserHandle.getUserId(uid); 1222 if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole() 1223 && mExemptedBucketPackages.contains(userId, packageName)) { 1224 return false; 1225 } 1226 return mForceAllAppsStandby; 1227 } 1228 } 1229 1230 /** 1231 * @return whether a UID is in active or not *based on cached information.* 1232 * 1233 * Note this information is based on the UID proc state callback, meaning it's updated 1234 * asynchronously and may subtly be stale. If the fresh data is needed, use 1235 * {@link #isUidActiveSynced} instead. 1236 */ isUidActive(int uid)1237 public boolean isUidActive(int uid) { 1238 if (UserHandle.isCore(uid)) { 1239 return true; 1240 } 1241 synchronized (mLock) { 1242 return mActiveUids.get(uid); 1243 } 1244 } 1245 1246 /** 1247 * @return whether a UID is in active or not *right now.* 1248 * 1249 * This gives the fresh information, but may access the activity manager so is slower. 1250 */ isUidActiveSynced(int uid)1251 public boolean isUidActiveSynced(int uid) { 1252 if (isUidActive(uid)) { // Use the cached one first. 1253 return true; 1254 } 1255 final long start = mStatLogger.getTime(); 1256 1257 final boolean ret = mActivityManagerInternal.isUidActive(uid); 1258 mStatLogger.logDurationStat(Stats.IS_UID_ACTIVE_RAW, start); 1259 1260 return ret; 1261 } 1262 1263 /** 1264 * @return whether force all apps standby is enabled or not. 1265 */ isForceAllAppsStandbyEnabled()1266 public boolean isForceAllAppsStandbyEnabled() { 1267 synchronized (mLock) { 1268 return mForceAllAppsStandby; 1269 } 1270 } 1271 1272 /** 1273 * @return whether a UID/package has {@code OP_RUN_ANY_IN_BACKGROUND} allowed or not. 1274 * 1275 * Note clients normally shouldn't need to access it. It's only for dumpsys. 1276 */ isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName)1277 public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) { 1278 synchronized (mLock) { 1279 return !isRunAnyRestrictedLocked(uid, packageName); 1280 } 1281 } 1282 1283 /** 1284 * @return whether a UID is in the user / system defined power-save exemption list or not. 1285 * 1286 * Note clients normally shouldn't need to access it. It's only for dumpsys. 1287 */ isUidPowerSaveExempt(int uid)1288 public boolean isUidPowerSaveExempt(int uid) { 1289 synchronized (mLock) { 1290 return ArrayUtils.contains(mPowerExemptAllAppIds, UserHandle.getAppId(uid)); 1291 } 1292 } 1293 1294 /** 1295 * @param uid the uid to check for 1296 * @return whether a UID is in the user defined power-save exemption list or not. 1297 */ isUidPowerSaveUserExempt(int uid)1298 public boolean isUidPowerSaveUserExempt(int uid) { 1299 synchronized (mLock) { 1300 return ArrayUtils.contains(mPowerExemptUserAppIds, UserHandle.getAppId(uid)); 1301 } 1302 } 1303 1304 /** 1305 * @return whether a UID is in the temp power-save exemption list or not. 1306 * 1307 * Note clients normally shouldn't need to access it. It's only for dumpsys. 1308 */ isUidTempPowerSaveExempt(int uid)1309 public boolean isUidTempPowerSaveExempt(int uid) { 1310 synchronized (mLock) { 1311 return ArrayUtils.contains(mTempExemptAppIds, UserHandle.getAppId(uid)); 1312 } 1313 } 1314 1315 /** 1316 * Dump the internal state to the given PrintWriter. Can be included in the dump 1317 * of a binder service to be output on the shell command "dumpsys". 1318 */ dump(IndentingPrintWriter pw)1319 public void dump(IndentingPrintWriter pw) { 1320 synchronized (mLock) { 1321 pw.println("Current AppStateTracker State:"); 1322 1323 pw.increaseIndent(); 1324 pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled); 1325 1326 pw.print("Force all apps standby: "); 1327 pw.println(isForceAllAppsStandbyEnabled()); 1328 1329 pw.print("Small Battery Device: "); 1330 pw.println(isSmallBatteryDevice()); 1331 1332 pw.print("Force all apps standby for small battery device: "); 1333 pw.println(mForceAllAppStandbyForSmallBattery); 1334 1335 pw.print("Plugged In: "); 1336 pw.println(mIsPluggedIn); 1337 1338 pw.print("Active uids: "); 1339 dumpUids(pw, mActiveUids); 1340 1341 pw.print("Except-idle + user exemption list appids: "); 1342 pw.println(Arrays.toString(mPowerExemptAllAppIds)); 1343 1344 pw.print("User exemption list appids: "); 1345 pw.println(Arrays.toString(mPowerExemptUserAppIds)); 1346 1347 pw.print("Temp exemption list appids: "); 1348 pw.println(Arrays.toString(mTempExemptAppIds)); 1349 1350 pw.println("Exempted bucket packages:"); 1351 pw.increaseIndent(); 1352 for (int i = 0; i < mExemptedBucketPackages.size(); i++) { 1353 pw.print("User "); 1354 pw.print(mExemptedBucketPackages.keyAt(i)); 1355 pw.println(); 1356 1357 pw.increaseIndent(); 1358 for (int j = 0; j < mExemptedBucketPackages.sizeAt(i); j++) { 1359 pw.print(mExemptedBucketPackages.valueAt(i, j)); 1360 pw.println(); 1361 } 1362 pw.decreaseIndent(); 1363 } 1364 pw.decreaseIndent(); 1365 pw.println(); 1366 1367 pw.println("Restricted packages:"); 1368 pw.increaseIndent(); 1369 for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) { 1370 pw.print(UserHandle.formatUid(uidAndPackage.first)); 1371 pw.print(" "); 1372 pw.print(uidAndPackage.second); 1373 pw.println(); 1374 } 1375 pw.decreaseIndent(); 1376 1377 mStatLogger.dump(pw); 1378 pw.decreaseIndent(); 1379 } 1380 } 1381 dumpUids(PrintWriter pw, SparseBooleanArray array)1382 private void dumpUids(PrintWriter pw, SparseBooleanArray array) { 1383 pw.print("["); 1384 1385 String sep = ""; 1386 for (int i = 0; i < array.size(); i++) { 1387 if (array.valueAt(i)) { 1388 pw.print(sep); 1389 pw.print(UserHandle.formatUid(array.keyAt(i))); 1390 sep = " "; 1391 } 1392 } 1393 pw.println("]"); 1394 } 1395 1396 /** 1397 * Proto version of {@link #dump(IndentingPrintWriter)} 1398 */ dumpProto(ProtoOutputStream proto, long fieldId)1399 public void dumpProto(ProtoOutputStream proto, long fieldId) { 1400 synchronized (mLock) { 1401 final long token = proto.start(fieldId); 1402 1403 proto.write(AppStateTrackerProto.FORCED_APP_STANDBY_FEATURE_ENABLED, 1404 mForcedAppStandbyEnabled); 1405 proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY, 1406 isForceAllAppsStandbyEnabled()); 1407 proto.write(AppStateTrackerProto.IS_SMALL_BATTERY_DEVICE, isSmallBatteryDevice()); 1408 proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY, 1409 mForceAllAppStandbyForSmallBattery); 1410 proto.write(AppStateTrackerProto.IS_PLUGGED_IN, mIsPluggedIn); 1411 1412 for (int i = 0; i < mActiveUids.size(); i++) { 1413 if (mActiveUids.valueAt(i)) { 1414 proto.write(AppStateTrackerProto.ACTIVE_UIDS, mActiveUids.keyAt(i)); 1415 } 1416 } 1417 1418 for (int appId : mPowerExemptAllAppIds) { 1419 proto.write(AppStateTrackerProto.POWER_SAVE_EXEMPT_APP_IDS, appId); 1420 } 1421 1422 for (int appId : mPowerExemptUserAppIds) { 1423 proto.write(AppStateTrackerProto.POWER_SAVE_USER_EXEMPT_APP_IDS, appId); 1424 } 1425 1426 for (int appId : mTempExemptAppIds) { 1427 proto.write(AppStateTrackerProto.TEMP_POWER_SAVE_EXEMPT_APP_IDS, appId); 1428 } 1429 1430 for (int i = 0; i < mExemptedBucketPackages.size(); i++) { 1431 for (int j = 0; j < mExemptedBucketPackages.sizeAt(i); j++) { 1432 final long token2 = proto.start(AppStateTrackerProto.EXEMPTED_BUCKET_PACKAGES); 1433 1434 proto.write(ExemptedPackage.USER_ID, mExemptedBucketPackages.keyAt(i)); 1435 proto.write(ExemptedPackage.PACKAGE_NAME, 1436 mExemptedBucketPackages.valueAt(i, j)); 1437 1438 proto.end(token2); 1439 } 1440 } 1441 1442 for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) { 1443 final long token2 = proto.start( 1444 AppStateTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES); 1445 proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first); 1446 proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME, 1447 uidAndPackage.second); 1448 proto.end(token2); 1449 } 1450 1451 mStatLogger.dumpProto(proto, AppStateTrackerProto.STATS); 1452 1453 proto.end(token); 1454 } 1455 } 1456 } 1457