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