1 /** 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 17 package com.android.server.usage; 18 19 import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT; 20 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM; 21 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER; 22 import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK; 23 import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED; 24 import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT; 25 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; 26 import static android.app.usage.UsageStatsManager.REASON_SUB_DEFAULT_APP_UPDATE; 27 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY; 28 import static android.app.usage.UsageStatsManager.REASON_SUB_MASK; 29 import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED; 30 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT; 31 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE; 32 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE; 33 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START; 34 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START; 35 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND; 36 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND; 37 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN; 38 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED; 39 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV; 40 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER; 41 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION; 42 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE; 43 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED; 44 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION; 45 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; 46 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED; 47 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; 48 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; 49 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; 50 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED; 51 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; 52 53 import static com.android.server.SystemService.PHASE_BOOT_COMPLETED; 54 import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; 55 56 import android.annotation.NonNull; 57 import android.annotation.Nullable; 58 import android.annotation.UserIdInt; 59 import android.app.ActivityManager; 60 import android.app.AppGlobals; 61 import android.app.usage.AppStandbyInfo; 62 import android.app.usage.UsageEvents; 63 import android.app.usage.UsageStatsManager.StandbyBuckets; 64 import android.app.usage.UsageStatsManager.SystemForcedReasons; 65 import android.appwidget.AppWidgetManager; 66 import android.content.BroadcastReceiver; 67 import android.content.ContentResolver; 68 import android.content.Context; 69 import android.content.Intent; 70 import android.content.IntentFilter; 71 import android.content.pm.ApplicationInfo; 72 import android.content.pm.CrossProfileAppsInternal; 73 import android.content.pm.PackageInfo; 74 import android.content.pm.PackageManager; 75 import android.content.pm.PackageManagerInternal; 76 import android.content.pm.ParceledListSlice; 77 import android.database.ContentObserver; 78 import android.hardware.display.DisplayManager; 79 import android.net.NetworkScoreManager; 80 import android.os.BatteryManager; 81 import android.os.BatteryStats; 82 import android.os.Build; 83 import android.os.Environment; 84 import android.os.Handler; 85 import android.os.IDeviceIdleController; 86 import android.os.Looper; 87 import android.os.Message; 88 import android.os.PowerManager; 89 import android.os.Process; 90 import android.os.RemoteException; 91 import android.os.ServiceManager; 92 import android.os.SystemClock; 93 import android.os.Trace; 94 import android.os.UserHandle; 95 import android.provider.Settings.Global; 96 import android.telephony.TelephonyManager; 97 import android.util.ArraySet; 98 import android.util.KeyValueListParser; 99 import android.util.Slog; 100 import android.util.SparseArray; 101 import android.util.SparseIntArray; 102 import android.util.TimeUtils; 103 import android.view.Display; 104 import android.widget.Toast; 105 106 import com.android.internal.R; 107 import com.android.internal.annotations.GuardedBy; 108 import com.android.internal.annotations.VisibleForTesting; 109 import com.android.internal.app.IBatteryStats; 110 import com.android.internal.os.SomeArgs; 111 import com.android.internal.util.ArrayUtils; 112 import com.android.internal.util.ConcurrentUtils; 113 import com.android.internal.util.IndentingPrintWriter; 114 import com.android.server.LocalServices; 115 import com.android.server.pm.parsing.pkg.AndroidPackage; 116 import com.android.server.usage.AppIdleHistory.AppUsageHistory; 117 118 import java.io.File; 119 import java.io.PrintWriter; 120 import java.time.Duration; 121 import java.time.format.DateTimeParseException; 122 import java.util.ArrayList; 123 import java.util.Arrays; 124 import java.util.Collections; 125 import java.util.List; 126 import java.util.Set; 127 import java.util.concurrent.CountDownLatch; 128 129 /** 130 * Manages the standby state of an app, listening to various events. 131 * 132 * Unit test: 133 atest com.android.server.usage.AppStandbyControllerTests 134 */ 135 public class AppStandbyController implements AppStandbyInternal { 136 137 private static final String TAG = "AppStandbyController"; 138 // Do not submit with true. 139 static final boolean DEBUG = false; 140 141 static final boolean COMPRESS_TIME = false; 142 private static final long ONE_MINUTE = 60 * 1000; 143 private static final long ONE_HOUR = ONE_MINUTE * 60; 144 private static final long ONE_DAY = ONE_HOUR * 24; 145 146 /** 147 * The minimum amount of time the screen must have been on before an app can time out from its 148 * current bucket to the next bucket. 149 */ 150 private static final long[] SCREEN_TIME_THRESHOLDS = { 151 0, 152 0, 153 COMPRESS_TIME ? 2 * ONE_MINUTE : 1 * ONE_HOUR, 154 COMPRESS_TIME ? 4 * ONE_MINUTE : 2 * ONE_HOUR, 155 COMPRESS_TIME ? 8 * ONE_MINUTE : 6 * ONE_HOUR 156 }; 157 158 /** The minimum allowed values for each index in {@link #SCREEN_TIME_THRESHOLDS}. */ 159 private static final long[] MINIMUM_SCREEN_TIME_THRESHOLDS = COMPRESS_TIME 160 ? new long[SCREEN_TIME_THRESHOLDS.length] 161 : new long[]{ 162 0, 163 0, 164 0, 165 30 * ONE_MINUTE, 166 ONE_HOUR 167 }; 168 169 /** 170 * The minimum amount of elapsed time that must have passed before an app can time out from its 171 * current bucket to the next bucket. 172 */ 173 private static final long[] ELAPSED_TIME_THRESHOLDS = { 174 0, 175 COMPRESS_TIME ? 1 * ONE_MINUTE : 12 * ONE_HOUR, 176 COMPRESS_TIME ? 4 * ONE_MINUTE : 24 * ONE_HOUR, 177 COMPRESS_TIME ? 16 * ONE_MINUTE : 48 * ONE_HOUR, 178 COMPRESS_TIME ? 32 * ONE_MINUTE : 30 * ONE_DAY 179 }; 180 181 /** The minimum allowed values for each index in {@link #ELAPSED_TIME_THRESHOLDS}. */ 182 private static final long[] MINIMUM_ELAPSED_TIME_THRESHOLDS = COMPRESS_TIME 183 ? new long[ELAPSED_TIME_THRESHOLDS.length] 184 : new long[]{ 185 0, 186 ONE_HOUR, 187 ONE_HOUR, 188 2 * ONE_HOUR, 189 4 * ONE_DAY 190 }; 191 192 private static final int[] THRESHOLD_BUCKETS = { 193 STANDBY_BUCKET_ACTIVE, 194 STANDBY_BUCKET_WORKING_SET, 195 STANDBY_BUCKET_FREQUENT, 196 STANDBY_BUCKET_RARE, 197 STANDBY_BUCKET_RESTRICTED 198 }; 199 200 /** Default expiration time for bucket prediction. After this, use thresholds to downgrade. */ 201 private static final long DEFAULT_PREDICTION_TIMEOUT = 12 * ONE_HOUR; 202 203 /** 204 * Indicates the maximum wait time for admin data to be available; 205 */ 206 private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000; 207 208 private static final int HEADLESS_APP_CHECK_FLAGS = 209 PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 210 | PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS; 211 212 // To name the lock for stack traces 213 static class Lock {} 214 215 /** Lock to protect the app's standby state. Required for calls into AppIdleHistory */ 216 private final Object mAppIdleLock = new Lock(); 217 218 /** Keeps the history and state for each app. */ 219 @GuardedBy("mAppIdleLock") 220 private AppIdleHistory mAppIdleHistory; 221 222 @GuardedBy("mPackageAccessListeners") 223 private final ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>(); 224 225 /** Whether we've queried the list of carrier privileged apps. */ 226 @GuardedBy("mAppIdleLock") 227 private boolean mHaveCarrierPrivilegedApps; 228 229 /** List of carrier-privileged apps that should be excluded from standby */ 230 @GuardedBy("mAppIdleLock") 231 private List<String> mCarrierPrivilegedApps; 232 233 @GuardedBy("mActiveAdminApps") 234 private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>(); 235 236 /** 237 * Set of system apps that are headless (don't have any declared activities, enabled or 238 * disabled). Presence in this map indicates that the app is a headless system app. 239 */ 240 @GuardedBy("mHeadlessSystemApps") 241 private final ArraySet<String> mHeadlessSystemApps = new ArraySet<>(); 242 243 private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1); 244 245 // Cache the active network scorer queried from the network scorer service 246 private volatile String mCachedNetworkScorer = null; 247 // The last time the network scorer service was queried 248 private volatile long mCachedNetworkScorerAtMillis = 0L; 249 // How long before querying the network scorer again. During this time, subsequent queries will 250 // get the cached value 251 private static final long NETWORK_SCORER_CACHE_DURATION_MILLIS = 5000L; 252 253 // Messages for the handler 254 static final int MSG_INFORM_LISTENERS = 3; 255 static final int MSG_FORCE_IDLE_STATE = 4; 256 static final int MSG_CHECK_IDLE_STATES = 5; 257 static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8; 258 static final int MSG_PAROLE_STATE_CHANGED = 9; 259 static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10; 260 /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */ 261 static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11; 262 static final int MSG_REPORT_SYNC_SCHEDULED = 12; 263 static final int MSG_REPORT_EXEMPTED_SYNC_START = 13; 264 265 long mCheckIdleIntervalMillis; 266 /** 267 * The minimum amount of time the screen must have been on before an app can time out from its 268 * current bucket to the next bucket. 269 */ 270 long[] mAppStandbyScreenThresholds = SCREEN_TIME_THRESHOLDS; 271 /** 272 * The minimum amount of elapsed time that must have passed before an app can time out from its 273 * current bucket to the next bucket. 274 */ 275 long[] mAppStandbyElapsedThresholds = ELAPSED_TIME_THRESHOLDS; 276 /** Minimum time a strong usage event should keep the bucket elevated. */ 277 long mStrongUsageTimeoutMillis; 278 /** Minimum time a notification seen event should keep the bucket elevated. */ 279 long mNotificationSeenTimeoutMillis; 280 /** Minimum time a system update event should keep the buckets elevated. */ 281 long mSystemUpdateUsageTimeoutMillis; 282 /** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */ 283 long mPredictionTimeoutMillis; 284 /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */ 285 long mSyncAdapterTimeoutMillis; 286 /** 287 * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in 288 * non-doze 289 */ 290 long mExemptedSyncScheduledNonDozeTimeoutMillis; 291 /** 292 * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in 293 * doze 294 */ 295 long mExemptedSyncScheduledDozeTimeoutMillis; 296 /** 297 * Maximum time an exempted sync should keep the buckets elevated, when sync is started. 298 */ 299 long mExemptedSyncStartTimeoutMillis; 300 /** 301 * Maximum time an unexempted sync should keep the buckets elevated, when sync is scheduled 302 */ 303 long mUnexemptedSyncScheduledTimeoutMillis; 304 /** Maximum time a system interaction should keep the buckets elevated. */ 305 long mSystemInteractionTimeoutMillis; 306 /** 307 * Maximum time a foreground service start should keep the buckets elevated if the service 308 * start is the first usage of the app 309 */ 310 long mInitialForegroundServiceStartTimeoutMillis; 311 /** 312 * User usage that would elevate an app's standby bucket will also elevate the standby bucket of 313 * cross profile connected apps. Explicit standby bucket setting via 314 * {@link #setAppStandbyBucket(String, int, int, int, int)} will not be propagated. 315 */ 316 boolean mLinkCrossProfileApps; 317 /** 318 * Whether we should allow apps into the 319 * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not. 320 * If false, any attempts to put an app into the bucket will put the app into the 321 * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RARE} bucket instead. 322 */ 323 private boolean mAllowRestrictedBucket; 324 325 private volatile boolean mAppIdleEnabled; 326 private boolean mIsCharging; 327 private boolean mSystemServicesReady = false; 328 // There was a system update, defaults need to be initialized after services are ready 329 private boolean mPendingInitializeDefaults; 330 331 private volatile boolean mPendingOneTimeCheckIdleStates; 332 333 private final AppStandbyHandler mHandler; 334 private final Context mContext; 335 336 private AppWidgetManager mAppWidgetManager; 337 private PackageManager mPackageManager; 338 Injector mInjector; 339 340 static final ArrayList<StandbyUpdateRecord> sStandbyUpdatePool = new ArrayList<>(4); 341 342 public static class StandbyUpdateRecord { 343 // Identity of the app whose standby state has changed 344 String packageName; 345 int userId; 346 347 // What the standby bucket the app is now in 348 int bucket; 349 350 // Whether the bucket change is because the user has started interacting with the app 351 boolean isUserInteraction; 352 353 // Reason for bucket change 354 int reason; 355 StandbyUpdateRecord(String pkgName, int userId, int bucket, int reason, boolean isInteraction)356 StandbyUpdateRecord(String pkgName, int userId, int bucket, int reason, 357 boolean isInteraction) { 358 this.packageName = pkgName; 359 this.userId = userId; 360 this.bucket = bucket; 361 this.reason = reason; 362 this.isUserInteraction = isInteraction; 363 } 364 obtain(String pkgName, int userId, int bucket, int reason, boolean isInteraction)365 public static StandbyUpdateRecord obtain(String pkgName, int userId, 366 int bucket, int reason, boolean isInteraction) { 367 synchronized (sStandbyUpdatePool) { 368 final int size = sStandbyUpdatePool.size(); 369 if (size < 1) { 370 return new StandbyUpdateRecord(pkgName, userId, bucket, reason, isInteraction); 371 } 372 StandbyUpdateRecord r = sStandbyUpdatePool.remove(size - 1); 373 r.packageName = pkgName; 374 r.userId = userId; 375 r.bucket = bucket; 376 r.reason = reason; 377 r.isUserInteraction = isInteraction; 378 return r; 379 } 380 } 381 recycle()382 public void recycle() { 383 synchronized (sStandbyUpdatePool) { 384 sStandbyUpdatePool.add(this); 385 } 386 } 387 } 388 AppStandbyController(Context context, Looper looper)389 public AppStandbyController(Context context, Looper looper) { 390 this(new Injector(context, looper)); 391 } 392 AppStandbyController(Injector injector)393 AppStandbyController(Injector injector) { 394 mInjector = injector; 395 mContext = mInjector.getContext(); 396 mHandler = new AppStandbyHandler(mInjector.getLooper()); 397 mPackageManager = mContext.getPackageManager(); 398 399 DeviceStateReceiver deviceStateReceiver = new DeviceStateReceiver(); 400 IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING); 401 deviceStates.addAction(BatteryManager.ACTION_DISCHARGING); 402 deviceStates.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED); 403 mContext.registerReceiver(deviceStateReceiver, deviceStates); 404 405 synchronized (mAppIdleLock) { 406 mAppIdleHistory = new AppIdleHistory(mInjector.getDataSystemDirectory(), 407 mInjector.elapsedRealtime()); 408 } 409 410 IntentFilter packageFilter = new IntentFilter(); 411 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 412 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 413 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 414 packageFilter.addDataScheme("package"); 415 416 mContext.registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter, 417 null, mHandler); 418 } 419 420 @VisibleForTesting setAppIdleEnabled(boolean enabled)421 void setAppIdleEnabled(boolean enabled) { 422 synchronized (mAppIdleLock) { 423 if (mAppIdleEnabled != enabled) { 424 final boolean oldParoleState = isInParole(); 425 mAppIdleEnabled = enabled; 426 if (isInParole() != oldParoleState) { 427 postParoleStateChanged(); 428 } 429 } 430 } 431 432 } 433 434 @Override isAppIdleEnabled()435 public boolean isAppIdleEnabled() { 436 return mAppIdleEnabled; 437 } 438 439 @Override onBootPhase(int phase)440 public void onBootPhase(int phase) { 441 mInjector.onBootPhase(phase); 442 if (phase == PHASE_SYSTEM_SERVICES_READY) { 443 Slog.d(TAG, "Setting app idle enabled state"); 444 // Observe changes to the threshold 445 SettingsObserver settingsObserver = new SettingsObserver(mHandler); 446 settingsObserver.registerObserver(); 447 settingsObserver.updateSettings(); 448 449 mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class); 450 451 mInjector.registerDisplayListener(mDisplayListener, mHandler); 452 synchronized (mAppIdleLock) { 453 mAppIdleHistory.updateDisplay(isDisplayOn(), mInjector.elapsedRealtime()); 454 } 455 456 mSystemServicesReady = true; 457 458 // Offload to handler thread to avoid boot time impact. 459 mHandler.post(AppStandbyController.this::updatePowerWhitelistCache); 460 461 boolean userFileExists; 462 synchronized (mAppIdleLock) { 463 userFileExists = mAppIdleHistory.userFileExists(UserHandle.USER_SYSTEM); 464 } 465 466 if (mPendingInitializeDefaults || !userFileExists) { 467 initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM); 468 } 469 470 if (mPendingOneTimeCheckIdleStates) { 471 postOneTimeCheckIdleStates(); 472 } 473 } else if (phase == PHASE_BOOT_COMPLETED) { 474 setChargingState(mInjector.isCharging()); 475 476 // Offload to handler thread after boot completed to avoid boot time impact. This means 477 // that headless system apps may be put in a lower bucket until boot has completed. 478 mHandler.post(this::loadHeadlessSystemAppCache); 479 } 480 } 481 reportContentProviderUsage(String authority, String providerPkgName, int userId)482 private void reportContentProviderUsage(String authority, String providerPkgName, int userId) { 483 if (!mAppIdleEnabled) return; 484 485 // Get sync adapters for the authority 486 String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser( 487 authority, userId); 488 final long elapsedRealtime = mInjector.elapsedRealtime(); 489 for (String packageName: packages) { 490 // Only force the sync adapters to active if the provider is not in the same package and 491 // the sync adapter is a system package. 492 try { 493 PackageInfo pi = mPackageManager.getPackageInfoAsUser( 494 packageName, PackageManager.MATCH_SYSTEM_ONLY, userId); 495 if (pi == null || pi.applicationInfo == null) { 496 continue; 497 } 498 if (!packageName.equals(providerPkgName)) { 499 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, 500 userId); 501 synchronized (mAppIdleLock) { 502 reportNoninteractiveUsageCrossUserLocked(packageName, userId, 503 STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER, 504 elapsedRealtime, mSyncAdapterTimeoutMillis, linkedProfiles); 505 } 506 } 507 } catch (PackageManager.NameNotFoundException e) { 508 // Shouldn't happen 509 } 510 } 511 } 512 reportExemptedSyncScheduled(String packageName, int userId)513 private void reportExemptedSyncScheduled(String packageName, int userId) { 514 if (!mAppIdleEnabled) return; 515 516 final int bucketToPromote; 517 final int usageReason; 518 final long durationMillis; 519 520 if (!mInjector.isDeviceIdleMode()) { 521 // Not dozing. 522 bucketToPromote = STANDBY_BUCKET_ACTIVE; 523 usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE; 524 durationMillis = mExemptedSyncScheduledNonDozeTimeoutMillis; 525 } else { 526 // Dozing. 527 bucketToPromote = STANDBY_BUCKET_WORKING_SET; 528 usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE; 529 durationMillis = mExemptedSyncScheduledDozeTimeoutMillis; 530 } 531 532 final long elapsedRealtime = mInjector.elapsedRealtime(); 533 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId); 534 synchronized (mAppIdleLock) { 535 reportNoninteractiveUsageCrossUserLocked(packageName, userId, bucketToPromote, 536 usageReason, elapsedRealtime, durationMillis, linkedProfiles); 537 } 538 } 539 reportUnexemptedSyncScheduled(String packageName, int userId)540 private void reportUnexemptedSyncScheduled(String packageName, int userId) { 541 if (!mAppIdleEnabled) return; 542 543 final long elapsedRealtime = mInjector.elapsedRealtime(); 544 synchronized (mAppIdleLock) { 545 final int currentBucket = 546 mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime); 547 if (currentBucket == STANDBY_BUCKET_NEVER) { 548 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId); 549 // Bring the app out of the never bucket 550 reportNoninteractiveUsageCrossUserLocked(packageName, userId, 551 STANDBY_BUCKET_WORKING_SET, REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED, 552 elapsedRealtime, mUnexemptedSyncScheduledTimeoutMillis, linkedProfiles); 553 } 554 } 555 } 556 reportExemptedSyncStart(String packageName, int userId)557 private void reportExemptedSyncStart(String packageName, int userId) { 558 if (!mAppIdleEnabled) return; 559 560 final long elapsedRealtime = mInjector.elapsedRealtime(); 561 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId); 562 synchronized (mAppIdleLock) { 563 reportNoninteractiveUsageCrossUserLocked(packageName, userId, STANDBY_BUCKET_ACTIVE, 564 REASON_SUB_USAGE_EXEMPTED_SYNC_START, elapsedRealtime, 565 mExemptedSyncStartTimeoutMillis, linkedProfiles); 566 } 567 } 568 569 /** 570 * Helper method to report indirect user usage of an app and handle reporting the usage 571 * against cross profile connected apps. <br> 572 * Use {@link #reportNoninteractiveUsageLocked(String, int, int, int, long, long)} if 573 * cross profile connected apps do not need to be handled. 574 */ reportNoninteractiveUsageCrossUserLocked(String packageName, int userId, int bucket, int subReason, long elapsedRealtime, long nextCheckDelay, List<UserHandle> otherProfiles)575 private void reportNoninteractiveUsageCrossUserLocked(String packageName, int userId, 576 int bucket, int subReason, long elapsedRealtime, long nextCheckDelay, 577 List<UserHandle> otherProfiles) { 578 reportNoninteractiveUsageLocked(packageName, userId, bucket, subReason, elapsedRealtime, 579 nextCheckDelay); 580 final int size = otherProfiles.size(); 581 for (int profileIndex = 0; profileIndex < size; profileIndex++) { 582 final int otherUserId = otherProfiles.get(profileIndex).getIdentifier(); 583 reportNoninteractiveUsageLocked(packageName, otherUserId, bucket, subReason, 584 elapsedRealtime, nextCheckDelay); 585 } 586 } 587 588 /** 589 * Helper method to report indirect user usage of an app. <br> 590 * Use 591 * {@link #reportNoninteractiveUsageCrossUserLocked(String, int, int, int, long, long, List)} 592 * if cross profile connected apps need to be handled. 593 */ reportNoninteractiveUsageLocked(String packageName, int userId, int bucket, int subReason, long elapsedRealtime, long nextCheckDelay)594 private void reportNoninteractiveUsageLocked(String packageName, int userId, int bucket, 595 int subReason, long elapsedRealtime, long nextCheckDelay) { 596 final AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, bucket, 597 subReason, 0, elapsedRealtime + nextCheckDelay); 598 mHandler.sendMessageDelayed( 599 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, packageName), 600 nextCheckDelay); 601 maybeInformListeners(packageName, userId, elapsedRealtime, appUsage.currentBucket, 602 appUsage.bucketingReason, false); 603 } 604 605 @VisibleForTesting setChargingState(boolean isCharging)606 void setChargingState(boolean isCharging) { 607 synchronized (mAppIdleLock) { 608 if (mIsCharging != isCharging) { 609 if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging); 610 mIsCharging = isCharging; 611 postParoleStateChanged(); 612 } 613 } 614 } 615 616 @Override isInParole()617 public boolean isInParole() { 618 return !mAppIdleEnabled || mIsCharging; 619 } 620 postParoleStateChanged()621 private void postParoleStateChanged() { 622 if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED"); 623 mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED); 624 mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED); 625 } 626 627 @Override postCheckIdleStates(int userId)628 public void postCheckIdleStates(int userId) { 629 mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0)); 630 } 631 632 @Override postOneTimeCheckIdleStates()633 public void postOneTimeCheckIdleStates() { 634 if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) { 635 // Not booted yet; wait for it! 636 mPendingOneTimeCheckIdleStates = true; 637 } else { 638 mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES); 639 mPendingOneTimeCheckIdleStates = false; 640 } 641 } 642 643 @VisibleForTesting checkIdleStates(int checkUserId)644 boolean checkIdleStates(int checkUserId) { 645 if (!mAppIdleEnabled) { 646 return false; 647 } 648 649 final int[] runningUserIds; 650 try { 651 runningUserIds = mInjector.getRunningUserIds(); 652 if (checkUserId != UserHandle.USER_ALL 653 && !ArrayUtils.contains(runningUserIds, checkUserId)) { 654 return false; 655 } 656 } catch (RemoteException re) { 657 throw re.rethrowFromSystemServer(); 658 } 659 660 final long elapsedRealtime = mInjector.elapsedRealtime(); 661 for (int i = 0; i < runningUserIds.length; i++) { 662 final int userId = runningUserIds[i]; 663 if (checkUserId != UserHandle.USER_ALL && checkUserId != userId) { 664 continue; 665 } 666 if (DEBUG) { 667 Slog.d(TAG, "Checking idle state for user " + userId); 668 } 669 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser( 670 PackageManager.MATCH_DISABLED_COMPONENTS, 671 userId); 672 final int packageCount = packages.size(); 673 for (int p = 0; p < packageCount; p++) { 674 final PackageInfo pi = packages.get(p); 675 final String packageName = pi.packageName; 676 checkAndUpdateStandbyState(packageName, userId, pi.applicationInfo.uid, 677 elapsedRealtime); 678 } 679 } 680 if (DEBUG) { 681 Slog.d(TAG, "checkIdleStates took " 682 + (mInjector.elapsedRealtime() - elapsedRealtime)); 683 } 684 return true; 685 } 686 687 /** Check if we need to update the standby state of a specific app. */ checkAndUpdateStandbyState(String packageName, @UserIdInt int userId, int uid, long elapsedRealtime)688 private void checkAndUpdateStandbyState(String packageName, @UserIdInt int userId, 689 int uid, long elapsedRealtime) { 690 if (uid <= 0) { 691 try { 692 uid = mPackageManager.getPackageUidAsUser(packageName, userId); 693 } catch (PackageManager.NameNotFoundException e) { 694 // Not a valid package for this user, nothing to do 695 // TODO: Remove any history of removed packages 696 return; 697 } 698 } 699 final int minBucket = getAppMinBucket(packageName, 700 UserHandle.getAppId(uid), 701 userId); 702 if (DEBUG) { 703 Slog.d(TAG, " Checking idle state for " + packageName 704 + " minBucket=" + minBucket); 705 } 706 if (minBucket <= STANDBY_BUCKET_ACTIVE) { 707 // No extra processing needed for ACTIVE or higher since apps can't drop into lower 708 // buckets. 709 synchronized (mAppIdleLock) { 710 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, 711 minBucket, REASON_MAIN_DEFAULT); 712 } 713 maybeInformListeners(packageName, userId, elapsedRealtime, 714 minBucket, REASON_MAIN_DEFAULT, false); 715 } else { 716 synchronized (mAppIdleLock) { 717 final AppIdleHistory.AppUsageHistory app = 718 mAppIdleHistory.getAppUsageHistory(packageName, 719 userId, elapsedRealtime); 720 int reason = app.bucketingReason; 721 final int oldMainReason = reason & REASON_MAIN_MASK; 722 723 // If the bucket was forced by the user/developer, leave it alone. 724 // A usage event will be the only way to bring it out of this forced state 725 if (oldMainReason == REASON_MAIN_FORCED_BY_USER) { 726 return; 727 } 728 final int oldBucket = app.currentBucket; 729 if (oldBucket == STANDBY_BUCKET_NEVER) { 730 // None of this should bring an app out of the NEVER bucket. 731 return; 732 } 733 int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED 734 boolean predictionLate = predictionTimedOut(app, elapsedRealtime); 735 // Compute age-based bucket 736 if (oldMainReason == REASON_MAIN_DEFAULT 737 || oldMainReason == REASON_MAIN_USAGE 738 || oldMainReason == REASON_MAIN_TIMEOUT 739 || predictionLate) { 740 741 if (!predictionLate && app.lastPredictedBucket >= STANDBY_BUCKET_ACTIVE 742 && app.lastPredictedBucket <= STANDBY_BUCKET_RARE) { 743 newBucket = app.lastPredictedBucket; 744 reason = REASON_MAIN_PREDICTED | REASON_SUB_PREDICTED_RESTORED; 745 if (DEBUG) { 746 Slog.d(TAG, "Restored predicted newBucket = " + newBucket); 747 } 748 } else { 749 newBucket = getBucketForLocked(packageName, userId, 750 elapsedRealtime); 751 if (DEBUG) { 752 Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket); 753 } 754 reason = REASON_MAIN_TIMEOUT; 755 } 756 } 757 758 // Check if the app is within one of the timeouts for forced bucket elevation 759 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime); 760 if (newBucket >= STANDBY_BUCKET_ACTIVE 761 && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) { 762 newBucket = STANDBY_BUCKET_ACTIVE; 763 reason = app.bucketingReason; 764 if (DEBUG) { 765 Slog.d(TAG, " Keeping at ACTIVE due to min timeout"); 766 } 767 } else if (newBucket >= STANDBY_BUCKET_WORKING_SET 768 && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) { 769 newBucket = STANDBY_BUCKET_WORKING_SET; 770 // If it was already there, keep the reason, else assume timeout to WS 771 reason = (newBucket == oldBucket) 772 ? app.bucketingReason 773 : REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT; 774 if (DEBUG) { 775 Slog.d(TAG, " Keeping at WORKING_SET due to min timeout"); 776 } 777 } 778 779 if (app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime 780 && elapsedTimeAdjusted - app.lastUsedByUserElapsedTime 781 >= mInjector.getAutoRestrictedBucketDelayMs()) { 782 newBucket = STANDBY_BUCKET_RESTRICTED; 783 reason = app.lastRestrictReason; 784 if (DEBUG) { 785 Slog.d(TAG, "Bringing down to RESTRICTED due to timeout"); 786 } 787 } 788 if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) { 789 newBucket = STANDBY_BUCKET_RARE; 790 // Leave the reason alone. 791 if (DEBUG) { 792 Slog.d(TAG, "Bringing up from RESTRICTED to RARE due to off switch"); 793 } 794 } 795 if (newBucket > minBucket) { 796 newBucket = minBucket; 797 // Leave the reason alone. 798 if (DEBUG) { 799 Slog.d(TAG, "Bringing up from " + newBucket + " to " + minBucket 800 + " due to min bucketing"); 801 } 802 } 803 if (DEBUG) { 804 Slog.d(TAG, " Old bucket=" + oldBucket 805 + ", newBucket=" + newBucket); 806 } 807 if (oldBucket != newBucket || predictionLate) { 808 mAppIdleHistory.setAppStandbyBucket(packageName, userId, 809 elapsedRealtime, newBucket, reason); 810 maybeInformListeners(packageName, userId, elapsedRealtime, 811 newBucket, reason, false); 812 } 813 } 814 } 815 } 816 817 /** Returns true if there hasn't been a prediction for the app in a while. */ predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime)818 private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) { 819 return app.lastPredictedTime > 0 820 && mAppIdleHistory.getElapsedTime(elapsedRealtime) 821 - app.lastPredictedTime > mPredictionTimeoutMillis; 822 } 823 824 /** Inform listeners if the bucket has changed since it was last reported to listeners */ maybeInformListeners(String packageName, int userId, long elapsedRealtime, int bucket, int reason, boolean userStartedInteracting)825 private void maybeInformListeners(String packageName, int userId, 826 long elapsedRealtime, int bucket, int reason, boolean userStartedInteracting) { 827 synchronized (mAppIdleLock) { 828 if (mAppIdleHistory.shouldInformListeners(packageName, userId, 829 elapsedRealtime, bucket)) { 830 final StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId, 831 bucket, reason, userStartedInteracting); 832 if (DEBUG) Slog.d(TAG, "Standby bucket for " + packageName + "=" + bucket); 833 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, r)); 834 } 835 } 836 } 837 838 /** 839 * Evaluates next bucket based on time since last used and the bucketing thresholds. 840 * @param packageName the app 841 * @param userId the user 842 * @param elapsedRealtime as the name suggests, current elapsed time 843 * @return the bucket for the app, based on time since last used 844 */ 845 @GuardedBy("mAppIdleLock") 846 @StandbyBuckets getBucketForLocked(String packageName, int userId, long elapsedRealtime)847 private int getBucketForLocked(String packageName, int userId, 848 long elapsedRealtime) { 849 int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId, 850 elapsedRealtime, mAppStandbyScreenThresholds, mAppStandbyElapsedThresholds); 851 return THRESHOLD_BUCKETS[bucketIndex]; 852 } 853 notifyBatteryStats(String packageName, int userId, boolean idle)854 private void notifyBatteryStats(String packageName, int userId, boolean idle) { 855 try { 856 final int uid = mPackageManager.getPackageUidAsUser(packageName, 857 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); 858 if (idle) { 859 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE, 860 packageName, uid); 861 } else { 862 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE, 863 packageName, uid); 864 } 865 } catch (PackageManager.NameNotFoundException | RemoteException e) { 866 } 867 } 868 869 @Override reportEvent(UsageEvents.Event event, int userId)870 public void reportEvent(UsageEvents.Event event, int userId) { 871 if (!mAppIdleEnabled) return; 872 final int eventType = event.getEventType(); 873 if ((eventType == UsageEvents.Event.ACTIVITY_RESUMED 874 || eventType == UsageEvents.Event.ACTIVITY_PAUSED 875 || eventType == UsageEvents.Event.SYSTEM_INTERACTION 876 || eventType == UsageEvents.Event.USER_INTERACTION 877 || eventType == UsageEvents.Event.NOTIFICATION_SEEN 878 || eventType == UsageEvents.Event.SLICE_PINNED 879 || eventType == UsageEvents.Event.SLICE_PINNED_PRIV 880 || eventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) { 881 final String pkg = event.getPackageName(); 882 final List<UserHandle> linkedProfiles = getCrossProfileTargets(pkg, userId); 883 synchronized (mAppIdleLock) { 884 final long elapsedRealtime = mInjector.elapsedRealtime(); 885 reportEventLocked(pkg, eventType, elapsedRealtime, userId); 886 887 final int size = linkedProfiles.size(); 888 for (int profileIndex = 0; profileIndex < size; profileIndex++) { 889 final int linkedUserId = linkedProfiles.get(profileIndex).getIdentifier(); 890 reportEventLocked(pkg, eventType, elapsedRealtime, linkedUserId); 891 } 892 } 893 } 894 } 895 reportEventLocked(String pkg, int eventType, long elapsedRealtime, int userId)896 private void reportEventLocked(String pkg, int eventType, long elapsedRealtime, int userId) { 897 // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back 898 // about apps that are on some kind of whitelist anyway. 899 final boolean previouslyIdle = mAppIdleHistory.isIdle( 900 pkg, userId, elapsedRealtime); 901 902 final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory( 903 pkg, userId, elapsedRealtime); 904 final int prevBucket = appHistory.currentBucket; 905 final int prevBucketReason = appHistory.bucketingReason; 906 final long nextCheckDelay; 907 final int subReason = usageEventToSubReason(eventType); 908 final int reason = REASON_MAIN_USAGE | subReason; 909 if (eventType == UsageEvents.Event.NOTIFICATION_SEEN 910 || eventType == UsageEvents.Event.SLICE_PINNED) { 911 // Mild usage elevates to WORKING_SET but doesn't change usage time. 912 mAppIdleHistory.reportUsage(appHistory, pkg, userId, 913 STANDBY_BUCKET_WORKING_SET, subReason, 914 0, elapsedRealtime + mNotificationSeenTimeoutMillis); 915 nextCheckDelay = mNotificationSeenTimeoutMillis; 916 } else if (eventType == UsageEvents.Event.SYSTEM_INTERACTION) { 917 mAppIdleHistory.reportUsage(appHistory, pkg, userId, 918 STANDBY_BUCKET_ACTIVE, subReason, 919 0, elapsedRealtime + mSystemInteractionTimeoutMillis); 920 nextCheckDelay = mSystemInteractionTimeoutMillis; 921 } else if (eventType == UsageEvents.Event.FOREGROUND_SERVICE_START) { 922 // Only elevate bucket if this is the first usage of the app 923 if (prevBucket != STANDBY_BUCKET_NEVER) return; 924 mAppIdleHistory.reportUsage(appHistory, pkg, userId, 925 STANDBY_BUCKET_ACTIVE, subReason, 926 0, elapsedRealtime + mInitialForegroundServiceStartTimeoutMillis); 927 nextCheckDelay = mInitialForegroundServiceStartTimeoutMillis; 928 } else { 929 mAppIdleHistory.reportUsage(appHistory, pkg, userId, 930 STANDBY_BUCKET_ACTIVE, subReason, 931 elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis); 932 nextCheckDelay = mStrongUsageTimeoutMillis; 933 } 934 if (appHistory.currentBucket != prevBucket) { 935 mHandler.sendMessageDelayed( 936 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkg), 937 nextCheckDelay); 938 final boolean userStartedInteracting = 939 appHistory.currentBucket == STANDBY_BUCKET_ACTIVE 940 && (prevBucketReason & REASON_MAIN_MASK) != REASON_MAIN_USAGE; 941 maybeInformListeners(pkg, userId, elapsedRealtime, 942 appHistory.currentBucket, reason, userStartedInteracting); 943 } 944 945 if (previouslyIdle) { 946 notifyBatteryStats(pkg, userId, false); 947 } 948 } 949 950 /** 951 * Note: don't call this with the lock held since it makes calls to other system services. 952 */ getCrossProfileTargets(String pkg, int userId)953 private @NonNull List<UserHandle> getCrossProfileTargets(String pkg, int userId) { 954 synchronized (mAppIdleLock) { 955 if (!mLinkCrossProfileApps) return Collections.emptyList(); 956 } 957 return mInjector.getValidCrossProfileTargets(pkg, userId); 958 } 959 usageEventToSubReason(int eventType)960 private int usageEventToSubReason(int eventType) { 961 switch (eventType) { 962 case UsageEvents.Event.ACTIVITY_RESUMED: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND; 963 case UsageEvents.Event.ACTIVITY_PAUSED: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND; 964 case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION; 965 case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION; 966 case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN; 967 case UsageEvents.Event.SLICE_PINNED: return REASON_SUB_USAGE_SLICE_PINNED; 968 case UsageEvents.Event.SLICE_PINNED_PRIV: return REASON_SUB_USAGE_SLICE_PINNED_PRIV; 969 case UsageEvents.Event.FOREGROUND_SERVICE_START: 970 return REASON_SUB_USAGE_FOREGROUND_SERVICE_START; 971 default: return 0; 972 } 973 } 974 975 @VisibleForTesting forceIdleState(String packageName, int userId, boolean idle)976 void forceIdleState(String packageName, int userId, boolean idle) { 977 if (!mAppIdleEnabled) return; 978 979 final int appId = getAppId(packageName); 980 if (appId < 0) return; 981 final long elapsedRealtime = mInjector.elapsedRealtime(); 982 983 final boolean previouslyIdle = isAppIdleFiltered(packageName, appId, 984 userId, elapsedRealtime); 985 final int standbyBucket; 986 synchronized (mAppIdleLock) { 987 standbyBucket = mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime); 988 } 989 final boolean stillIdle = isAppIdleFiltered(packageName, appId, 990 userId, elapsedRealtime); 991 // Inform listeners if necessary 992 if (previouslyIdle != stillIdle) { 993 maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket, 994 REASON_MAIN_FORCED_BY_USER, false); 995 if (!stillIdle) { 996 notifyBatteryStats(packageName, userId, idle); 997 } 998 } 999 } 1000 1001 @Override setLastJobRunTime(String packageName, int userId, long elapsedRealtime)1002 public void setLastJobRunTime(String packageName, int userId, long elapsedRealtime) { 1003 synchronized (mAppIdleLock) { 1004 mAppIdleHistory.setLastJobRunTime(packageName, userId, elapsedRealtime); 1005 } 1006 } 1007 1008 @Override getTimeSinceLastJobRun(String packageName, int userId)1009 public long getTimeSinceLastJobRun(String packageName, int userId) { 1010 final long elapsedRealtime = mInjector.elapsedRealtime(); 1011 synchronized (mAppIdleLock) { 1012 return mAppIdleHistory.getTimeSinceLastJobRun(packageName, userId, elapsedRealtime); 1013 } 1014 } 1015 1016 @Override onUserRemoved(int userId)1017 public void onUserRemoved(int userId) { 1018 synchronized (mAppIdleLock) { 1019 mAppIdleHistory.onUserRemoved(userId); 1020 synchronized (mActiveAdminApps) { 1021 mActiveAdminApps.remove(userId); 1022 } 1023 } 1024 } 1025 isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime)1026 private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) { 1027 synchronized (mAppIdleLock) { 1028 return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime); 1029 } 1030 } 1031 1032 @Override addListener(AppIdleStateChangeListener listener)1033 public void addListener(AppIdleStateChangeListener listener) { 1034 synchronized (mPackageAccessListeners) { 1035 if (!mPackageAccessListeners.contains(listener)) { 1036 mPackageAccessListeners.add(listener); 1037 } 1038 } 1039 } 1040 1041 @Override removeListener(AppIdleStateChangeListener listener)1042 public void removeListener(AppIdleStateChangeListener listener) { 1043 synchronized (mPackageAccessListeners) { 1044 mPackageAccessListeners.remove(listener); 1045 } 1046 } 1047 1048 @Override getAppId(String packageName)1049 public int getAppId(String packageName) { 1050 try { 1051 ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName, 1052 PackageManager.MATCH_ANY_USER 1053 | PackageManager.MATCH_DISABLED_COMPONENTS); 1054 return ai.uid; 1055 } catch (PackageManager.NameNotFoundException re) { 1056 return -1; 1057 } 1058 } 1059 1060 @Override isAppIdleFiltered(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps)1061 public boolean isAppIdleFiltered(String packageName, int userId, long elapsedRealtime, 1062 boolean shouldObfuscateInstantApps) { 1063 if (shouldObfuscateInstantApps && 1064 mInjector.isPackageEphemeral(userId, packageName)) { 1065 return false; 1066 } 1067 return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime); 1068 } 1069 1070 @StandbyBuckets getAppMinBucket(String packageName, int userId)1071 private int getAppMinBucket(String packageName, int userId) { 1072 try { 1073 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId); 1074 return getAppMinBucket(packageName, UserHandle.getAppId(uid), userId); 1075 } catch (PackageManager.NameNotFoundException e) { 1076 // Not a valid package for this user, nothing to do 1077 return STANDBY_BUCKET_NEVER; 1078 } 1079 } 1080 1081 /** 1082 * Return the lowest bucket this app should ever enter. 1083 */ 1084 @StandbyBuckets getAppMinBucket(String packageName, int appId, int userId)1085 private int getAppMinBucket(String packageName, int appId, int userId) { 1086 if (packageName == null) return STANDBY_BUCKET_NEVER; 1087 // If not enabled at all, of course nobody is ever idle. 1088 if (!mAppIdleEnabled) { 1089 return STANDBY_BUCKET_EXEMPTED; 1090 } 1091 if (appId < Process.FIRST_APPLICATION_UID) { 1092 // System uids never go idle. 1093 return STANDBY_BUCKET_EXEMPTED; 1094 } 1095 if (packageName.equals("android")) { 1096 // Nor does the framework (which should be redundant with the above, but for MR1 we will 1097 // retain this for safety). 1098 return STANDBY_BUCKET_EXEMPTED; 1099 } 1100 if (mSystemServicesReady) { 1101 // We allow all whitelisted apps, including those that don't want to be whitelisted 1102 // for idle mode, because app idle (aka app standby) is really not as big an issue 1103 // for controlling who participates vs. doze mode. 1104 if (mInjector.isNonIdleWhitelisted(packageName)) { 1105 return STANDBY_BUCKET_EXEMPTED; 1106 } 1107 1108 if (isActiveDeviceAdmin(packageName, userId)) { 1109 return STANDBY_BUCKET_EXEMPTED; 1110 } 1111 1112 if (isActiveNetworkScorer(packageName)) { 1113 return STANDBY_BUCKET_EXEMPTED; 1114 } 1115 1116 if (mAppWidgetManager != null 1117 && mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) { 1118 return STANDBY_BUCKET_ACTIVE; 1119 } 1120 1121 if (isDeviceProvisioningPackage(packageName)) { 1122 return STANDBY_BUCKET_EXEMPTED; 1123 } 1124 } 1125 1126 // Check this last, as it can be the most expensive check 1127 if (isCarrierApp(packageName)) { 1128 return STANDBY_BUCKET_EXEMPTED; 1129 } 1130 1131 if (isHeadlessSystemApp(packageName)) { 1132 return STANDBY_BUCKET_ACTIVE; 1133 } 1134 1135 return STANDBY_BUCKET_NEVER; 1136 } 1137 isHeadlessSystemApp(String packageName)1138 private boolean isHeadlessSystemApp(String packageName) { 1139 synchronized (mHeadlessSystemApps) { 1140 return mHeadlessSystemApps.contains(packageName); 1141 } 1142 } 1143 1144 @Override isAppIdleFiltered(String packageName, int appId, int userId, long elapsedRealtime)1145 public boolean isAppIdleFiltered(String packageName, int appId, int userId, 1146 long elapsedRealtime) { 1147 if (getAppMinBucket(packageName, appId, userId) < AppIdleHistory.IDLE_BUCKET_CUTOFF) { 1148 return false; 1149 } else { 1150 synchronized (mAppIdleLock) { 1151 if (!mAppIdleEnabled || mIsCharging) { 1152 return false; 1153 } 1154 } 1155 return isAppIdleUnfiltered(packageName, userId, elapsedRealtime); 1156 } 1157 } 1158 isUserUsage(int reason)1159 static boolean isUserUsage(int reason) { 1160 if ((reason & REASON_MAIN_MASK) == REASON_MAIN_USAGE) { 1161 final int subReason = reason & REASON_SUB_MASK; 1162 return subReason == REASON_SUB_USAGE_USER_INTERACTION 1163 || subReason == REASON_SUB_USAGE_MOVE_TO_FOREGROUND; 1164 } 1165 return false; 1166 } 1167 1168 @Override getIdleUidsForUser(int userId)1169 public int[] getIdleUidsForUser(int userId) { 1170 if (!mAppIdleEnabled) { 1171 return new int[0]; 1172 } 1173 1174 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "getIdleUidsForUser"); 1175 1176 final long elapsedRealtime = mInjector.elapsedRealtime(); 1177 1178 List<ApplicationInfo> apps; 1179 try { 1180 ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager() 1181 .getInstalledApplications(/* flags= */ 0, userId); 1182 if (slice == null) { 1183 return new int[0]; 1184 } 1185 apps = slice.getList(); 1186 } catch (RemoteException e) { 1187 throw e.rethrowFromSystemServer(); 1188 } 1189 1190 // State of each uid. Key is the uid. Value lower 16 bits is the number of apps 1191 // associated with that uid, upper 16 bits is the number of those apps that is idle. 1192 SparseIntArray uidStates = new SparseIntArray(); 1193 1194 // Now resolve all app state. Iterating over all apps, keeping track of how many 1195 // we find for each uid and how many of those are idle. 1196 for (int i = apps.size() - 1; i >= 0; i--) { 1197 ApplicationInfo ai = apps.get(i); 1198 1199 // Check whether this app is idle. 1200 boolean idle = isAppIdleFiltered(ai.packageName, UserHandle.getAppId(ai.uid), 1201 userId, elapsedRealtime); 1202 1203 int index = uidStates.indexOfKey(ai.uid); 1204 if (index < 0) { 1205 uidStates.put(ai.uid, 1 + (idle ? 1<<16 : 0)); 1206 } else { 1207 int value = uidStates.valueAt(index); 1208 uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0)); 1209 } 1210 } 1211 1212 if (DEBUG) { 1213 Slog.d(TAG, "getIdleUids took " + (mInjector.elapsedRealtime() - elapsedRealtime)); 1214 } 1215 int numIdle = 0; 1216 for (int i = uidStates.size() - 1; i >= 0; i--) { 1217 int value = uidStates.valueAt(i); 1218 if ((value&0x7fff) == (value>>16)) { 1219 numIdle++; 1220 } 1221 } 1222 1223 int[] res = new int[numIdle]; 1224 numIdle = 0; 1225 for (int i = uidStates.size() - 1; i >= 0; i--) { 1226 int value = uidStates.valueAt(i); 1227 if ((value&0x7fff) == (value>>16)) { 1228 res[numIdle] = uidStates.keyAt(i); 1229 numIdle++; 1230 } 1231 } 1232 1233 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 1234 1235 return res; 1236 } 1237 1238 @Override setAppIdleAsync(String packageName, boolean idle, int userId)1239 public void setAppIdleAsync(String packageName, boolean idle, int userId) { 1240 if (packageName == null || !mAppIdleEnabled) return; 1241 1242 mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName) 1243 .sendToTarget(); 1244 } 1245 1246 @Override getAppStandbyBucket(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps)1247 @StandbyBuckets public int getAppStandbyBucket(String packageName, int userId, 1248 long elapsedRealtime, boolean shouldObfuscateInstantApps) { 1249 if (!mAppIdleEnabled || (shouldObfuscateInstantApps 1250 && mInjector.isPackageEphemeral(userId, packageName))) { 1251 return STANDBY_BUCKET_ACTIVE; 1252 } 1253 1254 synchronized (mAppIdleLock) { 1255 return mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime); 1256 } 1257 } 1258 1259 @VisibleForTesting getAppStandbyBucketReason(String packageName, int userId, long elapsedRealtime)1260 int getAppStandbyBucketReason(String packageName, int userId, long elapsedRealtime) { 1261 synchronized (mAppIdleLock) { 1262 return mAppIdleHistory.getAppStandbyReason(packageName, userId, elapsedRealtime); 1263 } 1264 } 1265 1266 @Override getAppStandbyBuckets(int userId)1267 public List<AppStandbyInfo> getAppStandbyBuckets(int userId) { 1268 synchronized (mAppIdleLock) { 1269 return mAppIdleHistory.getAppStandbyBuckets(userId, mAppIdleEnabled); 1270 } 1271 } 1272 1273 @Override restrictApp(@onNull String packageName, int userId, @SystemForcedReasons int restrictReason)1274 public void restrictApp(@NonNull String packageName, int userId, 1275 @SystemForcedReasons int restrictReason) { 1276 // If the package is not installed, don't allow the bucket to be set. 1277 if (!mInjector.isPackageInstalled(packageName, 0, userId)) { 1278 Slog.e(TAG, "Tried to restrict uninstalled app: " + packageName); 1279 return; 1280 } 1281 1282 final int reason = REASON_MAIN_FORCED_BY_SYSTEM | (REASON_SUB_MASK & restrictReason); 1283 final long nowElapsed = mInjector.elapsedRealtime(); 1284 final int bucket = mAllowRestrictedBucket ? STANDBY_BUCKET_RESTRICTED : STANDBY_BUCKET_RARE; 1285 setAppStandbyBucket(packageName, userId, bucket, reason, nowElapsed, false); 1286 } 1287 1288 @Override setAppStandbyBucket(@onNull String packageName, int bucket, int userId, int callingUid, int callingPid)1289 public void setAppStandbyBucket(@NonNull String packageName, int bucket, int userId, 1290 int callingUid, int callingPid) { 1291 setAppStandbyBuckets( 1292 Collections.singletonList(new AppStandbyInfo(packageName, bucket)), 1293 userId, callingUid, callingPid); 1294 } 1295 1296 @Override setAppStandbyBuckets(@onNull List<AppStandbyInfo> appBuckets, int userId, int callingUid, int callingPid)1297 public void setAppStandbyBuckets(@NonNull List<AppStandbyInfo> appBuckets, int userId, 1298 int callingUid, int callingPid) { 1299 userId = ActivityManager.handleIncomingUser( 1300 callingPid, callingUid, userId, false, true, "setAppStandbyBucket", null); 1301 final boolean shellCaller = callingUid == Process.ROOT_UID 1302 || callingUid == Process.SHELL_UID; 1303 final int reason; 1304 // The Settings app runs in the system UID but in a separate process. Assume 1305 // things coming from other processes are due to the user. 1306 if ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && callingPid != Process.myPid()) 1307 || shellCaller) { 1308 reason = REASON_MAIN_FORCED_BY_USER; 1309 } else if (UserHandle.isCore(callingUid)) { 1310 reason = REASON_MAIN_FORCED_BY_SYSTEM; 1311 } else { 1312 reason = REASON_MAIN_PREDICTED; 1313 } 1314 final int packageFlags = PackageManager.MATCH_ANY_USER 1315 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 1316 | PackageManager.MATCH_DIRECT_BOOT_AWARE; 1317 final int numApps = appBuckets.size(); 1318 final long elapsedRealtime = mInjector.elapsedRealtime(); 1319 for (int i = 0; i < numApps; ++i) { 1320 final AppStandbyInfo bucketInfo = appBuckets.get(i); 1321 final String packageName = bucketInfo.mPackageName; 1322 final int bucket = bucketInfo.mStandbyBucket; 1323 if (bucket < STANDBY_BUCKET_ACTIVE || bucket > STANDBY_BUCKET_NEVER) { 1324 throw new IllegalArgumentException("Cannot set the standby bucket to " + bucket); 1325 } 1326 final int packageUid = mInjector.getPackageManagerInternal() 1327 .getPackageUid(packageName, packageFlags, userId); 1328 // Caller cannot set their own standby state 1329 if (packageUid == callingUid) { 1330 throw new IllegalArgumentException("Cannot set your own standby bucket"); 1331 } 1332 if (packageUid < 0) { 1333 throw new IllegalArgumentException( 1334 "Cannot set standby bucket for non existent package (" + packageName + ")"); 1335 } 1336 setAppStandbyBucket(packageName, userId, bucket, reason, elapsedRealtime, shellCaller); 1337 } 1338 } 1339 1340 @VisibleForTesting setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason)1341 void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, 1342 int reason) { 1343 setAppStandbyBucket( 1344 packageName, userId, newBucket, reason, mInjector.elapsedRealtime(), false); 1345 } 1346 setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime, boolean resetTimeout)1347 private void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, 1348 int reason, long elapsedRealtime, boolean resetTimeout) { 1349 if (!mAppIdleEnabled) return; 1350 1351 synchronized (mAppIdleLock) { 1352 // If the package is not installed, don't allow the bucket to be set. 1353 if (!mInjector.isPackageInstalled(packageName, 0, userId)) { 1354 Slog.e(TAG, "Tried to set bucket of uninstalled app: " + packageName); 1355 return; 1356 } 1357 if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) { 1358 newBucket = STANDBY_BUCKET_RARE; 1359 } 1360 AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName, 1361 userId, elapsedRealtime); 1362 boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED; 1363 1364 // Don't allow changing bucket if higher than ACTIVE 1365 if (app.currentBucket < STANDBY_BUCKET_ACTIVE) return; 1366 1367 // Don't allow prediction to change from/to NEVER. 1368 if ((app.currentBucket == STANDBY_BUCKET_NEVER || newBucket == STANDBY_BUCKET_NEVER) 1369 && predicted) { 1370 return; 1371 } 1372 1373 final boolean wasForcedBySystem = 1374 (app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM; 1375 1376 // If the bucket was forced, don't allow prediction to override 1377 if (predicted 1378 && ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER 1379 || wasForcedBySystem)) { 1380 return; 1381 } 1382 1383 final boolean isForcedBySystem = 1384 (reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM; 1385 1386 if (app.currentBucket == newBucket && wasForcedBySystem && isForcedBySystem) { 1387 mAppIdleHistory 1388 .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason); 1389 // Keep track of all restricting reasons 1390 reason = REASON_MAIN_FORCED_BY_SYSTEM 1391 | (app.bucketingReason & REASON_SUB_MASK) 1392 | (reason & REASON_SUB_MASK); 1393 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, 1394 newBucket, reason, resetTimeout); 1395 return; 1396 } 1397 1398 final boolean isForcedByUser = 1399 (reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER; 1400 1401 if (app.currentBucket == STANDBY_BUCKET_RESTRICTED) { 1402 if ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_TIMEOUT) { 1403 if (predicted && newBucket >= STANDBY_BUCKET_RARE) { 1404 // Predicting into RARE or below means we don't expect the user to use the 1405 // app anytime soon, so don't elevate it from RESTRICTED. 1406 return; 1407 } 1408 } else if (!isUserUsage(reason) && !isForcedByUser) { 1409 // If the current bucket is RESTRICTED, only user force or usage should bring 1410 // it out, unless the app was put into the bucket due to timing out. 1411 return; 1412 } 1413 } 1414 1415 if (newBucket == STANDBY_BUCKET_RESTRICTED) { 1416 mAppIdleHistory 1417 .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason); 1418 1419 if (isForcedByUser) { 1420 // Only user force can bypass the delay restriction. If the user forced the 1421 // app into the RESTRICTED bucket, then a toast confirming the action 1422 // shouldn't be surprising. 1423 if (Build.IS_DEBUGGABLE) { 1424 Toast.makeText(mContext, 1425 // Since AppStandbyController sits low in the lock hierarchy, 1426 // make sure not to call out with the lock held. 1427 mHandler.getLooper(), 1428 mContext.getResources().getString( 1429 R.string.as_app_forced_to_restricted_bucket, packageName), 1430 Toast.LENGTH_SHORT) 1431 .show(); 1432 } else { 1433 Slog.i(TAG, packageName + " restricted by user"); 1434 } 1435 } else { 1436 final long timeUntilRestrictPossibleMs = app.lastUsedByUserElapsedTime 1437 + mInjector.getAutoRestrictedBucketDelayMs() - elapsedRealtime; 1438 if (timeUntilRestrictPossibleMs > 0) { 1439 Slog.w(TAG, "Tried to restrict recently used app: " + packageName 1440 + " due to " + reason); 1441 mHandler.sendMessageDelayed( 1442 mHandler.obtainMessage( 1443 MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, packageName), 1444 timeUntilRestrictPossibleMs); 1445 return; 1446 } 1447 } 1448 } 1449 1450 // If the bucket is required to stay in a higher state for a specified duration, don't 1451 // override unless the duration has passed 1452 if (predicted) { 1453 // Check if the app is within one of the timeouts for forced bucket elevation 1454 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime); 1455 // In case of not using the prediction, just keep track of it for applying after 1456 // ACTIVE or WORKING_SET timeout. 1457 mAppIdleHistory.updateLastPrediction(app, elapsedTimeAdjusted, newBucket); 1458 1459 if (newBucket > STANDBY_BUCKET_ACTIVE 1460 && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) { 1461 newBucket = STANDBY_BUCKET_ACTIVE; 1462 reason = app.bucketingReason; 1463 if (DEBUG) { 1464 Slog.d(TAG, " Keeping at ACTIVE due to min timeout"); 1465 } 1466 } else if (newBucket > STANDBY_BUCKET_WORKING_SET 1467 && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) { 1468 newBucket = STANDBY_BUCKET_WORKING_SET; 1469 if (app.currentBucket != newBucket) { 1470 reason = REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT; 1471 } else { 1472 reason = app.bucketingReason; 1473 } 1474 if (DEBUG) { 1475 Slog.d(TAG, " Keeping at WORKING_SET due to min timeout"); 1476 } 1477 } else if (newBucket == STANDBY_BUCKET_RARE 1478 && mAllowRestrictedBucket 1479 && getBucketForLocked(packageName, userId, elapsedRealtime) 1480 == STANDBY_BUCKET_RESTRICTED) { 1481 // Prediction doesn't think the app will be used anytime soon and 1482 // it's been long enough that it could just time out into restricted, 1483 // so time it out there instead. Using TIMEOUT will allow prediction 1484 // to raise the bucket when it needs to. 1485 newBucket = STANDBY_BUCKET_RESTRICTED; 1486 reason = REASON_MAIN_TIMEOUT; 1487 if (DEBUG) { 1488 Slog.d(TAG, 1489 "Prediction to RARE overridden by timeout into RESTRICTED"); 1490 } 1491 } 1492 } 1493 1494 // Make sure we don't put the app in a lower bucket than it's supposed to be in. 1495 newBucket = Math.min(newBucket, getAppMinBucket(packageName, userId)); 1496 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, 1497 reason, resetTimeout); 1498 } 1499 maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, reason, false); 1500 } 1501 1502 @VisibleForTesting isActiveDeviceAdmin(String packageName, int userId)1503 boolean isActiveDeviceAdmin(String packageName, int userId) { 1504 synchronized (mActiveAdminApps) { 1505 final Set<String> adminPkgs = mActiveAdminApps.get(userId); 1506 return adminPkgs != null && adminPkgs.contains(packageName); 1507 } 1508 } 1509 1510 @Override addActiveDeviceAdmin(String adminPkg, int userId)1511 public void addActiveDeviceAdmin(String adminPkg, int userId) { 1512 synchronized (mActiveAdminApps) { 1513 Set<String> adminPkgs = mActiveAdminApps.get(userId); 1514 if (adminPkgs == null) { 1515 adminPkgs = new ArraySet<>(); 1516 mActiveAdminApps.put(userId, adminPkgs); 1517 } 1518 adminPkgs.add(adminPkg); 1519 } 1520 } 1521 1522 @Override setActiveAdminApps(Set<String> adminPkgs, int userId)1523 public void setActiveAdminApps(Set<String> adminPkgs, int userId) { 1524 synchronized (mActiveAdminApps) { 1525 if (adminPkgs == null) { 1526 mActiveAdminApps.remove(userId); 1527 } else { 1528 mActiveAdminApps.put(userId, adminPkgs); 1529 } 1530 } 1531 } 1532 1533 @Override onAdminDataAvailable()1534 public void onAdminDataAvailable() { 1535 mAdminDataAvailableLatch.countDown(); 1536 } 1537 1538 /** 1539 * This will only ever be called once - during device boot. 1540 */ waitForAdminData()1541 private void waitForAdminData() { 1542 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) { 1543 ConcurrentUtils.waitForCountDownNoInterrupt(mAdminDataAvailableLatch, 1544 WAIT_FOR_ADMIN_DATA_TIMEOUT_MS, "Wait for admin data"); 1545 } 1546 } 1547 1548 @VisibleForTesting getActiveAdminAppsForTest(int userId)1549 Set<String> getActiveAdminAppsForTest(int userId) { 1550 synchronized (mActiveAdminApps) { 1551 return mActiveAdminApps.get(userId); 1552 } 1553 } 1554 1555 /** 1556 * Returns {@code true} if the supplied package is the device provisioning app. Otherwise, 1557 * returns {@code false}. 1558 */ isDeviceProvisioningPackage(String packageName)1559 private boolean isDeviceProvisioningPackage(String packageName) { 1560 String deviceProvisioningPackage = mContext.getResources().getString( 1561 com.android.internal.R.string.config_deviceProvisioningPackage); 1562 return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName); 1563 } 1564 isCarrierApp(String packageName)1565 private boolean isCarrierApp(String packageName) { 1566 synchronized (mAppIdleLock) { 1567 if (!mHaveCarrierPrivilegedApps) { 1568 fetchCarrierPrivilegedAppsLocked(); 1569 } 1570 if (mCarrierPrivilegedApps != null) { 1571 return mCarrierPrivilegedApps.contains(packageName); 1572 } 1573 return false; 1574 } 1575 } 1576 1577 @Override clearCarrierPrivilegedApps()1578 public void clearCarrierPrivilegedApps() { 1579 if (DEBUG) { 1580 Slog.i(TAG, "Clearing carrier privileged apps list"); 1581 } 1582 synchronized (mAppIdleLock) { 1583 mHaveCarrierPrivilegedApps = false; 1584 mCarrierPrivilegedApps = null; // Need to be refetched. 1585 } 1586 } 1587 1588 @GuardedBy("mAppIdleLock") fetchCarrierPrivilegedAppsLocked()1589 private void fetchCarrierPrivilegedAppsLocked() { 1590 TelephonyManager telephonyManager = 1591 mContext.getSystemService(TelephonyManager.class); 1592 mCarrierPrivilegedApps = 1593 telephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions(); 1594 mHaveCarrierPrivilegedApps = true; 1595 if (DEBUG) { 1596 Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps); 1597 } 1598 } 1599 isActiveNetworkScorer(String packageName)1600 private boolean isActiveNetworkScorer(String packageName) { 1601 // Validity of network scorer cache is limited to a few seconds. Fetch it again 1602 // if longer since query. 1603 // This is a temporary optimization until there's a callback mechanism for changes to network scorer. 1604 final long now = SystemClock.elapsedRealtime(); 1605 if (mCachedNetworkScorer == null 1606 || mCachedNetworkScorerAtMillis < now - NETWORK_SCORER_CACHE_DURATION_MILLIS) { 1607 mCachedNetworkScorer = mInjector.getActiveNetworkScorer(); 1608 mCachedNetworkScorerAtMillis = now; 1609 } 1610 return packageName != null && packageName.equals(mCachedNetworkScorer); 1611 } 1612 informListeners(String packageName, int userId, int bucket, int reason, boolean userInteraction)1613 private void informListeners(String packageName, int userId, int bucket, int reason, 1614 boolean userInteraction) { 1615 final boolean idle = bucket >= STANDBY_BUCKET_RARE; 1616 synchronized (mPackageAccessListeners) { 1617 for (AppIdleStateChangeListener listener : mPackageAccessListeners) { 1618 listener.onAppIdleStateChanged(packageName, userId, idle, bucket, reason); 1619 if (userInteraction) { 1620 listener.onUserInteractionStarted(packageName, userId); 1621 } 1622 } 1623 } 1624 } 1625 informParoleStateChanged()1626 private void informParoleStateChanged() { 1627 final boolean paroled = isInParole(); 1628 synchronized (mPackageAccessListeners) { 1629 for (AppIdleStateChangeListener listener : mPackageAccessListeners) { 1630 listener.onParoleStateChanged(paroled); 1631 } 1632 } 1633 } 1634 1635 1636 @Override flushToDisk()1637 public void flushToDisk() { 1638 synchronized (mAppIdleLock) { 1639 mAppIdleHistory.writeAppIdleTimes(); 1640 mAppIdleHistory.writeAppIdleDurations(); 1641 } 1642 } 1643 isDisplayOn()1644 private boolean isDisplayOn() { 1645 return mInjector.isDefaultDisplayOn(); 1646 } 1647 1648 @VisibleForTesting clearAppIdleForPackage(String packageName, int userId)1649 void clearAppIdleForPackage(String packageName, int userId) { 1650 synchronized (mAppIdleLock) { 1651 mAppIdleHistory.clearUsage(packageName, userId); 1652 } 1653 } 1654 1655 /** 1656 * Remove an app from the {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} 1657 * bucket if it was forced into the bucket by the system because it was buggy. 1658 */ 1659 @VisibleForTesting maybeUnrestrictBuggyApp(String packageName, int userId)1660 void maybeUnrestrictBuggyApp(String packageName, int userId) { 1661 synchronized (mAppIdleLock) { 1662 final long elapsedRealtime = mInjector.elapsedRealtime(); 1663 final AppIdleHistory.AppUsageHistory app = 1664 mAppIdleHistory.getAppUsageHistory(packageName, userId, elapsedRealtime); 1665 if (app.currentBucket != STANDBY_BUCKET_RESTRICTED 1666 || (app.bucketingReason & REASON_MAIN_MASK) != REASON_MAIN_FORCED_BY_SYSTEM) { 1667 return; 1668 } 1669 1670 final int newBucket; 1671 final int newReason; 1672 if ((app.bucketingReason & REASON_SUB_MASK) == REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY) { 1673 // If bugginess was the only reason the app should be restricted, then lift it out. 1674 newBucket = STANDBY_BUCKET_RARE; 1675 newReason = REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_APP_UPDATE; 1676 } else { 1677 // There's another reason the app was restricted. Remove the buggy bit and call 1678 // it a day. 1679 newBucket = STANDBY_BUCKET_RESTRICTED; 1680 newReason = app.bucketingReason & ~REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY; 1681 } 1682 mAppIdleHistory.setAppStandbyBucket( 1683 packageName, userId, elapsedRealtime, newBucket, newReason); 1684 } 1685 } 1686 updatePowerWhitelistCache()1687 private void updatePowerWhitelistCache() { 1688 if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) { 1689 return; 1690 } 1691 mInjector.updatePowerWhitelistCache(); 1692 postCheckIdleStates(UserHandle.USER_ALL); 1693 } 1694 1695 private class PackageReceiver extends BroadcastReceiver { 1696 @Override onReceive(Context context, Intent intent)1697 public void onReceive(Context context, Intent intent) { 1698 final String action = intent.getAction(); 1699 final String pkgName = intent.getData().getSchemeSpecificPart(); 1700 final int userId = getSendingUserId(); 1701 if (Intent.ACTION_PACKAGE_ADDED.equals(action) 1702 || Intent.ACTION_PACKAGE_CHANGED.equals(action)) { 1703 clearCarrierPrivilegedApps(); 1704 // ACTION_PACKAGE_ADDED is called even for system app downgrades. 1705 evaluateSystemAppException(pkgName, userId); 1706 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkgName) 1707 .sendToTarget(); 1708 } 1709 if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) || 1710 Intent.ACTION_PACKAGE_ADDED.equals(action))) { 1711 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 1712 maybeUnrestrictBuggyApp(pkgName, userId); 1713 } else { 1714 clearAppIdleForPackage(pkgName, userId); 1715 } 1716 } 1717 } 1718 } 1719 evaluateSystemAppException(String packageName, int userId)1720 private void evaluateSystemAppException(String packageName, int userId) { 1721 if (!mSystemServicesReady) { 1722 // The app will be evaluated in when services are ready. 1723 return; 1724 } 1725 try { 1726 PackageInfo pi = mPackageManager.getPackageInfoAsUser( 1727 packageName, HEADLESS_APP_CHECK_FLAGS, userId); 1728 evaluateSystemAppException(pi); 1729 } catch (PackageManager.NameNotFoundException e) { 1730 synchronized (mHeadlessSystemApps) { 1731 mHeadlessSystemApps.remove(packageName); 1732 } 1733 } 1734 } 1735 1736 /** Returns true if the exception status changed. */ evaluateSystemAppException(@ullable PackageInfo pkgInfo)1737 private boolean evaluateSystemAppException(@Nullable PackageInfo pkgInfo) { 1738 if (pkgInfo == null || pkgInfo.applicationInfo == null 1739 || (!pkgInfo.applicationInfo.isSystemApp() 1740 && !pkgInfo.applicationInfo.isUpdatedSystemApp())) { 1741 return false; 1742 } 1743 synchronized (mHeadlessSystemApps) { 1744 if (pkgInfo.activities == null || pkgInfo.activities.length == 0) { 1745 // Headless system app. 1746 return mHeadlessSystemApps.add(pkgInfo.packageName); 1747 } else { 1748 return mHeadlessSystemApps.remove(pkgInfo.packageName); 1749 } 1750 } 1751 } 1752 1753 /** Call on a system version update to temporarily reset system app buckets. */ 1754 @Override initializeDefaultsForSystemApps(int userId)1755 public void initializeDefaultsForSystemApps(int userId) { 1756 if (!mSystemServicesReady) { 1757 // Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled 1758 mPendingInitializeDefaults = true; 1759 return; 1760 } 1761 Slog.d(TAG, "Initializing defaults for system apps on user " + userId + ", " 1762 + "appIdleEnabled=" + mAppIdleEnabled); 1763 final long elapsedRealtime = mInjector.elapsedRealtime(); 1764 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser( 1765 PackageManager.MATCH_DISABLED_COMPONENTS, 1766 userId); 1767 final int packageCount = packages.size(); 1768 synchronized (mAppIdleLock) { 1769 for (int i = 0; i < packageCount; i++) { 1770 final PackageInfo pi = packages.get(i); 1771 String packageName = pi.packageName; 1772 if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) { 1773 // Mark app as used for 2 hours. After that it can timeout to whatever the 1774 // past usage pattern was. 1775 mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, 1776 REASON_SUB_USAGE_SYSTEM_UPDATE, 0, 1777 elapsedRealtime + mSystemUpdateUsageTimeoutMillis); 1778 } 1779 } 1780 // Immediately persist defaults to disk 1781 mAppIdleHistory.writeAppIdleTimes(userId); 1782 } 1783 } 1784 1785 /** Call on system boot to get the initial set of headless system apps. */ loadHeadlessSystemAppCache()1786 private void loadHeadlessSystemAppCache() { 1787 Slog.d(TAG, "Loading headless system app cache. appIdleEnabled=" + mAppIdleEnabled); 1788 final List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser( 1789 HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM); 1790 final int packageCount = packages.size(); 1791 for (int i = 0; i < packageCount; i++) { 1792 PackageInfo pkgInfo = packages.get(i); 1793 if (pkgInfo != null && evaluateSystemAppException(pkgInfo)) { 1794 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, 1795 UserHandle.USER_SYSTEM, -1, pkgInfo.packageName) 1796 .sendToTarget(); 1797 } 1798 } 1799 } 1800 1801 @Override postReportContentProviderUsage(String name, String packageName, int userId)1802 public void postReportContentProviderUsage(String name, String packageName, int userId) { 1803 SomeArgs args = SomeArgs.obtain(); 1804 args.arg1 = name; 1805 args.arg2 = packageName; 1806 args.arg3 = userId; 1807 mHandler.obtainMessage(MSG_REPORT_CONTENT_PROVIDER_USAGE, args) 1808 .sendToTarget(); 1809 } 1810 1811 @Override postReportSyncScheduled(String packageName, int userId, boolean exempted)1812 public void postReportSyncScheduled(String packageName, int userId, boolean exempted) { 1813 mHandler.obtainMessage(MSG_REPORT_SYNC_SCHEDULED, userId, exempted ? 1 : 0, packageName) 1814 .sendToTarget(); 1815 } 1816 1817 @Override postReportExemptedSyncStart(String packageName, int userId)1818 public void postReportExemptedSyncStart(String packageName, int userId) { 1819 mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName) 1820 .sendToTarget(); 1821 } 1822 1823 @Override dumpUsers(IndentingPrintWriter idpw, int[] userIds, List<String> pkgs)1824 public void dumpUsers(IndentingPrintWriter idpw, int[] userIds, List<String> pkgs) { 1825 synchronized (mAppIdleLock) { 1826 mAppIdleHistory.dumpUsers(idpw, userIds, pkgs); 1827 } 1828 } 1829 1830 @Override dumpState(String[] args, PrintWriter pw)1831 public void dumpState(String[] args, PrintWriter pw) { 1832 synchronized (mAppIdleLock) { 1833 pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps 1834 + "): " + mCarrierPrivilegedApps); 1835 } 1836 1837 pw.println(); 1838 pw.println("Settings:"); 1839 1840 pw.print(" mCheckIdleIntervalMillis="); 1841 TimeUtils.formatDuration(mCheckIdleIntervalMillis, pw); 1842 pw.println(); 1843 1844 pw.print(" mStrongUsageTimeoutMillis="); 1845 TimeUtils.formatDuration(mStrongUsageTimeoutMillis, pw); 1846 pw.println(); 1847 pw.print(" mNotificationSeenTimeoutMillis="); 1848 TimeUtils.formatDuration(mNotificationSeenTimeoutMillis, pw); 1849 pw.println(); 1850 pw.print(" mSyncAdapterTimeoutMillis="); 1851 TimeUtils.formatDuration(mSyncAdapterTimeoutMillis, pw); 1852 pw.println(); 1853 pw.print(" mSystemInteractionTimeoutMillis="); 1854 TimeUtils.formatDuration(mSystemInteractionTimeoutMillis, pw); 1855 pw.println(); 1856 pw.print(" mInitialForegroundServiceStartTimeoutMillis="); 1857 TimeUtils.formatDuration(mInitialForegroundServiceStartTimeoutMillis, pw); 1858 pw.println(); 1859 1860 pw.print(" mPredictionTimeoutMillis="); 1861 TimeUtils.formatDuration(mPredictionTimeoutMillis, pw); 1862 pw.println(); 1863 1864 pw.print(" mExemptedSyncScheduledNonDozeTimeoutMillis="); 1865 TimeUtils.formatDuration(mExemptedSyncScheduledNonDozeTimeoutMillis, pw); 1866 pw.println(); 1867 pw.print(" mExemptedSyncScheduledDozeTimeoutMillis="); 1868 TimeUtils.formatDuration(mExemptedSyncScheduledDozeTimeoutMillis, pw); 1869 pw.println(); 1870 pw.print(" mExemptedSyncStartTimeoutMillis="); 1871 TimeUtils.formatDuration(mExemptedSyncStartTimeoutMillis, pw); 1872 pw.println(); 1873 pw.print(" mUnexemptedSyncScheduledTimeoutMillis="); 1874 TimeUtils.formatDuration(mUnexemptedSyncScheduledTimeoutMillis, pw); 1875 pw.println(); 1876 1877 pw.print(" mSystemUpdateUsageTimeoutMillis="); 1878 TimeUtils.formatDuration(mSystemUpdateUsageTimeoutMillis, pw); 1879 pw.println(); 1880 1881 pw.println(); 1882 pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled); 1883 pw.print(" mAllowRestrictedBucket="); 1884 pw.print(mAllowRestrictedBucket); 1885 pw.print(" mIsCharging="); 1886 pw.print(mIsCharging); 1887 pw.println(); 1888 pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds)); 1889 pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds)); 1890 pw.println(); 1891 1892 pw.println("mHeadlessSystemApps=["); 1893 synchronized (mHeadlessSystemApps) { 1894 for (int i = mHeadlessSystemApps.size() - 1; i >= 0; --i) { 1895 pw.print(" "); 1896 pw.print(mHeadlessSystemApps.valueAt(i)); 1897 pw.println(","); 1898 } 1899 } 1900 pw.println("]"); 1901 pw.println(); 1902 1903 mInjector.dump(pw); 1904 } 1905 1906 /** 1907 * Injector for interaction with external code. Override methods to provide a mock 1908 * implementation for tests. 1909 * onBootPhase() must be called with at least the PHASE_SYSTEM_SERVICES_READY 1910 */ 1911 static class Injector { 1912 1913 private final Context mContext; 1914 private final Looper mLooper; 1915 private IBatteryStats mBatteryStats; 1916 private BatteryManager mBatteryManager; 1917 private PackageManagerInternal mPackageManagerInternal; 1918 private DisplayManager mDisplayManager; 1919 private PowerManager mPowerManager; 1920 private IDeviceIdleController mDeviceIdleController; 1921 private CrossProfileAppsInternal mCrossProfileAppsInternal; 1922 int mBootPhase; 1923 /** 1924 * The minimum amount of time required since the last user interaction before an app can be 1925 * automatically placed in the RESTRICTED bucket. 1926 */ 1927 long mAutoRestrictedBucketDelayMs = ONE_DAY; 1928 /** 1929 * Cached set of apps that are power whitelisted, including those not whitelisted from idle. 1930 */ 1931 @GuardedBy("mPowerWhitelistedApps") 1932 private final ArraySet<String> mPowerWhitelistedApps = new ArraySet<>(); 1933 Injector(Context context, Looper looper)1934 Injector(Context context, Looper looper) { 1935 mContext = context; 1936 mLooper = looper; 1937 } 1938 getContext()1939 Context getContext() { 1940 return mContext; 1941 } 1942 getLooper()1943 Looper getLooper() { 1944 return mLooper; 1945 } 1946 onBootPhase(int phase)1947 void onBootPhase(int phase) { 1948 if (phase == PHASE_SYSTEM_SERVICES_READY) { 1949 mDeviceIdleController = IDeviceIdleController.Stub.asInterface( 1950 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); 1951 mBatteryStats = IBatteryStats.Stub.asInterface( 1952 ServiceManager.getService(BatteryStats.SERVICE_NAME)); 1953 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); 1954 mDisplayManager = (DisplayManager) mContext.getSystemService( 1955 Context.DISPLAY_SERVICE); 1956 mPowerManager = mContext.getSystemService(PowerManager.class); 1957 mBatteryManager = mContext.getSystemService(BatteryManager.class); 1958 mCrossProfileAppsInternal = LocalServices.getService( 1959 CrossProfileAppsInternal.class); 1960 1961 final ActivityManager activityManager = 1962 (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); 1963 if (activityManager.isLowRamDevice() || ActivityManager.isSmallBatteryDevice()) { 1964 mAutoRestrictedBucketDelayMs = 12 * ONE_HOUR; 1965 } 1966 } 1967 mBootPhase = phase; 1968 } 1969 getBootPhase()1970 int getBootPhase() { 1971 return mBootPhase; 1972 } 1973 1974 /** 1975 * Returns the elapsed realtime since the device started. Override this 1976 * to control the clock. 1977 * @return elapsed realtime 1978 */ elapsedRealtime()1979 long elapsedRealtime() { 1980 return SystemClock.elapsedRealtime(); 1981 } 1982 currentTimeMillis()1983 long currentTimeMillis() { 1984 return System.currentTimeMillis(); 1985 } 1986 isAppIdleEnabled()1987 boolean isAppIdleEnabled() { 1988 final boolean buildFlag = mContext.getResources().getBoolean( 1989 com.android.internal.R.bool.config_enableAutoPowerModes); 1990 final boolean runtimeFlag = Global.getInt(mContext.getContentResolver(), 1991 Global.APP_STANDBY_ENABLED, 1) == 1 1992 && Global.getInt(mContext.getContentResolver(), 1993 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 1) == 1; 1994 return buildFlag && runtimeFlag; 1995 } 1996 isCharging()1997 boolean isCharging() { 1998 return mBatteryManager.isCharging(); 1999 } 2000 isNonIdleWhitelisted(String packageName)2001 boolean isNonIdleWhitelisted(String packageName) { 2002 if (mBootPhase < PHASE_SYSTEM_SERVICES_READY) { 2003 return false; 2004 } 2005 synchronized (mPowerWhitelistedApps) { 2006 return mPowerWhitelistedApps.contains(packageName); 2007 } 2008 } 2009 updatePowerWhitelistCache()2010 void updatePowerWhitelistCache() { 2011 try { 2012 // Don't call out to DeviceIdleController with the lock held. 2013 final String[] whitelistedPkgs = 2014 mDeviceIdleController.getFullPowerWhitelistExceptIdle(); 2015 synchronized (mPowerWhitelistedApps) { 2016 mPowerWhitelistedApps.clear(); 2017 final int len = whitelistedPkgs.length; 2018 for (int i = 0; i < len; ++i) { 2019 mPowerWhitelistedApps.add(whitelistedPkgs[i]); 2020 } 2021 } 2022 } catch (RemoteException e) { 2023 // Should not happen. 2024 Slog.wtf(TAG, "Failed to get power whitelist", e); 2025 } 2026 } 2027 isRestrictedBucketEnabled()2028 boolean isRestrictedBucketEnabled() { 2029 return Global.getInt(mContext.getContentResolver(), 2030 Global.ENABLE_RESTRICTED_BUCKET, 2031 Global.DEFAULT_ENABLE_RESTRICTED_BUCKET) == 1; 2032 } 2033 getDataSystemDirectory()2034 File getDataSystemDirectory() { 2035 return Environment.getDataSystemDirectory(); 2036 } 2037 2038 /** 2039 * Return the minimum amount of time that must have passed since the last user usage before 2040 * an app can be automatically put into the 2041 * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket. 2042 */ getAutoRestrictedBucketDelayMs()2043 long getAutoRestrictedBucketDelayMs() { 2044 return mAutoRestrictedBucketDelayMs; 2045 } 2046 noteEvent(int event, String packageName, int uid)2047 void noteEvent(int event, String packageName, int uid) throws RemoteException { 2048 mBatteryStats.noteEvent(event, packageName, uid); 2049 } 2050 getPackageManagerInternal()2051 PackageManagerInternal getPackageManagerInternal() { 2052 return mPackageManagerInternal; 2053 } 2054 isPackageEphemeral(int userId, String packageName)2055 boolean isPackageEphemeral(int userId, String packageName) { 2056 return mPackageManagerInternal.isPackageEphemeral(userId, packageName); 2057 } 2058 isPackageInstalled(String packageName, int flags, int userId)2059 boolean isPackageInstalled(String packageName, int flags, int userId) { 2060 return mPackageManagerInternal.getPackageUid(packageName, flags, userId) >= 0; 2061 } 2062 getRunningUserIds()2063 int[] getRunningUserIds() throws RemoteException { 2064 return ActivityManager.getService().getRunningUserIds(); 2065 } 2066 isDefaultDisplayOn()2067 boolean isDefaultDisplayOn() { 2068 return mDisplayManager 2069 .getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_ON; 2070 } 2071 registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler)2072 void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) { 2073 mDisplayManager.registerDisplayListener(listener, handler); 2074 } 2075 getActiveNetworkScorer()2076 String getActiveNetworkScorer() { 2077 NetworkScoreManager nsm = (NetworkScoreManager) mContext.getSystemService( 2078 Context.NETWORK_SCORE_SERVICE); 2079 return nsm.getActiveScorerPackage(); 2080 } 2081 isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName, int userId)2082 public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName, 2083 int userId) { 2084 return appWidgetManager.isBoundWidgetPackage(packageName, userId); 2085 } 2086 getAppIdleSettings()2087 String getAppIdleSettings() { 2088 return Global.getString(mContext.getContentResolver(), 2089 Global.APP_IDLE_CONSTANTS); 2090 } 2091 2092 /** Whether the device is in doze or not. */ isDeviceIdleMode()2093 public boolean isDeviceIdleMode() { 2094 return mPowerManager.isDeviceIdleMode(); 2095 } 2096 getValidCrossProfileTargets(String pkg, int userId)2097 public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) { 2098 final int uid = mPackageManagerInternal.getPackageUidInternal(pkg, 0, userId); 2099 final AndroidPackage aPkg = mPackageManagerInternal.getPackage(uid); 2100 if (uid < 0 2101 || aPkg == null 2102 || !aPkg.isCrossProfile() 2103 || !mCrossProfileAppsInternal 2104 .verifyUidHasInteractAcrossProfilePermission(pkg, uid)) { 2105 if (uid >= 0 && aPkg == null) { 2106 Slog.wtf(TAG, "Null package retrieved for UID " + uid); 2107 } 2108 return Collections.emptyList(); 2109 } 2110 return mCrossProfileAppsInternal.getTargetUserProfiles(pkg, userId); 2111 } 2112 dump(PrintWriter pw)2113 void dump(PrintWriter pw) { 2114 pw.println("mPowerWhitelistedApps=["); 2115 synchronized (mPowerWhitelistedApps) { 2116 for (int i = mPowerWhitelistedApps.size() - 1; i >= 0; --i) { 2117 pw.print(" "); 2118 pw.print(mPowerWhitelistedApps.valueAt(i)); 2119 pw.println(","); 2120 } 2121 } 2122 pw.println("]"); 2123 pw.println(); 2124 } 2125 } 2126 2127 class AppStandbyHandler extends Handler { 2128 AppStandbyHandler(Looper looper)2129 AppStandbyHandler(Looper looper) { 2130 super(looper); 2131 } 2132 2133 @Override handleMessage(Message msg)2134 public void handleMessage(Message msg) { 2135 switch (msg.what) { 2136 case MSG_INFORM_LISTENERS: 2137 StandbyUpdateRecord r = (StandbyUpdateRecord) msg.obj; 2138 informListeners(r.packageName, r.userId, r.bucket, r.reason, 2139 r.isUserInteraction); 2140 r.recycle(); 2141 break; 2142 2143 case MSG_FORCE_IDLE_STATE: 2144 forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1); 2145 break; 2146 2147 case MSG_CHECK_IDLE_STATES: 2148 if (checkIdleStates(msg.arg1) && mAppIdleEnabled) { 2149 mHandler.sendMessageDelayed(mHandler.obtainMessage( 2150 MSG_CHECK_IDLE_STATES, msg.arg1, 0), 2151 mCheckIdleIntervalMillis); 2152 } 2153 break; 2154 2155 case MSG_ONE_TIME_CHECK_IDLE_STATES: 2156 mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES); 2157 waitForAdminData(); 2158 checkIdleStates(UserHandle.USER_ALL); 2159 break; 2160 2161 case MSG_REPORT_CONTENT_PROVIDER_USAGE: 2162 SomeArgs args = (SomeArgs) msg.obj; 2163 reportContentProviderUsage((String) args.arg1, // authority name 2164 (String) args.arg2, // package name 2165 (int) args.arg3); // userId 2166 args.recycle(); 2167 break; 2168 2169 case MSG_PAROLE_STATE_CHANGED: 2170 if (DEBUG) Slog.d(TAG, "Parole state: " + isInParole()); 2171 informParoleStateChanged(); 2172 break; 2173 2174 case MSG_CHECK_PACKAGE_IDLE_STATE: 2175 checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2, 2176 mInjector.elapsedRealtime()); 2177 break; 2178 2179 case MSG_REPORT_SYNC_SCHEDULED: 2180 final boolean exempted = msg.arg2 > 0 ? true : false; 2181 if (exempted) { 2182 reportExemptedSyncScheduled((String) msg.obj, msg.arg1); 2183 } else { 2184 reportUnexemptedSyncScheduled((String) msg.obj, msg.arg1); 2185 } 2186 break; 2187 2188 case MSG_REPORT_EXEMPTED_SYNC_START: 2189 reportExemptedSyncStart((String) msg.obj, msg.arg1); 2190 break; 2191 2192 default: 2193 super.handleMessage(msg); 2194 break; 2195 2196 } 2197 } 2198 }; 2199 2200 private class DeviceStateReceiver extends BroadcastReceiver { 2201 @Override onReceive(Context context, Intent intent)2202 public void onReceive(Context context, Intent intent) { 2203 switch (intent.getAction()) { 2204 case BatteryManager.ACTION_CHARGING: 2205 setChargingState(true); 2206 break; 2207 case BatteryManager.ACTION_DISCHARGING: 2208 setChargingState(false); 2209 break; 2210 case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED: 2211 if (mSystemServicesReady) { 2212 mHandler.post(AppStandbyController.this::updatePowerWhitelistCache); 2213 } 2214 break; 2215 } 2216 } 2217 } 2218 2219 private final DisplayManager.DisplayListener mDisplayListener 2220 = new DisplayManager.DisplayListener() { 2221 2222 @Override public void onDisplayAdded(int displayId) { 2223 } 2224 2225 @Override public void onDisplayRemoved(int displayId) { 2226 } 2227 2228 @Override public void onDisplayChanged(int displayId) { 2229 if (displayId == Display.DEFAULT_DISPLAY) { 2230 final boolean displayOn = isDisplayOn(); 2231 synchronized (mAppIdleLock) { 2232 mAppIdleHistory.updateDisplay(displayOn, mInjector.elapsedRealtime()); 2233 } 2234 } 2235 } 2236 }; 2237 2238 /** 2239 * Observe settings changes for {@link Global#APP_IDLE_CONSTANTS}. 2240 */ 2241 private class SettingsObserver extends ContentObserver { 2242 private static final String KEY_SCREEN_TIME_THRESHOLDS = "screen_thresholds"; 2243 private static final String KEY_ELAPSED_TIME_THRESHOLDS = "elapsed_thresholds"; 2244 private static final String KEY_STRONG_USAGE_HOLD_DURATION = "strong_usage_duration"; 2245 private static final String KEY_NOTIFICATION_SEEN_HOLD_DURATION = 2246 "notification_seen_duration"; 2247 private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION = 2248 "system_update_usage_duration"; 2249 private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout"; 2250 private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration"; 2251 private static final String KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION = 2252 "exempted_sync_scheduled_nd_duration"; 2253 private static final String KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION = 2254 "exempted_sync_scheduled_d_duration"; 2255 private static final String KEY_EXEMPTED_SYNC_START_HOLD_DURATION = 2256 "exempted_sync_start_duration"; 2257 private static final String KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION = 2258 "unexempted_sync_scheduled_duration"; 2259 private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION = 2260 "system_interaction_duration"; 2261 private static final String KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION = 2262 "initial_foreground_service_start_duration"; 2263 private static final String KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS = 2264 "auto_restricted_bucket_delay_ms"; 2265 private static final String KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = 2266 "cross_profile_apps_share_standby_buckets"; 2267 public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR; 2268 public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR; 2269 public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR; 2270 public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE; 2271 public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE; 2272 public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT = 10 * ONE_MINUTE; 2273 public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = 4 * ONE_HOUR; 2274 public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 10 * ONE_MINUTE; 2275 public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 10 * ONE_MINUTE; 2276 public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE; 2277 public static final long DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS = ONE_DAY; 2278 public static final boolean DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = true; 2279 2280 private final KeyValueListParser mParser = new KeyValueListParser(','); 2281 SettingsObserver(Handler handler)2282 SettingsObserver(Handler handler) { 2283 super(handler); 2284 } 2285 registerObserver()2286 void registerObserver() { 2287 final ContentResolver cr = mContext.getContentResolver(); 2288 cr.registerContentObserver(Global.getUriFor(Global.APP_IDLE_CONSTANTS), false, this); 2289 cr.registerContentObserver(Global.getUriFor(Global.APP_STANDBY_ENABLED), false, this); 2290 cr.registerContentObserver(Global.getUriFor(Global.ENABLE_RESTRICTED_BUCKET), 2291 false, this); 2292 cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED), 2293 false, this); 2294 } 2295 2296 @Override onChange(boolean selfChange)2297 public void onChange(boolean selfChange) { 2298 updateSettings(); 2299 postOneTimeCheckIdleStates(); 2300 } 2301 updateSettings()2302 void updateSettings() { 2303 if (DEBUG) { 2304 Slog.d(TAG, 2305 "appidle=" + Global.getString(mContext.getContentResolver(), 2306 Global.APP_STANDBY_ENABLED)); 2307 Slog.d(TAG, 2308 "adaptivebat=" + Global.getString(mContext.getContentResolver(), 2309 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED)); 2310 Slog.d(TAG, "appidleconstants=" + Global.getString( 2311 mContext.getContentResolver(), 2312 Global.APP_IDLE_CONSTANTS)); 2313 } 2314 2315 // Look at global settings for this. 2316 // TODO: Maybe apply different thresholds for different users. 2317 try { 2318 mParser.setString(mInjector.getAppIdleSettings()); 2319 } catch (IllegalArgumentException e) { 2320 Slog.e(TAG, "Bad value for app idle settings: " + e.getMessage()); 2321 // fallthrough, mParser is empty and all defaults will be returned. 2322 } 2323 2324 synchronized (mAppIdleLock) { 2325 2326 String screenThresholdsValue = mParser.getString(KEY_SCREEN_TIME_THRESHOLDS, null); 2327 mAppStandbyScreenThresholds = parseLongArray(screenThresholdsValue, 2328 SCREEN_TIME_THRESHOLDS, MINIMUM_SCREEN_TIME_THRESHOLDS); 2329 2330 String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS, 2331 null); 2332 mAppStandbyElapsedThresholds = parseLongArray(elapsedThresholdsValue, 2333 ELAPSED_TIME_THRESHOLDS, MINIMUM_ELAPSED_TIME_THRESHOLDS); 2334 mCheckIdleIntervalMillis = Math.min(mAppStandbyElapsedThresholds[1] / 4, 2335 COMPRESS_TIME ? ONE_MINUTE : 4 * 60 * ONE_MINUTE); // 4 hours 2336 mStrongUsageTimeoutMillis = mParser.getDurationMillis( 2337 KEY_STRONG_USAGE_HOLD_DURATION, 2338 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STRONG_USAGE_TIMEOUT); 2339 mNotificationSeenTimeoutMillis = mParser.getDurationMillis( 2340 KEY_NOTIFICATION_SEEN_HOLD_DURATION, 2341 COMPRESS_TIME ? 12 * ONE_MINUTE : DEFAULT_NOTIFICATION_TIMEOUT); 2342 mSystemUpdateUsageTimeoutMillis = mParser.getDurationMillis( 2343 KEY_SYSTEM_UPDATE_HOLD_DURATION, 2344 COMPRESS_TIME ? 2 * ONE_MINUTE : DEFAULT_SYSTEM_UPDATE_TIMEOUT); 2345 mPredictionTimeoutMillis = mParser.getDurationMillis( 2346 KEY_PREDICTION_TIMEOUT, 2347 COMPRESS_TIME ? 10 * ONE_MINUTE : DEFAULT_PREDICTION_TIMEOUT); 2348 mSyncAdapterTimeoutMillis = mParser.getDurationMillis( 2349 KEY_SYNC_ADAPTER_HOLD_DURATION, 2350 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT); 2351 2352 mExemptedSyncScheduledNonDozeTimeoutMillis = mParser.getDurationMillis( 2353 KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION, 2354 COMPRESS_TIME ? (ONE_MINUTE / 2) 2355 : DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT); 2356 2357 mExemptedSyncScheduledDozeTimeoutMillis = mParser.getDurationMillis( 2358 KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION, 2359 COMPRESS_TIME ? ONE_MINUTE 2360 : DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT); 2361 2362 mExemptedSyncStartTimeoutMillis = mParser.getDurationMillis( 2363 KEY_EXEMPTED_SYNC_START_HOLD_DURATION, 2364 COMPRESS_TIME ? ONE_MINUTE 2365 : DEFAULT_EXEMPTED_SYNC_START_TIMEOUT); 2366 2367 mUnexemptedSyncScheduledTimeoutMillis = mParser.getDurationMillis( 2368 KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION, 2369 COMPRESS_TIME 2370 ? ONE_MINUTE : DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT); 2371 2372 mSystemInteractionTimeoutMillis = mParser.getDurationMillis( 2373 KEY_SYSTEM_INTERACTION_HOLD_DURATION, 2374 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT); 2375 2376 mInitialForegroundServiceStartTimeoutMillis = mParser.getDurationMillis( 2377 KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION, 2378 COMPRESS_TIME ? ONE_MINUTE : 2379 DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT); 2380 2381 mInjector.mAutoRestrictedBucketDelayMs = Math.max( 2382 COMPRESS_TIME ? ONE_MINUTE : 2 * ONE_HOUR, 2383 mParser.getDurationMillis(KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS, 2384 COMPRESS_TIME 2385 ? ONE_MINUTE : DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS)); 2386 2387 mLinkCrossProfileApps = mParser.getBoolean( 2388 KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS, 2389 DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS); 2390 2391 mAllowRestrictedBucket = mInjector.isRestrictedBucketEnabled(); 2392 } 2393 2394 // Check if app_idle_enabled has changed. Do this after getting the rest of the settings 2395 // in case we need to change something based on the new values. 2396 setAppIdleEnabled(mInjector.isAppIdleEnabled()); 2397 } 2398 parseLongArray(String values, long[] defaults, long[] minValues)2399 long[] parseLongArray(String values, long[] defaults, long[] minValues) { 2400 if (values == null) return defaults; 2401 if (values.isEmpty()) { 2402 // Reset to defaults 2403 return defaults; 2404 } else { 2405 String[] thresholds = values.split("/"); 2406 if (thresholds.length == THRESHOLD_BUCKETS.length) { 2407 if (minValues.length != THRESHOLD_BUCKETS.length) { 2408 Slog.wtf(TAG, "minValues array is the wrong size"); 2409 // Use zeroes as the minimums. 2410 minValues = new long[THRESHOLD_BUCKETS.length]; 2411 } 2412 long[] array = new long[THRESHOLD_BUCKETS.length]; 2413 for (int i = 0; i < THRESHOLD_BUCKETS.length; i++) { 2414 try { 2415 if (thresholds[i].startsWith("P") || thresholds[i].startsWith("p")) { 2416 array[i] = Math.max(minValues[i], 2417 Duration.parse(thresholds[i]).toMillis()); 2418 } else { 2419 array[i] = Math.max(minValues[i], Long.parseLong(thresholds[i])); 2420 } 2421 } catch (NumberFormatException|DateTimeParseException e) { 2422 return defaults; 2423 } 2424 } 2425 return array; 2426 } else { 2427 return defaults; 2428 } 2429 } 2430 } 2431 } 2432 } 2433