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