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