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_RESTORED; 27 import static android.app.usage.UsageStatsManager.REASON_SUB_DEFAULT_APP_UPDATE; 28 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY; 29 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_USER_FLAG_INTERACTION; 30 import static android.app.usage.UsageStatsManager.REASON_SUB_MASK; 31 import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED; 32 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT; 33 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE; 34 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE; 35 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START; 36 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START; 37 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND; 38 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND; 39 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN; 40 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED; 41 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV; 42 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER; 43 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION; 44 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE; 45 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED; 46 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION; 47 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; 48 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED; 49 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; 50 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; 51 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; 52 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED; 53 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; 54 import static android.app.usage.UsageStatsManager.standbyBucketToString; 55 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 56 57 import static com.android.server.SystemService.PHASE_BOOT_COMPLETED; 58 import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; 59 import static com.android.server.usage.AppIdleHistory.STANDBY_BUCKET_UNKNOWN; 60 61 import android.annotation.CurrentTimeMillisLong; 62 import android.annotation.NonNull; 63 import android.annotation.Nullable; 64 import android.annotation.UserIdInt; 65 import android.app.ActivityManager; 66 import android.app.usage.AppStandbyInfo; 67 import android.app.usage.UsageEvents; 68 import android.app.usage.UsageStatsManager.ForcedReasons; 69 import android.app.usage.UsageStatsManager.StandbyBuckets; 70 import android.app.usage.UsageStatsManagerInternal; 71 import android.appwidget.AppWidgetManager; 72 import android.content.BroadcastReceiver; 73 import android.content.ContentResolver; 74 import android.content.Context; 75 import android.content.Intent; 76 import android.content.IntentFilter; 77 import android.content.pm.ApplicationInfo; 78 import android.content.pm.CrossProfileAppsInternal; 79 import android.content.pm.PackageInfo; 80 import android.content.pm.PackageManager; 81 import android.content.pm.PackageManagerInternal; 82 import android.content.pm.ResolveInfo; 83 import android.database.ContentObserver; 84 import android.hardware.display.DisplayManager; 85 import android.net.NetworkScoreManager; 86 import android.os.BatteryManager; 87 import android.os.BatteryStats; 88 import android.os.Build; 89 import android.os.Environment; 90 import android.os.Handler; 91 import android.os.IDeviceIdleController; 92 import android.os.Looper; 93 import android.os.Message; 94 import android.os.PowerManager; 95 import android.os.Process; 96 import android.os.RemoteException; 97 import android.os.ServiceManager; 98 import android.os.SystemClock; 99 import android.os.Trace; 100 import android.os.UserHandle; 101 import android.provider.DeviceConfig; 102 import android.provider.Settings.Global; 103 import android.telephony.TelephonyManager; 104 import android.text.TextUtils; 105 import android.util.ArrayMap; 106 import android.util.ArraySet; 107 import android.util.IndentingPrintWriter; 108 import android.util.Slog; 109 import android.util.SparseArray; 110 import android.util.SparseBooleanArray; 111 import android.util.SparseLongArray; 112 import android.util.SparseSetArray; 113 import android.util.TimeUtils; 114 import android.view.Display; 115 import android.widget.Toast; 116 117 import com.android.internal.R; 118 import com.android.internal.annotations.GuardedBy; 119 import com.android.internal.annotations.VisibleForTesting; 120 import com.android.internal.app.IBatteryStats; 121 import com.android.internal.util.ArrayUtils; 122 import com.android.internal.util.ConcurrentUtils; 123 import com.android.server.AlarmManagerInternal; 124 import com.android.server.JobSchedulerBackgroundThread; 125 import com.android.server.LocalServices; 126 import com.android.server.pm.parsing.pkg.AndroidPackage; 127 import com.android.server.usage.AppIdleHistory.AppUsageHistory; 128 129 import libcore.util.EmptyArray; 130 131 import java.io.File; 132 import java.io.PrintWriter; 133 import java.util.ArrayList; 134 import java.util.Arrays; 135 import java.util.Collections; 136 import java.util.List; 137 import java.util.Map; 138 import java.util.Set; 139 import java.util.concurrent.CountDownLatch; 140 141 /** 142 * Manages the standby state of an app, listening to various events. 143 * 144 * Unit test: 145 * atest com.android.server.usage.AppStandbyControllerTests 146 */ 147 public class AppStandbyController 148 implements AppStandbyInternal, UsageStatsManagerInternal.UsageEventListener { 149 150 private static final String TAG = "AppStandbyController"; 151 // Do not submit with true. 152 static final boolean DEBUG = false; 153 154 static final boolean COMPRESS_TIME = false; 155 private static final long ONE_MINUTE = 60 * 1000; 156 private static final long ONE_HOUR = ONE_MINUTE * 60; 157 private static final long ONE_DAY = ONE_HOUR * 24; 158 159 /** 160 * The default minimum amount of time the screen must have been on before an app can time out 161 * from its current bucket to the next bucket. 162 */ 163 @VisibleForTesting 164 static final long[] DEFAULT_SCREEN_TIME_THRESHOLDS = { 165 0, 166 0, 167 COMPRESS_TIME ? 2 * ONE_MINUTE : 1 * ONE_HOUR, 168 COMPRESS_TIME ? 4 * ONE_MINUTE : 2 * ONE_HOUR, 169 COMPRESS_TIME ? 8 * ONE_MINUTE : 6 * ONE_HOUR 170 }; 171 172 /** The minimum allowed values for each index in {@link #DEFAULT_SCREEN_TIME_THRESHOLDS}. */ 173 @VisibleForTesting 174 static final long[] MINIMUM_SCREEN_TIME_THRESHOLDS = COMPRESS_TIME 175 ? new long[DEFAULT_SCREEN_TIME_THRESHOLDS.length] 176 : new long[]{ 177 0, 178 0, 179 0, 180 30 * ONE_MINUTE, 181 ONE_HOUR 182 }; 183 184 /** 185 * The default minimum amount of elapsed time that must have passed before an app can time out 186 * from its current bucket to the next bucket. 187 */ 188 @VisibleForTesting 189 static final long[] DEFAULT_ELAPSED_TIME_THRESHOLDS = { 190 0, 191 COMPRESS_TIME ? 1 * ONE_MINUTE : 12 * ONE_HOUR, 192 COMPRESS_TIME ? 4 * ONE_MINUTE : 24 * ONE_HOUR, 193 COMPRESS_TIME ? 16 * ONE_MINUTE : 48 * ONE_HOUR, 194 COMPRESS_TIME ? 32 * ONE_MINUTE : 8 * ONE_DAY 195 }; 196 197 /** The minimum allowed values for each index in {@link #DEFAULT_ELAPSED_TIME_THRESHOLDS}. */ 198 @VisibleForTesting 199 static final long[] MINIMUM_ELAPSED_TIME_THRESHOLDS = COMPRESS_TIME 200 ? new long[DEFAULT_ELAPSED_TIME_THRESHOLDS.length] 201 : new long[]{ 202 0, 203 ONE_HOUR, 204 ONE_HOUR, 205 2 * ONE_HOUR, 206 4 * ONE_HOUR 207 }; 208 209 private static final int[] THRESHOLD_BUCKETS = { 210 STANDBY_BUCKET_ACTIVE, 211 STANDBY_BUCKET_WORKING_SET, 212 STANDBY_BUCKET_FREQUENT, 213 STANDBY_BUCKET_RARE, 214 STANDBY_BUCKET_RESTRICTED 215 }; 216 217 /** Default expiration time for bucket prediction. After this, use thresholds to downgrade. */ 218 private static final long DEFAULT_PREDICTION_TIMEOUT = 219 COMPRESS_TIME ? 10 * ONE_MINUTE : 12 * ONE_HOUR; 220 221 /** 222 * Indicates the maximum wait time for admin data to be available; 223 */ 224 private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000; 225 226 private static final int HEADLESS_APP_CHECK_FLAGS = 227 PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 228 | PackageManager.MATCH_DISABLED_COMPONENTS 229 | PackageManager.MATCH_SYSTEM_ONLY; 230 231 private static final int NOTIFICATION_SEEN_PROMOTED_BUCKET_FOR_PRE_T_APPS = 232 STANDBY_BUCKET_WORKING_SET; 233 private static final long NOTIFICATION_SEEN_HOLD_DURATION_FOR_PRE_T_APPS = 234 COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR; 235 236 // To name the lock for stack traces 237 static class Lock {} 238 239 /** Lock to protect the app's standby state. Required for calls into AppIdleHistory */ 240 private final Object mAppIdleLock = new Lock(); 241 242 /** Keeps the history and state for each app. */ 243 @GuardedBy("mAppIdleLock") 244 private AppIdleHistory mAppIdleHistory; 245 246 @GuardedBy("mPackageAccessListeners") 247 private final ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>(); 248 249 /** 250 * Lock specifically for bookkeeping around the carrier-privileged app set. 251 * Do not acquire any other locks while holding this one. Methods that 252 * require this lock to be held are named with a "CPL" suffix. 253 */ 254 private final Object mCarrierPrivilegedLock = new Lock(); 255 256 /** Whether we've queried the list of carrier privileged apps. */ 257 @GuardedBy("mCarrierPrivilegedLock") 258 private boolean mHaveCarrierPrivilegedApps; 259 260 /** List of carrier-privileged apps that should be excluded from standby */ 261 @GuardedBy("mCarrierPrivilegedLock") 262 private List<String> mCarrierPrivilegedApps; 263 264 @GuardedBy("mActiveAdminApps") 265 private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>(); 266 267 /** List of admin protected packages. Can contain {@link android.os.UserHandle#USER_ALL}. */ 268 @GuardedBy("mAdminProtectedPackages") 269 private final SparseArray<Set<String>> mAdminProtectedPackages = new SparseArray<>(); 270 271 /** 272 * Set of system apps that are headless (don't have any "front door" activities, enabled or 273 * disabled). Presence in this map indicates that the app is a headless system app. 274 */ 275 @GuardedBy("mHeadlessSystemApps") 276 private final ArraySet<String> mHeadlessSystemApps = new ArraySet<>(); 277 278 private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1); 279 280 /** 281 * Set of user IDs and the next time (in the elapsed realtime timebase) when we should check the 282 * apps' idle states. 283 */ 284 @GuardedBy("mPendingIdleStateChecks") 285 private final SparseLongArray mPendingIdleStateChecks = new SparseLongArray(); 286 287 // Cache the active network scorer queried from the network scorer service 288 private volatile String mCachedNetworkScorer = null; 289 // The last time the network scorer service was queried 290 private volatile long mCachedNetworkScorerAtMillis = 0L; 291 // How long before querying the network scorer again. During this time, subsequent queries will 292 // get the cached value 293 private static final long NETWORK_SCORER_CACHE_DURATION_MILLIS = 5000L; 294 295 // Cache the device provisioning package queried from resource config_deviceProvisioningPackage. 296 // Note that there is no synchronization on this variable which is okay since in the worst case 297 // scenario, they might be a few extra reads from resources. 298 private String mCachedDeviceProvisioningPackage = null; 299 300 // Messages for the handler 301 static final int MSG_INFORM_LISTENERS = 3; 302 static final int MSG_FORCE_IDLE_STATE = 4; 303 static final int MSG_CHECK_IDLE_STATES = 5; 304 static final int MSG_TRIGGER_LISTENER_QUOTA_BUMP = 7; 305 static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8; 306 static final int MSG_PAROLE_STATE_CHANGED = 9; 307 static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10; 308 /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */ 309 static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11; 310 static final int MSG_REPORT_SYNC_SCHEDULED = 12; 311 static final int MSG_REPORT_EXEMPTED_SYNC_START = 13; 312 313 long mCheckIdleIntervalMillis = Math.min(DEFAULT_ELAPSED_TIME_THRESHOLDS[1] / 4, 314 ConstantsObserver.DEFAULT_CHECK_IDLE_INTERVAL_MS); 315 /** 316 * The minimum amount of time the screen must have been on before an app can time out from its 317 * current bucket to the next bucket. 318 */ 319 long[] mAppStandbyScreenThresholds = DEFAULT_SCREEN_TIME_THRESHOLDS; 320 /** 321 * The minimum amount of elapsed time that must have passed before an app can time out from its 322 * current bucket to the next bucket. 323 */ 324 long[] mAppStandbyElapsedThresholds = DEFAULT_ELAPSED_TIME_THRESHOLDS; 325 /** Minimum time a strong usage event should keep the bucket elevated. */ 326 long mStrongUsageTimeoutMillis = ConstantsObserver.DEFAULT_STRONG_USAGE_TIMEOUT; 327 /** Minimum time a notification seen event should keep the bucket elevated. */ 328 long mNotificationSeenTimeoutMillis = ConstantsObserver.DEFAULT_NOTIFICATION_TIMEOUT; 329 /** Minimum time a slice pinned event should keep the bucket elevated. */ 330 long mSlicePinnedTimeoutMillis = ConstantsObserver.DEFAULT_SLICE_PINNED_TIMEOUT; 331 /** The standby bucket that an app will be promoted on a notification-seen event */ 332 int mNotificationSeenPromotedBucket = 333 ConstantsObserver.DEFAULT_NOTIFICATION_SEEN_PROMOTED_BUCKET; 334 /** 335 * If {@code true}, tell each {@link AppIdleStateChangeListener} to give quota bump for each 336 * notification seen event. 337 */ 338 private boolean mTriggerQuotaBumpOnNotificationSeen = 339 ConstantsObserver.DEFAULT_TRIGGER_QUOTA_BUMP_ON_NOTIFICATION_SEEN; 340 /** 341 * If {@code true}, we will retain the pre-T impact of notification signal on apps targeting 342 * pre-T sdk levels regardless of other flag changes. 343 */ 344 boolean mRetainNotificationSeenImpactForPreTApps = 345 ConstantsObserver.DEFAULT_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS; 346 /** Minimum time a system update event should keep the buckets elevated. */ 347 long mSystemUpdateUsageTimeoutMillis = ConstantsObserver.DEFAULT_SYSTEM_UPDATE_TIMEOUT; 348 /** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */ 349 long mPredictionTimeoutMillis = DEFAULT_PREDICTION_TIMEOUT; 350 /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */ 351 long mSyncAdapterTimeoutMillis = ConstantsObserver.DEFAULT_SYNC_ADAPTER_TIMEOUT; 352 /** 353 * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in 354 * non-doze 355 */ 356 long mExemptedSyncScheduledNonDozeTimeoutMillis = 357 ConstantsObserver.DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT; 358 /** 359 * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in 360 * doze 361 */ 362 long mExemptedSyncScheduledDozeTimeoutMillis = 363 ConstantsObserver.DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT; 364 /** 365 * Maximum time an exempted sync should keep the buckets elevated, when sync is started. 366 */ 367 long mExemptedSyncStartTimeoutMillis = ConstantsObserver.DEFAULT_EXEMPTED_SYNC_START_TIMEOUT; 368 /** 369 * Maximum time an unexempted sync should keep the buckets elevated, when sync is scheduled 370 */ 371 long mUnexemptedSyncScheduledTimeoutMillis = 372 ConstantsObserver.DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT; 373 /** Maximum time a system interaction should keep the buckets elevated. */ 374 long mSystemInteractionTimeoutMillis = ConstantsObserver.DEFAULT_SYSTEM_INTERACTION_TIMEOUT; 375 /** 376 * Maximum time a foreground service start should keep the buckets elevated if the service 377 * start is the first usage of the app 378 */ 379 long mInitialForegroundServiceStartTimeoutMillis = 380 ConstantsObserver.DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT; 381 /** 382 * User usage that would elevate an app's standby bucket will also elevate the standby bucket of 383 * cross profile connected apps. Explicit standby bucket setting via 384 * {@link #setAppStandbyBucket(String, int, int, int, int)} will not be propagated. 385 */ 386 boolean mLinkCrossProfileApps = 387 ConstantsObserver.DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS; 388 389 /** 390 * Duration (in millis) for the window where events occurring will be considered as 391 * broadcast response, starting from the point when an app receives a broadcast. 392 */ 393 volatile long mBroadcastResponseWindowDurationMillis = 394 ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_WINDOW_DURATION_MS; 395 396 /** 397 * Process state threshold that is used for deciding whether or not an app is in the background 398 * in the context of recording broadcast response stats. Apps whose process state is higher 399 * than this threshold state will be considered to be in background. 400 */ 401 volatile int mBroadcastResponseFgThresholdState = 402 ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE; 403 404 /** 405 * Duration (in millis) for the window within which any broadcasts occurred will be 406 * treated as one broadcast session. 407 */ 408 volatile long mBroadcastSessionsDurationMs = 409 ConstantsObserver.DEFAULT_BROADCAST_SESSIONS_DURATION_MS; 410 411 /** 412 * Duration (in millis) for the window within which any broadcasts occurred ((with a 413 * corresponding response event) will be treated as one broadcast session. This similar to 414 * {@link #mBroadcastSessionsDurationMs}, except that this duration will be used to group only 415 * broadcasts that have a corresponding response event into sessions. 416 */ 417 volatile long mBroadcastSessionsWithResponseDurationMs = 418 ConstantsObserver.DEFAULT_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS; 419 420 /** 421 * Denotes whether the response event should be attributed to all broadcast sessions or not. 422 * If this is {@code true}, then the response event should be attributed to all the broadcast 423 * sessions that occurred within the broadcast response window. Otherwise, the 424 * response event should be attributed to only the earliest broadcast session within the 425 * broadcast response window. 426 */ 427 volatile boolean mNoteResponseEventForAllBroadcastSessions = 428 ConstantsObserver.DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS; 429 430 /** 431 * List of roles whose holders are exempted from the requirement of starting 432 * a response event after receiving a broadcast. 433 * 434 * The list of roles will be separated by '|' in the string. 435 */ 436 volatile String mBroadcastResponseExemptedRoles = 437 ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES; 438 volatile List<String> mBroadcastResponseExemptedRolesList = Collections.EMPTY_LIST; 439 440 /** 441 * List of permissions whose holders are exempted from the requirement of starting 442 * a response event after receiving a broadcast. 443 * 444 * The list of permissions will be separated by '|' in the string. 445 */ 446 volatile String mBroadcastResponseExemptedPermissions = 447 ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS; 448 volatile List<String> mBroadcastResponseExemptedPermissionsList = Collections.EMPTY_LIST; 449 450 /** 451 * Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}. 452 * 453 * Note: We are intentionally not guarding this by any lock since this is only updated on 454 * a handler thread and when querying, if we do end up seeing slightly older values, it is fine 455 * since the values are only used in tests and doesn't need to be queried in any other cases. 456 */ 457 private final Map<String, String> mAppStandbyProperties = new ArrayMap<>(); 458 459 /** 460 * Set of apps that were restored via backup & restore, per user, that need their 461 * standby buckets to be adjusted when installed. 462 */ 463 private final SparseSetArray<String> mAppsToRestoreToRare = new SparseSetArray<>(); 464 465 /** 466 * List of app-ids of system packages, populated on boot, when system services are ready. 467 */ 468 private final ArrayList<Integer> mSystemPackagesAppIds = new ArrayList<>(); 469 470 /** 471 * PackageManager flags to query for all system packages, including those that are disabled 472 * and hidden. 473 */ 474 private static final int SYSTEM_PACKAGE_FLAGS = PackageManager.MATCH_UNINSTALLED_PACKAGES 475 | PackageManager.MATCH_SYSTEM_ONLY 476 | PackageManager.MATCH_ANY_USER 477 | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS 478 | PackageManager.MATCH_DIRECT_BOOT_AWARE 479 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; 480 481 /** 482 * Whether we should allow apps into the 483 * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not. 484 * If false, any attempts to put an app into the bucket will put the app into the 485 * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RARE} bucket instead. 486 */ 487 private boolean mAllowRestrictedBucket; 488 489 private volatile boolean mAppIdleEnabled; 490 private volatile boolean mIsCharging; 491 private boolean mSystemServicesReady = false; 492 // There was a system update, defaults need to be initialized after services are ready 493 private boolean mPendingInitializeDefaults; 494 495 private volatile boolean mPendingOneTimeCheckIdleStates; 496 497 private final AppStandbyHandler mHandler; 498 private final Context mContext; 499 500 private AppWidgetManager mAppWidgetManager; 501 private PackageManager mPackageManager; 502 Injector mInjector; 503 504 private static class Pool<T> { 505 private final T[] mArray; 506 private int mSize = 0; 507 Pool(T[] array)508 Pool(T[] array) { 509 mArray = array; 510 } 511 512 @Nullable obtain()513 synchronized T obtain() { 514 return mSize > 0 ? mArray[--mSize] : null; 515 } 516 recycle(T instance)517 synchronized void recycle(T instance) { 518 if (mSize < mArray.length) { 519 mArray[mSize++] = instance; 520 } 521 } 522 } 523 524 private static class StandbyUpdateRecord { 525 private static final Pool<StandbyUpdateRecord> sPool = 526 new Pool<>(new StandbyUpdateRecord[10]); 527 528 // Identity of the app whose standby state has changed 529 String packageName; 530 int userId; 531 532 // What the standby bucket the app is now in 533 int bucket; 534 535 // Whether the bucket change is because the user has started interacting with the app 536 boolean isUserInteraction; 537 538 // Reason for bucket change 539 int reason; 540 obtain(String pkgName, int userId, int bucket, int reason, boolean isInteraction)541 public static StandbyUpdateRecord obtain(String pkgName, int userId, 542 int bucket, int reason, boolean isInteraction) { 543 StandbyUpdateRecord r = sPool.obtain(); 544 if (r == null) { 545 r = new StandbyUpdateRecord(); 546 } 547 r.packageName = pkgName; 548 r.userId = userId; 549 r.bucket = bucket; 550 r.reason = reason; 551 r.isUserInteraction = isInteraction; 552 return r; 553 554 } 555 recycle()556 public void recycle() { 557 sPool.recycle(this); 558 } 559 } 560 561 private static class ContentProviderUsageRecord { 562 private static final Pool<ContentProviderUsageRecord> sPool = 563 new Pool<>(new ContentProviderUsageRecord[10]); 564 565 public String name; 566 public String packageName; 567 public int userId; 568 obtain(String name, String packageName, int userId)569 public static ContentProviderUsageRecord obtain(String name, String packageName, 570 int userId) { 571 ContentProviderUsageRecord r = sPool.obtain(); 572 if (r == null) { 573 r = new ContentProviderUsageRecord(); 574 } 575 r.name = name; 576 r.packageName = packageName; 577 r.userId = userId; 578 return r; 579 } 580 recycle()581 public void recycle() { 582 sPool.recycle(this); 583 } 584 } 585 AppStandbyController(Context context)586 public AppStandbyController(Context context) { 587 this(new Injector(context, JobSchedulerBackgroundThread.get().getLooper())); 588 } 589 AppStandbyController(Injector injector)590 AppStandbyController(Injector injector) { 591 mInjector = injector; 592 mContext = mInjector.getContext(); 593 mHandler = new AppStandbyHandler(mInjector.getLooper()); 594 mPackageManager = mContext.getPackageManager(); 595 596 DeviceStateReceiver deviceStateReceiver = new DeviceStateReceiver(); 597 IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING); 598 deviceStates.addAction(BatteryManager.ACTION_DISCHARGING); 599 deviceStates.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED); 600 mContext.registerReceiver(deviceStateReceiver, deviceStates); 601 602 synchronized (mAppIdleLock) { 603 mAppIdleHistory = new AppIdleHistory(mInjector.getDataSystemDirectory(), 604 mInjector.elapsedRealtime()); 605 } 606 607 IntentFilter packageFilter = new IntentFilter(); 608 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 609 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 610 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 611 packageFilter.addDataScheme("package"); 612 613 mContext.registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter, 614 null, mHandler); 615 } 616 617 @VisibleForTesting setAppIdleEnabled(boolean enabled)618 void setAppIdleEnabled(boolean enabled) { 619 // Don't call out to USM with the lock held. Also, register the listener before we 620 // change our internal state so no events fall through the cracks. 621 final UsageStatsManagerInternal usmi = 622 LocalServices.getService(UsageStatsManagerInternal.class); 623 if (enabled) { 624 usmi.registerListener(this); 625 } else { 626 usmi.unregisterListener(this); 627 } 628 629 synchronized (mAppIdleLock) { 630 if (mAppIdleEnabled != enabled) { 631 final boolean oldParoleState = isInParole(); 632 mAppIdleEnabled = enabled; 633 634 if (isInParole() != oldParoleState) { 635 postParoleStateChanged(); 636 } 637 } 638 } 639 } 640 641 @Override isAppIdleEnabled()642 public boolean isAppIdleEnabled() { 643 return mAppIdleEnabled; 644 } 645 646 @Override onBootPhase(int phase)647 public void onBootPhase(int phase) { 648 mInjector.onBootPhase(phase); 649 if (phase == PHASE_SYSTEM_SERVICES_READY) { 650 Slog.d(TAG, "Setting app idle enabled state"); 651 652 if (mAppIdleEnabled) { 653 LocalServices.getService(UsageStatsManagerInternal.class).registerListener(this); 654 } 655 656 // Observe changes to the threshold 657 ConstantsObserver settingsObserver = new ConstantsObserver(mHandler); 658 settingsObserver.start(); 659 660 mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class); 661 662 mInjector.registerDisplayListener(mDisplayListener, mHandler); 663 synchronized (mAppIdleLock) { 664 mAppIdleHistory.updateDisplay(isDisplayOn(), mInjector.elapsedRealtime()); 665 } 666 667 mSystemServicesReady = true; 668 669 boolean userFileExists; 670 synchronized (mAppIdleLock) { 671 userFileExists = mAppIdleHistory.userFileExists(UserHandle.USER_SYSTEM); 672 } 673 674 if (mPendingInitializeDefaults || !userFileExists) { 675 initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM); 676 } 677 678 if (mPendingOneTimeCheckIdleStates) { 679 postOneTimeCheckIdleStates(); 680 } 681 682 // Populate list of system packages and their app-ids. 683 final List<ApplicationInfo> systemApps = mPackageManager.getInstalledApplications( 684 SYSTEM_PACKAGE_FLAGS); 685 for (int i = 0, size = systemApps.size(); i < size; i++) { 686 final ApplicationInfo appInfo = systemApps.get(i); 687 mSystemPackagesAppIds.add(UserHandle.getAppId(appInfo.uid)); 688 } 689 } else if (phase == PHASE_BOOT_COMPLETED) { 690 setChargingState(mInjector.isCharging()); 691 692 // Offload to handler thread after boot completed to avoid boot time impact. This means 693 // that app standby buckets may be slightly out of date and headless system apps may be 694 // put in a lower bucket until boot has completed. 695 mHandler.post(AppStandbyController.this::updatePowerWhitelistCache); 696 mHandler.post(this::loadHeadlessSystemAppCache); 697 } 698 } 699 reportContentProviderUsage(String authority, String providerPkgName, int userId)700 private void reportContentProviderUsage(String authority, String providerPkgName, int userId) { 701 if (!mAppIdleEnabled) return; 702 703 // Get sync adapters for the authority 704 String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser( 705 authority, userId); 706 final PackageManagerInternal pmi = mInjector.getPackageManagerInternal(); 707 final long elapsedRealtime = mInjector.elapsedRealtime(); 708 for (String packageName : packages) { 709 // Don't force the sync adapter to active if the provider is in the same APK. 710 if (packageName.equals(providerPkgName)) { 711 continue; 712 } 713 714 final int appId = UserHandle.getAppId(pmi.getPackageUid(packageName, 0, userId)); 715 // Elevate the sync adapter to active if it's a system app or 716 // is a non-system app and shares its app id with a system app. 717 if (mSystemPackagesAppIds.contains(appId)) { 718 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, 719 userId); 720 synchronized (mAppIdleLock) { 721 reportNoninteractiveUsageCrossUserLocked(packageName, userId, 722 STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER, 723 elapsedRealtime, mSyncAdapterTimeoutMillis, linkedProfiles); 724 } 725 } 726 } 727 } 728 reportExemptedSyncScheduled(String packageName, int userId)729 private void reportExemptedSyncScheduled(String packageName, int userId) { 730 if (!mAppIdleEnabled) return; 731 732 final int bucketToPromote; 733 final int usageReason; 734 final long durationMillis; 735 736 if (!mInjector.isDeviceIdleMode()) { 737 // Not dozing. 738 bucketToPromote = STANDBY_BUCKET_ACTIVE; 739 usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE; 740 durationMillis = mExemptedSyncScheduledNonDozeTimeoutMillis; 741 } else { 742 // Dozing. 743 bucketToPromote = STANDBY_BUCKET_WORKING_SET; 744 usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE; 745 durationMillis = mExemptedSyncScheduledDozeTimeoutMillis; 746 } 747 748 final long elapsedRealtime = mInjector.elapsedRealtime(); 749 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId); 750 synchronized (mAppIdleLock) { 751 reportNoninteractiveUsageCrossUserLocked(packageName, userId, bucketToPromote, 752 usageReason, elapsedRealtime, durationMillis, linkedProfiles); 753 } 754 } 755 reportUnexemptedSyncScheduled(String packageName, int userId)756 private void reportUnexemptedSyncScheduled(String packageName, int userId) { 757 if (!mAppIdleEnabled) return; 758 759 final long elapsedRealtime = mInjector.elapsedRealtime(); 760 synchronized (mAppIdleLock) { 761 final int currentBucket = 762 mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime); 763 if (currentBucket == STANDBY_BUCKET_NEVER) { 764 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId); 765 // Bring the app out of the never bucket 766 reportNoninteractiveUsageCrossUserLocked(packageName, userId, 767 STANDBY_BUCKET_WORKING_SET, REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED, 768 elapsedRealtime, mUnexemptedSyncScheduledTimeoutMillis, linkedProfiles); 769 } 770 } 771 } 772 reportExemptedSyncStart(String packageName, int userId)773 private void reportExemptedSyncStart(String packageName, int userId) { 774 if (!mAppIdleEnabled) return; 775 776 final long elapsedRealtime = mInjector.elapsedRealtime(); 777 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId); 778 synchronized (mAppIdleLock) { 779 reportNoninteractiveUsageCrossUserLocked(packageName, userId, STANDBY_BUCKET_ACTIVE, 780 REASON_SUB_USAGE_EXEMPTED_SYNC_START, elapsedRealtime, 781 mExemptedSyncStartTimeoutMillis, linkedProfiles); 782 } 783 } 784 785 /** 786 * Helper method to report indirect user usage of an app and handle reporting the usage 787 * against cross profile connected apps. <br> 788 * Use {@link #reportNoninteractiveUsageLocked(String, int, int, int, long, long)} if 789 * cross profile connected apps do not need to be handled. 790 */ reportNoninteractiveUsageCrossUserLocked(String packageName, int userId, int bucket, int subReason, long elapsedRealtime, long nextCheckDelay, List<UserHandle> otherProfiles)791 private void reportNoninteractiveUsageCrossUserLocked(String packageName, int userId, 792 int bucket, int subReason, long elapsedRealtime, long nextCheckDelay, 793 List<UserHandle> otherProfiles) { 794 reportNoninteractiveUsageLocked(packageName, userId, bucket, subReason, elapsedRealtime, 795 nextCheckDelay); 796 final int size = otherProfiles.size(); 797 for (int profileIndex = 0; profileIndex < size; profileIndex++) { 798 final int otherUserId = otherProfiles.get(profileIndex).getIdentifier(); 799 reportNoninteractiveUsageLocked(packageName, otherUserId, bucket, subReason, 800 elapsedRealtime, nextCheckDelay); 801 } 802 } 803 804 /** 805 * Helper method to report indirect user usage of an app. <br> 806 * Use 807 * {@link #reportNoninteractiveUsageCrossUserLocked(String, int, int, int, long, long, List)} 808 * if cross profile connected apps need to be handled. 809 */ reportNoninteractiveUsageLocked(String packageName, int userId, int bucket, int subReason, long elapsedRealtime, long nextCheckDelay)810 private void reportNoninteractiveUsageLocked(String packageName, int userId, int bucket, 811 int subReason, long elapsedRealtime, long nextCheckDelay) { 812 final AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, bucket, 813 subReason, 0, elapsedRealtime + nextCheckDelay); 814 mHandler.sendMessageDelayed( 815 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, packageName), 816 nextCheckDelay); 817 maybeInformListeners(packageName, userId, elapsedRealtime, appUsage.currentBucket, 818 appUsage.bucketingReason, false); 819 } 820 821 /** Trigger a quota bump in the listeners. */ triggerListenerQuotaBump(String packageName, int userId)822 private void triggerListenerQuotaBump(String packageName, int userId) { 823 if (!mAppIdleEnabled) return; 824 825 synchronized (mPackageAccessListeners) { 826 for (AppIdleStateChangeListener listener : mPackageAccessListeners) { 827 listener.triggerTemporaryQuotaBump(packageName, userId); 828 } 829 } 830 } 831 832 @VisibleForTesting setChargingState(boolean isCharging)833 void setChargingState(boolean isCharging) { 834 if (mIsCharging != isCharging) { 835 if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging); 836 mIsCharging = isCharging; 837 postParoleStateChanged(); 838 } 839 } 840 841 @Override isInParole()842 public boolean isInParole() { 843 return !mAppIdleEnabled || mIsCharging; 844 } 845 postParoleStateChanged()846 private void postParoleStateChanged() { 847 if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED"); 848 mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED); 849 mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED); 850 } 851 852 @Override postCheckIdleStates(int userId)853 public void postCheckIdleStates(int userId) { 854 if (userId == UserHandle.USER_ALL) { 855 postOneTimeCheckIdleStates(); 856 } else { 857 synchronized (mPendingIdleStateChecks) { 858 mPendingIdleStateChecks.put(userId, mInjector.elapsedRealtime()); 859 } 860 mHandler.obtainMessage(MSG_CHECK_IDLE_STATES).sendToTarget(); 861 } 862 } 863 864 @Override postOneTimeCheckIdleStates()865 public void postOneTimeCheckIdleStates() { 866 if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) { 867 // Not booted yet; wait for it! 868 mPendingOneTimeCheckIdleStates = true; 869 } else { 870 mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES); 871 mPendingOneTimeCheckIdleStates = false; 872 } 873 } 874 875 @VisibleForTesting checkIdleStates(int checkUserId)876 boolean checkIdleStates(int checkUserId) { 877 if (!mAppIdleEnabled) { 878 return false; 879 } 880 881 final int[] runningUserIds; 882 try { 883 runningUserIds = mInjector.getRunningUserIds(); 884 if (checkUserId != UserHandle.USER_ALL 885 && !ArrayUtils.contains(runningUserIds, checkUserId)) { 886 return false; 887 } 888 } catch (RemoteException re) { 889 throw re.rethrowFromSystemServer(); 890 } 891 892 final long elapsedRealtime = mInjector.elapsedRealtime(); 893 for (int i = 0; i < runningUserIds.length; i++) { 894 final int userId = runningUserIds[i]; 895 if (checkUserId != UserHandle.USER_ALL && checkUserId != userId) { 896 continue; 897 } 898 if (DEBUG) { 899 Slog.d(TAG, "Checking idle state for user " + userId); 900 } 901 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser( 902 PackageManager.MATCH_DISABLED_COMPONENTS, 903 userId); 904 final int packageCount = packages.size(); 905 for (int p = 0; p < packageCount; p++) { 906 final PackageInfo pi = packages.get(p); 907 final String packageName = pi.packageName; 908 checkAndUpdateStandbyState(packageName, userId, pi.applicationInfo.uid, 909 elapsedRealtime); 910 } 911 } 912 if (DEBUG) { 913 Slog.d(TAG, "checkIdleStates took " 914 + (mInjector.elapsedRealtime() - elapsedRealtime)); 915 } 916 return true; 917 } 918 919 /** Check if we need to update the standby state of a specific app. */ checkAndUpdateStandbyState(String packageName, @UserIdInt int userId, int uid, long elapsedRealtime)920 private void checkAndUpdateStandbyState(String packageName, @UserIdInt int userId, 921 int uid, long elapsedRealtime) { 922 if (uid <= 0) { 923 try { 924 uid = mPackageManager.getPackageUidAsUser(packageName, userId); 925 } catch (PackageManager.NameNotFoundException e) { 926 // Not a valid package for this user, nothing to do 927 // TODO: Remove any history of removed packages 928 return; 929 } 930 } 931 final int minBucket = getAppMinBucket(packageName, 932 UserHandle.getAppId(uid), 933 userId); 934 if (DEBUG) { 935 Slog.d(TAG, " Checking idle state for " + packageName 936 + " minBucket=" + standbyBucketToString(minBucket)); 937 } 938 if (minBucket <= STANDBY_BUCKET_ACTIVE) { 939 // No extra processing needed for ACTIVE or higher since apps can't drop into lower 940 // buckets. 941 synchronized (mAppIdleLock) { 942 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, 943 minBucket, REASON_MAIN_DEFAULT); 944 } 945 maybeInformListeners(packageName, userId, elapsedRealtime, 946 minBucket, REASON_MAIN_DEFAULT, false); 947 } else { 948 synchronized (mAppIdleLock) { 949 final AppIdleHistory.AppUsageHistory app = 950 mAppIdleHistory.getAppUsageHistory(packageName, 951 userId, elapsedRealtime); 952 int reason = app.bucketingReason; 953 final int oldMainReason = reason & REASON_MAIN_MASK; 954 955 // If the bucket was forced by the user/developer, leave it alone. 956 // A usage event will be the only way to bring it out of this forced state 957 if (oldMainReason == REASON_MAIN_FORCED_BY_USER) { 958 return; 959 } 960 final int oldBucket = app.currentBucket; 961 if (oldBucket == STANDBY_BUCKET_NEVER) { 962 // None of this should bring an app out of the NEVER bucket. 963 return; 964 } 965 int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED 966 boolean predictionLate = predictionTimedOut(app, elapsedRealtime); 967 // Compute age-based bucket 968 if (oldMainReason == REASON_MAIN_DEFAULT 969 || oldMainReason == REASON_MAIN_USAGE 970 || oldMainReason == REASON_MAIN_TIMEOUT 971 || predictionLate) { 972 973 if (!predictionLate && app.lastPredictedBucket >= STANDBY_BUCKET_ACTIVE 974 && app.lastPredictedBucket <= STANDBY_BUCKET_RARE) { 975 newBucket = app.lastPredictedBucket; 976 reason = REASON_MAIN_PREDICTED | REASON_SUB_PREDICTED_RESTORED; 977 if (DEBUG) { 978 Slog.d(TAG, "Restored predicted newBucket = " 979 + standbyBucketToString(newBucket)); 980 } 981 } else { 982 // Don't update the standby state for apps that were restored 983 if (!(oldMainReason == REASON_MAIN_DEFAULT 984 && (app.bucketingReason & REASON_SUB_MASK) 985 == REASON_SUB_DEFAULT_APP_RESTORED)) { 986 newBucket = getBucketForLocked(packageName, userId, elapsedRealtime); 987 if (DEBUG) { 988 Slog.d(TAG, "Evaluated AOSP newBucket = " 989 + standbyBucketToString(newBucket)); 990 } 991 reason = REASON_MAIN_TIMEOUT; 992 } 993 } 994 } 995 996 // Check if the app is within one of the expiry times for forced bucket elevation 997 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime); 998 final int bucketWithValidExpiryTime = getMinBucketWithValidExpiryTime(app, 999 newBucket, elapsedTimeAdjusted); 1000 if (bucketWithValidExpiryTime != STANDBY_BUCKET_UNKNOWN) { 1001 newBucket = bucketWithValidExpiryTime; 1002 if (newBucket == STANDBY_BUCKET_ACTIVE || app.currentBucket == newBucket) { 1003 reason = app.bucketingReason; 1004 } else { 1005 reason = REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT; 1006 } 1007 if (DEBUG) { 1008 Slog.d(TAG, " Keeping at " + standbyBucketToString(newBucket) 1009 + " due to min timeout"); 1010 } 1011 } 1012 1013 if (app.lastUsedByUserElapsedTime >= 0 1014 && app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime 1015 && elapsedTimeAdjusted - app.lastUsedByUserElapsedTime 1016 >= mInjector.getAutoRestrictedBucketDelayMs()) { 1017 newBucket = STANDBY_BUCKET_RESTRICTED; 1018 reason = app.lastRestrictReason; 1019 if (DEBUG) { 1020 Slog.d(TAG, "Bringing down to RESTRICTED due to timeout"); 1021 } 1022 } 1023 if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) { 1024 newBucket = STANDBY_BUCKET_RARE; 1025 // Leave the reason alone. 1026 if (DEBUG) { 1027 Slog.d(TAG, "Bringing up from RESTRICTED to RARE due to off switch"); 1028 } 1029 } 1030 if (newBucket > minBucket) { 1031 newBucket = minBucket; 1032 // Leave the reason alone. 1033 if (DEBUG) { 1034 Slog.d(TAG, "Bringing up from " + standbyBucketToString(newBucket) 1035 + " to " + standbyBucketToString(minBucket) 1036 + " due to min bucketing"); 1037 } 1038 } 1039 if (DEBUG) { 1040 Slog.d(TAG, " Old bucket=" + standbyBucketToString(oldBucket) 1041 + ", newBucket=" + standbyBucketToString(newBucket)); 1042 } 1043 if (oldBucket != newBucket || predictionLate) { 1044 mAppIdleHistory.setAppStandbyBucket(packageName, userId, 1045 elapsedRealtime, newBucket, reason); 1046 maybeInformListeners(packageName, userId, elapsedRealtime, 1047 newBucket, reason, false); 1048 } 1049 } 1050 } 1051 } 1052 1053 /** Returns true if there hasn't been a prediction for the app in a while. */ predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime)1054 private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) { 1055 return app.lastPredictedTime > 0 1056 && mAppIdleHistory.getElapsedTime(elapsedRealtime) 1057 - app.lastPredictedTime > mPredictionTimeoutMillis; 1058 } 1059 1060 /** 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)1061 private void maybeInformListeners(String packageName, int userId, 1062 long elapsedRealtime, int bucket, int reason, boolean userStartedInteracting) { 1063 synchronized (mAppIdleLock) { 1064 if (mAppIdleHistory.shouldInformListeners(packageName, userId, 1065 elapsedRealtime, bucket)) { 1066 final StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId, 1067 bucket, reason, userStartedInteracting); 1068 if (DEBUG) Slog.d(TAG, "Standby bucket for " + packageName + "=" + bucket); 1069 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, r)); 1070 } 1071 } 1072 } 1073 1074 /** 1075 * Evaluates next bucket based on time since last used and the bucketing thresholds. 1076 * @param packageName the app 1077 * @param userId the user 1078 * @param elapsedRealtime as the name suggests, current elapsed time 1079 * @return the bucket for the app, based on time since last used 1080 */ 1081 @GuardedBy("mAppIdleLock") 1082 @StandbyBuckets getBucketForLocked(String packageName, int userId, long elapsedRealtime)1083 private int getBucketForLocked(String packageName, int userId, 1084 long elapsedRealtime) { 1085 int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId, 1086 elapsedRealtime, mAppStandbyScreenThresholds, mAppStandbyElapsedThresholds); 1087 return bucketIndex >= 0 ? THRESHOLD_BUCKETS[bucketIndex] : STANDBY_BUCKET_NEVER; 1088 } 1089 notifyBatteryStats(String packageName, int userId, boolean idle)1090 private void notifyBatteryStats(String packageName, int userId, boolean idle) { 1091 try { 1092 final int uid = mPackageManager.getPackageUidAsUser(packageName, 1093 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); 1094 if (idle) { 1095 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE, 1096 packageName, uid); 1097 } else { 1098 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE, 1099 packageName, uid); 1100 } 1101 } catch (PackageManager.NameNotFoundException | RemoteException e) { 1102 } 1103 } 1104 1105 /** 1106 * Callback to inform listeners of a new event. 1107 */ onUsageEvent(int userId, @NonNull UsageEvents.Event event)1108 public void onUsageEvent(int userId, @NonNull UsageEvents.Event event) { 1109 if (!mAppIdleEnabled) return; 1110 final int eventType = event.getEventType(); 1111 if ((eventType == UsageEvents.Event.ACTIVITY_RESUMED 1112 || eventType == UsageEvents.Event.ACTIVITY_PAUSED 1113 || eventType == UsageEvents.Event.SYSTEM_INTERACTION 1114 || eventType == UsageEvents.Event.USER_INTERACTION 1115 || eventType == UsageEvents.Event.NOTIFICATION_SEEN 1116 || eventType == UsageEvents.Event.SLICE_PINNED 1117 || eventType == UsageEvents.Event.SLICE_PINNED_PRIV 1118 || eventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) { 1119 final String pkg = event.getPackageName(); 1120 final List<UserHandle> linkedProfiles = getCrossProfileTargets(pkg, userId); 1121 synchronized (mAppIdleLock) { 1122 final long elapsedRealtime = mInjector.elapsedRealtime(); 1123 reportEventLocked(pkg, eventType, elapsedRealtime, userId); 1124 1125 final int size = linkedProfiles.size(); 1126 for (int profileIndex = 0; profileIndex < size; profileIndex++) { 1127 final int linkedUserId = linkedProfiles.get(profileIndex).getIdentifier(); 1128 reportEventLocked(pkg, eventType, elapsedRealtime, linkedUserId); 1129 } 1130 } 1131 } 1132 } 1133 1134 @GuardedBy("mAppIdleLock") reportEventLocked(String pkg, int eventType, long elapsedRealtime, int userId)1135 private void reportEventLocked(String pkg, int eventType, long elapsedRealtime, int userId) { 1136 // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back 1137 // about apps that are on some kind of whitelist anyway. 1138 final boolean previouslyIdle = mAppIdleHistory.isIdle( 1139 pkg, userId, elapsedRealtime); 1140 1141 final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory( 1142 pkg, userId, elapsedRealtime); 1143 final int prevBucket = appHistory.currentBucket; 1144 final int prevBucketReason = appHistory.bucketingReason; 1145 final long nextCheckDelay; 1146 final int subReason = usageEventToSubReason(eventType); 1147 final int reason = REASON_MAIN_USAGE | subReason; 1148 if (eventType == UsageEvents.Event.NOTIFICATION_SEEN) { 1149 final int notificationSeenPromotedBucket; 1150 final long notificationSeenTimeoutMillis; 1151 if (mRetainNotificationSeenImpactForPreTApps 1152 && getTargetSdkVersion(pkg) < Build.VERSION_CODES.TIRAMISU) { 1153 notificationSeenPromotedBucket = 1154 NOTIFICATION_SEEN_PROMOTED_BUCKET_FOR_PRE_T_APPS; 1155 notificationSeenTimeoutMillis = 1156 NOTIFICATION_SEEN_HOLD_DURATION_FOR_PRE_T_APPS; 1157 } else { 1158 if (mTriggerQuotaBumpOnNotificationSeen) { 1159 mHandler.obtainMessage(MSG_TRIGGER_LISTENER_QUOTA_BUMP, userId, -1, pkg) 1160 .sendToTarget(); 1161 } 1162 notificationSeenPromotedBucket = mNotificationSeenPromotedBucket; 1163 notificationSeenTimeoutMillis = mNotificationSeenTimeoutMillis; 1164 } 1165 // Notification-seen elevates to a higher bucket (depending on 1166 // {@link ConstantsObserver#KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET}) but doesn't 1167 // change usage time. 1168 mAppIdleHistory.reportUsage(appHistory, pkg, userId, 1169 notificationSeenPromotedBucket, subReason, 1170 0, elapsedRealtime + notificationSeenTimeoutMillis); 1171 nextCheckDelay = notificationSeenTimeoutMillis; 1172 } else if (eventType == UsageEvents.Event.SLICE_PINNED) { 1173 // Mild usage elevates to WORKING_SET but doesn't change usage time. 1174 mAppIdleHistory.reportUsage(appHistory, pkg, userId, 1175 STANDBY_BUCKET_WORKING_SET, subReason, 1176 0, elapsedRealtime + mSlicePinnedTimeoutMillis); 1177 nextCheckDelay = mSlicePinnedTimeoutMillis; 1178 } else if (eventType == UsageEvents.Event.SYSTEM_INTERACTION) { 1179 mAppIdleHistory.reportUsage(appHistory, pkg, userId, 1180 STANDBY_BUCKET_ACTIVE, subReason, 1181 0, elapsedRealtime + mSystemInteractionTimeoutMillis); 1182 nextCheckDelay = mSystemInteractionTimeoutMillis; 1183 } else if (eventType == UsageEvents.Event.FOREGROUND_SERVICE_START) { 1184 // Only elevate bucket if this is the first usage of the app 1185 if (prevBucket != STANDBY_BUCKET_NEVER) return; 1186 mAppIdleHistory.reportUsage(appHistory, pkg, userId, 1187 STANDBY_BUCKET_ACTIVE, subReason, 1188 0, elapsedRealtime + mInitialForegroundServiceStartTimeoutMillis); 1189 nextCheckDelay = mInitialForegroundServiceStartTimeoutMillis; 1190 } else { 1191 mAppIdleHistory.reportUsage(appHistory, pkg, userId, 1192 STANDBY_BUCKET_ACTIVE, subReason, 1193 elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis); 1194 nextCheckDelay = mStrongUsageTimeoutMillis; 1195 } 1196 if (appHistory.currentBucket != prevBucket) { 1197 mHandler.sendMessageDelayed( 1198 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkg), 1199 nextCheckDelay); 1200 final boolean userStartedInteracting = 1201 appHistory.currentBucket == STANDBY_BUCKET_ACTIVE 1202 && (prevBucketReason & REASON_MAIN_MASK) != REASON_MAIN_USAGE; 1203 maybeInformListeners(pkg, userId, elapsedRealtime, 1204 appHistory.currentBucket, reason, userStartedInteracting); 1205 } 1206 1207 if (previouslyIdle) { 1208 notifyBatteryStats(pkg, userId, false); 1209 } 1210 } 1211 getTargetSdkVersion(String packageName)1212 private int getTargetSdkVersion(String packageName) { 1213 return mInjector.getPackageManagerInternal().getPackageTargetSdkVersion(packageName); 1214 } 1215 1216 /** 1217 * Returns the lowest standby bucket that is better than {@code targetBucket} and has an 1218 * valid expiry time (i.e. the expiry time is not yet elapsed). 1219 */ getMinBucketWithValidExpiryTime(AppUsageHistory usageHistory, int targetBucket, long elapsedTimeMs)1220 private int getMinBucketWithValidExpiryTime(AppUsageHistory usageHistory, 1221 int targetBucket, long elapsedTimeMs) { 1222 if (usageHistory.bucketExpiryTimesMs == null) { 1223 return STANDBY_BUCKET_UNKNOWN; 1224 } 1225 final int size = usageHistory.bucketExpiryTimesMs.size(); 1226 for (int i = 0; i < size; ++i) { 1227 final int bucket = usageHistory.bucketExpiryTimesMs.keyAt(i); 1228 if (targetBucket <= bucket) { 1229 break; 1230 } 1231 final long expiryTimeMs = usageHistory.bucketExpiryTimesMs.valueAt(i); 1232 if (expiryTimeMs > elapsedTimeMs) { 1233 return bucket; 1234 } 1235 } 1236 return STANDBY_BUCKET_UNKNOWN; 1237 } 1238 1239 /** 1240 * Note: don't call this with the lock held since it makes calls to other system services. 1241 */ getCrossProfileTargets(String pkg, int userId)1242 private @NonNull List<UserHandle> getCrossProfileTargets(String pkg, int userId) { 1243 synchronized (mAppIdleLock) { 1244 if (!mLinkCrossProfileApps) return Collections.emptyList(); 1245 } 1246 return mInjector.getValidCrossProfileTargets(pkg, userId); 1247 } 1248 usageEventToSubReason(int eventType)1249 private int usageEventToSubReason(int eventType) { 1250 switch (eventType) { 1251 case UsageEvents.Event.ACTIVITY_RESUMED: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND; 1252 case UsageEvents.Event.ACTIVITY_PAUSED: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND; 1253 case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION; 1254 case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION; 1255 case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN; 1256 case UsageEvents.Event.SLICE_PINNED: return REASON_SUB_USAGE_SLICE_PINNED; 1257 case UsageEvents.Event.SLICE_PINNED_PRIV: return REASON_SUB_USAGE_SLICE_PINNED_PRIV; 1258 case UsageEvents.Event.FOREGROUND_SERVICE_START: 1259 return REASON_SUB_USAGE_FOREGROUND_SERVICE_START; 1260 default: return 0; 1261 } 1262 } 1263 1264 @VisibleForTesting forceIdleState(String packageName, int userId, boolean idle)1265 void forceIdleState(String packageName, int userId, boolean idle) { 1266 if (!mAppIdleEnabled) return; 1267 1268 final int appId = getAppId(packageName); 1269 if (appId < 0) return; 1270 final int minBucket = getAppMinBucket(packageName, appId, userId); 1271 if (idle && minBucket < AppIdleHistory.IDLE_BUCKET_CUTOFF) { 1272 Slog.e(TAG, "Tried to force an app to be idle when its min bucket is " 1273 + standbyBucketToString(minBucket)); 1274 return; 1275 } 1276 final long elapsedRealtime = mInjector.elapsedRealtime(); 1277 1278 final boolean previouslyIdle = isAppIdleFiltered(packageName, appId, 1279 userId, elapsedRealtime); 1280 final int standbyBucket; 1281 synchronized (mAppIdleLock) { 1282 standbyBucket = mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime); 1283 } 1284 final boolean stillIdle = isAppIdleFiltered(packageName, appId, 1285 userId, elapsedRealtime); 1286 // Inform listeners if necessary 1287 maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket, 1288 REASON_MAIN_FORCED_BY_USER, false); 1289 if (previouslyIdle != stillIdle) { 1290 notifyBatteryStats(packageName, userId, stillIdle); 1291 } 1292 } 1293 1294 @Override setLastJobRunTime(String packageName, int userId, long elapsedRealtime)1295 public void setLastJobRunTime(String packageName, int userId, long elapsedRealtime) { 1296 synchronized (mAppIdleLock) { 1297 mAppIdleHistory.setLastJobRunTime(packageName, userId, elapsedRealtime); 1298 } 1299 } 1300 1301 @Override getTimeSinceLastJobRun(String packageName, int userId)1302 public long getTimeSinceLastJobRun(String packageName, int userId) { 1303 final long elapsedRealtime = mInjector.elapsedRealtime(); 1304 synchronized (mAppIdleLock) { 1305 return mAppIdleHistory.getTimeSinceLastJobRun(packageName, userId, elapsedRealtime); 1306 } 1307 } 1308 1309 @Override setEstimatedLaunchTime(String packageName, int userId, @CurrentTimeMillisLong long launchTime)1310 public void setEstimatedLaunchTime(String packageName, int userId, 1311 @CurrentTimeMillisLong long launchTime) { 1312 final long nowElapsed = mInjector.elapsedRealtime(); 1313 synchronized (mAppIdleLock) { 1314 mAppIdleHistory.setEstimatedLaunchTime(packageName, userId, nowElapsed, launchTime); 1315 } 1316 } 1317 1318 @Override 1319 @CurrentTimeMillisLong getEstimatedLaunchTime(String packageName, int userId)1320 public long getEstimatedLaunchTime(String packageName, int userId) { 1321 final long elapsedRealtime = mInjector.elapsedRealtime(); 1322 synchronized (mAppIdleLock) { 1323 return mAppIdleHistory.getEstimatedLaunchTime(packageName, userId, elapsedRealtime); 1324 } 1325 } 1326 1327 @Override getTimeSinceLastUsedByUser(String packageName, int userId)1328 public long getTimeSinceLastUsedByUser(String packageName, int userId) { 1329 final long elapsedRealtime = mInjector.elapsedRealtime(); 1330 synchronized (mAppIdleLock) { 1331 return mAppIdleHistory.getTimeSinceLastUsedByUser(packageName, userId, elapsedRealtime); 1332 } 1333 } 1334 1335 @Override onUserRemoved(int userId)1336 public void onUserRemoved(int userId) { 1337 synchronized (mAppIdleLock) { 1338 mAppIdleHistory.onUserRemoved(userId); 1339 synchronized (mActiveAdminApps) { 1340 mActiveAdminApps.remove(userId); 1341 } 1342 synchronized (mAdminProtectedPackages) { 1343 mAdminProtectedPackages.remove(userId); 1344 } 1345 } 1346 } 1347 isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime)1348 private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) { 1349 synchronized (mAppIdleLock) { 1350 return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime); 1351 } 1352 } 1353 1354 @Override addListener(AppIdleStateChangeListener listener)1355 public void addListener(AppIdleStateChangeListener listener) { 1356 synchronized (mPackageAccessListeners) { 1357 if (!mPackageAccessListeners.contains(listener)) { 1358 mPackageAccessListeners.add(listener); 1359 } 1360 } 1361 } 1362 1363 @Override removeListener(AppIdleStateChangeListener listener)1364 public void removeListener(AppIdleStateChangeListener listener) { 1365 synchronized (mPackageAccessListeners) { 1366 mPackageAccessListeners.remove(listener); 1367 } 1368 } 1369 1370 @Override getAppId(String packageName)1371 public int getAppId(String packageName) { 1372 try { 1373 ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName, 1374 PackageManager.MATCH_ANY_USER 1375 | PackageManager.MATCH_DISABLED_COMPONENTS); 1376 return ai.uid; 1377 } catch (PackageManager.NameNotFoundException re) { 1378 return -1; 1379 } 1380 } 1381 1382 @Override isAppIdleFiltered(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps)1383 public boolean isAppIdleFiltered(String packageName, int userId, long elapsedRealtime, 1384 boolean shouldObfuscateInstantApps) { 1385 if (shouldObfuscateInstantApps && 1386 mInjector.isPackageEphemeral(userId, packageName)) { 1387 return false; 1388 } 1389 return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime); 1390 } 1391 1392 @StandbyBuckets getAppMinBucket(String packageName, int userId)1393 private int getAppMinBucket(String packageName, int userId) { 1394 try { 1395 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId); 1396 return getAppMinBucket(packageName, UserHandle.getAppId(uid), userId); 1397 } catch (PackageManager.NameNotFoundException e) { 1398 // Not a valid package for this user, nothing to do 1399 return STANDBY_BUCKET_NEVER; 1400 } 1401 } 1402 1403 /** 1404 * Return the lowest bucket this app should ever enter. 1405 */ 1406 @StandbyBuckets getAppMinBucket(String packageName, int appId, int userId)1407 private int getAppMinBucket(String packageName, int appId, int userId) { 1408 if (packageName == null) return STANDBY_BUCKET_NEVER; 1409 // If not enabled at all, of course nobody is ever idle. 1410 if (!mAppIdleEnabled) { 1411 return STANDBY_BUCKET_EXEMPTED; 1412 } 1413 if (appId < Process.FIRST_APPLICATION_UID) { 1414 // System uids never go idle. 1415 return STANDBY_BUCKET_EXEMPTED; 1416 } 1417 if (packageName.equals("android")) { 1418 // Nor does the framework (which should be redundant with the above, but for MR1 we will 1419 // retain this for safety). 1420 return STANDBY_BUCKET_EXEMPTED; 1421 } 1422 if (mSystemServicesReady) { 1423 // We allow all whitelisted apps, including those that don't want to be whitelisted 1424 // for idle mode, because app idle (aka app standby) is really not as big an issue 1425 // for controlling who participates vs. doze mode. 1426 if (mInjector.isNonIdleWhitelisted(packageName)) { 1427 return STANDBY_BUCKET_EXEMPTED; 1428 } 1429 1430 if (isActiveDeviceAdmin(packageName, userId)) { 1431 return STANDBY_BUCKET_EXEMPTED; 1432 } 1433 1434 if (isAdminProtectedPackages(packageName, userId)) { 1435 return STANDBY_BUCKET_EXEMPTED; 1436 } 1437 1438 if (isActiveNetworkScorer(packageName)) { 1439 return STANDBY_BUCKET_EXEMPTED; 1440 } 1441 1442 if (mAppWidgetManager != null 1443 && mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) { 1444 return STANDBY_BUCKET_ACTIVE; 1445 } 1446 1447 if (isDeviceProvisioningPackage(packageName)) { 1448 return STANDBY_BUCKET_EXEMPTED; 1449 } 1450 1451 if (mInjector.isWellbeingPackage(packageName)) { 1452 return STANDBY_BUCKET_WORKING_SET; 1453 } 1454 1455 if (mInjector.hasExactAlarmPermission(packageName, UserHandle.getUid(userId, appId))) { 1456 return STANDBY_BUCKET_WORKING_SET; 1457 } 1458 } 1459 1460 // Check this last, as it can be the most expensive check 1461 if (isCarrierApp(packageName)) { 1462 return STANDBY_BUCKET_EXEMPTED; 1463 } 1464 1465 if (isHeadlessSystemApp(packageName)) { 1466 return STANDBY_BUCKET_ACTIVE; 1467 } 1468 1469 if (mPackageManager.checkPermission(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION, 1470 packageName) == PERMISSION_GRANTED) { 1471 return STANDBY_BUCKET_FREQUENT; 1472 } 1473 1474 return STANDBY_BUCKET_NEVER; 1475 } 1476 isHeadlessSystemApp(String packageName)1477 private boolean isHeadlessSystemApp(String packageName) { 1478 synchronized (mHeadlessSystemApps) { 1479 return mHeadlessSystemApps.contains(packageName); 1480 } 1481 } 1482 1483 @Override isAppIdleFiltered(String packageName, int appId, int userId, long elapsedRealtime)1484 public boolean isAppIdleFiltered(String packageName, int appId, int userId, 1485 long elapsedRealtime) { 1486 if (!mAppIdleEnabled || mIsCharging) { 1487 return false; 1488 } 1489 1490 return isAppIdleUnfiltered(packageName, userId, elapsedRealtime) 1491 && getAppMinBucket(packageName, appId, userId) >= AppIdleHistory.IDLE_BUCKET_CUTOFF; 1492 } 1493 isUserUsage(int reason)1494 static boolean isUserUsage(int reason) { 1495 if ((reason & REASON_MAIN_MASK) == REASON_MAIN_USAGE) { 1496 final int subReason = reason & REASON_SUB_MASK; 1497 return subReason == REASON_SUB_USAGE_USER_INTERACTION 1498 || subReason == REASON_SUB_USAGE_MOVE_TO_FOREGROUND; 1499 } 1500 return false; 1501 } 1502 1503 @Override getIdleUidsForUser(int userId)1504 public int[] getIdleUidsForUser(int userId) { 1505 if (!mAppIdleEnabled) { 1506 return EmptyArray.INT; 1507 } 1508 1509 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "getIdleUidsForUser"); 1510 1511 final long elapsedRealtime = mInjector.elapsedRealtime(); 1512 1513 final PackageManagerInternal pmi = mInjector.getPackageManagerInternal(); 1514 final List<ApplicationInfo> apps = pmi.getInstalledApplications(0, userId, Process.myUid()); 1515 if (apps == null) { 1516 return EmptyArray.INT; 1517 } 1518 1519 // State of each uid: Key is the uid, value is whether all the apps in that uid are idle. 1520 final SparseBooleanArray uidIdleStates = new SparseBooleanArray(); 1521 int notIdleCount = 0; 1522 for (int i = apps.size() - 1; i >= 0; i--) { 1523 final ApplicationInfo ai = apps.get(i); 1524 final int index = uidIdleStates.indexOfKey(ai.uid); 1525 1526 final boolean currentIdle = (index < 0) ? true : uidIdleStates.valueAt(index); 1527 1528 final boolean newIdle = currentIdle && isAppIdleFiltered(ai.packageName, 1529 UserHandle.getAppId(ai.uid), userId, elapsedRealtime); 1530 1531 if (currentIdle && !newIdle) { 1532 // This transition from true to false can happen at most once per uid in this loop. 1533 notIdleCount++; 1534 } 1535 if (index < 0) { 1536 uidIdleStates.put(ai.uid, newIdle); 1537 } else { 1538 uidIdleStates.setValueAt(index, newIdle); 1539 } 1540 } 1541 1542 int numIdleUids = uidIdleStates.size() - notIdleCount; 1543 final int[] idleUids = new int[numIdleUids]; 1544 for (int i = uidIdleStates.size() - 1; i >= 0; i--) { 1545 if (uidIdleStates.valueAt(i)) { 1546 idleUids[--numIdleUids] = uidIdleStates.keyAt(i); 1547 } 1548 } 1549 if (DEBUG) { 1550 Slog.d(TAG, "getIdleUids took " + (mInjector.elapsedRealtime() - elapsedRealtime)); 1551 } 1552 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 1553 1554 return idleUids; 1555 } 1556 1557 @Override setAppIdleAsync(String packageName, boolean idle, int userId)1558 public void setAppIdleAsync(String packageName, boolean idle, int userId) { 1559 if (packageName == null || !mAppIdleEnabled) return; 1560 1561 mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName) 1562 .sendToTarget(); 1563 } 1564 1565 @Override getAppStandbyBucket(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps)1566 @StandbyBuckets public int getAppStandbyBucket(String packageName, int userId, 1567 long elapsedRealtime, boolean shouldObfuscateInstantApps) { 1568 if (!mAppIdleEnabled || (shouldObfuscateInstantApps 1569 && mInjector.isPackageEphemeral(userId, packageName))) { 1570 return STANDBY_BUCKET_ACTIVE; 1571 } 1572 1573 synchronized (mAppIdleLock) { 1574 return mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime); 1575 } 1576 } 1577 1578 @Override getAppStandbyBucketReason(String packageName, int userId, long elapsedRealtime)1579 public int getAppStandbyBucketReason(String packageName, int userId, long elapsedRealtime) { 1580 synchronized (mAppIdleLock) { 1581 return mAppIdleHistory.getAppStandbyReason(packageName, userId, elapsedRealtime); 1582 } 1583 } 1584 1585 @Override getAppStandbyBuckets(int userId)1586 public List<AppStandbyInfo> getAppStandbyBuckets(int userId) { 1587 synchronized (mAppIdleLock) { 1588 return mAppIdleHistory.getAppStandbyBuckets(userId, mAppIdleEnabled); 1589 } 1590 } 1591 1592 @Override 1593 @StandbyBuckets getAppMinStandbyBucket(String packageName, int appId, int userId, boolean shouldObfuscateInstantApps)1594 public int getAppMinStandbyBucket(String packageName, int appId, int userId, 1595 boolean shouldObfuscateInstantApps) { 1596 if (shouldObfuscateInstantApps && mInjector.isPackageEphemeral(userId, packageName)) { 1597 return STANDBY_BUCKET_NEVER; 1598 } 1599 synchronized (mAppIdleLock) { 1600 return getAppMinBucket(packageName, appId, userId); 1601 } 1602 } 1603 1604 @Override restrictApp(@onNull String packageName, int userId, @ForcedReasons int restrictReason)1605 public void restrictApp(@NonNull String packageName, int userId, 1606 @ForcedReasons int restrictReason) { 1607 restrictApp(packageName, userId, REASON_MAIN_FORCED_BY_SYSTEM, restrictReason); 1608 } 1609 1610 @Override restrictApp(@onNull String packageName, int userId, int mainReason, @ForcedReasons int restrictReason)1611 public void restrictApp(@NonNull String packageName, int userId, int mainReason, 1612 @ForcedReasons int restrictReason) { 1613 if (mainReason != REASON_MAIN_FORCED_BY_SYSTEM 1614 && mainReason != REASON_MAIN_FORCED_BY_USER) { 1615 Slog.e(TAG, "Tried to restrict app " + packageName + " for an unsupported reason"); 1616 return; 1617 } 1618 // If the package is not installed, don't allow the bucket to be set. 1619 if (!mInjector.isPackageInstalled(packageName, 0, userId)) { 1620 Slog.e(TAG, "Tried to restrict uninstalled app: " + packageName); 1621 return; 1622 } 1623 1624 final int reason = (REASON_MAIN_MASK & mainReason) | (REASON_SUB_MASK & restrictReason); 1625 final long nowElapsed = mInjector.elapsedRealtime(); 1626 final int bucket = mAllowRestrictedBucket ? STANDBY_BUCKET_RESTRICTED : STANDBY_BUCKET_RARE; 1627 setAppStandbyBucket(packageName, userId, bucket, reason, nowElapsed, false); 1628 } 1629 1630 @Override restoreAppsToRare(Set<String> restoredApps, int userId)1631 public void restoreAppsToRare(Set<String> restoredApps, int userId) { 1632 final int reason = REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_APP_RESTORED; 1633 final long nowElapsed = mInjector.elapsedRealtime(); 1634 for (String packageName : restoredApps) { 1635 // If the package is not installed, don't allow the bucket to be set. Instead, add it 1636 // to a list of all packages whose buckets need to be adjusted when installed. 1637 if (!mInjector.isPackageInstalled(packageName, 0, userId)) { 1638 Slog.i(TAG, "Tried to restore bucket for uninstalled app: " + packageName); 1639 mAppsToRestoreToRare.add(userId, packageName); 1640 continue; 1641 } 1642 1643 restoreAppToRare(packageName, userId, nowElapsed, reason); 1644 } 1645 // Clear out the list of restored apps that need to have their standby buckets adjusted 1646 // if they still haven't been installed eight hours after restore. 1647 // Note: if the device reboots within these first 8 hours, this list will be lost since it's 1648 // not persisted - this is the expected behavior for now and may be updated in the future. 1649 mHandler.postDelayed(() -> mAppsToRestoreToRare.remove(userId), 8 * ONE_HOUR); 1650 } 1651 1652 /** Adjust the standby bucket of the given package for the user to RARE. */ restoreAppToRare(String pkgName, int userId, long nowElapsed, int reason)1653 private void restoreAppToRare(String pkgName, int userId, long nowElapsed, int reason) { 1654 final int standbyBucket = getAppStandbyBucket(pkgName, userId, nowElapsed, false); 1655 // Only update the standby bucket to RARE if the app is still in the NEVER bucket. 1656 if (standbyBucket == STANDBY_BUCKET_NEVER) { 1657 setAppStandbyBucket(pkgName, userId, STANDBY_BUCKET_RARE, reason, nowElapsed, false); 1658 } 1659 } 1660 1661 @Override setAppStandbyBucket(@onNull String packageName, int bucket, int userId, int callingUid, int callingPid)1662 public void setAppStandbyBucket(@NonNull String packageName, int bucket, int userId, 1663 int callingUid, int callingPid) { 1664 setAppStandbyBuckets( 1665 Collections.singletonList(new AppStandbyInfo(packageName, bucket)), 1666 userId, callingUid, callingPid); 1667 } 1668 1669 @Override setAppStandbyBuckets(@onNull List<AppStandbyInfo> appBuckets, int userId, int callingUid, int callingPid)1670 public void setAppStandbyBuckets(@NonNull List<AppStandbyInfo> appBuckets, int userId, 1671 int callingUid, int callingPid) { 1672 userId = ActivityManager.handleIncomingUser( 1673 callingPid, callingUid, userId, false, true, "setAppStandbyBucket", null); 1674 final boolean shellCaller = callingUid == Process.ROOT_UID 1675 || callingUid == Process.SHELL_UID; 1676 final int reason; 1677 // The Settings app runs in the system UID but in a separate process. Assume 1678 // things coming from other processes are due to the user. 1679 if ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && callingPid != Process.myPid()) 1680 || shellCaller) { 1681 reason = REASON_MAIN_FORCED_BY_USER; 1682 } else if (UserHandle.isCore(callingUid)) { 1683 reason = REASON_MAIN_FORCED_BY_SYSTEM; 1684 } else { 1685 reason = REASON_MAIN_PREDICTED; 1686 } 1687 final int packageFlags = PackageManager.MATCH_ANY_USER 1688 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 1689 | PackageManager.MATCH_DIRECT_BOOT_AWARE; 1690 final int numApps = appBuckets.size(); 1691 final long elapsedRealtime = mInjector.elapsedRealtime(); 1692 for (int i = 0; i < numApps; ++i) { 1693 final AppStandbyInfo bucketInfo = appBuckets.get(i); 1694 final String packageName = bucketInfo.mPackageName; 1695 final int bucket = bucketInfo.mStandbyBucket; 1696 if (bucket < STANDBY_BUCKET_ACTIVE || bucket > STANDBY_BUCKET_NEVER) { 1697 throw new IllegalArgumentException("Cannot set the standby bucket to " + bucket); 1698 } 1699 final int packageUid = mInjector.getPackageManagerInternal() 1700 .getPackageUid(packageName, packageFlags, userId); 1701 // Caller cannot set their own standby state 1702 if (packageUid == callingUid) { 1703 throw new IllegalArgumentException("Cannot set your own standby bucket"); 1704 } 1705 if (packageUid < 0) { 1706 throw new IllegalArgumentException( 1707 "Cannot set standby bucket for non existent package (" + packageName + ")"); 1708 } 1709 setAppStandbyBucket(packageName, userId, bucket, reason, elapsedRealtime, shellCaller); 1710 } 1711 } 1712 1713 @VisibleForTesting setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason)1714 void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, 1715 int reason) { 1716 setAppStandbyBucket( 1717 packageName, userId, newBucket, reason, mInjector.elapsedRealtime(), false); 1718 } 1719 setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime, boolean resetTimeout)1720 private void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, 1721 int reason, long elapsedRealtime, boolean resetTimeout) { 1722 if (!mAppIdleEnabled) return; 1723 1724 synchronized (mAppIdleLock) { 1725 // If the package is not installed, don't allow the bucket to be set. 1726 if (!mInjector.isPackageInstalled(packageName, 0, userId)) { 1727 Slog.e(TAG, "Tried to set bucket of uninstalled app: " + packageName); 1728 return; 1729 } 1730 if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) { 1731 newBucket = STANDBY_BUCKET_RARE; 1732 } 1733 AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName, 1734 userId, elapsedRealtime); 1735 boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED; 1736 1737 // Don't allow changing bucket if higher than ACTIVE 1738 if (app.currentBucket < STANDBY_BUCKET_ACTIVE) return; 1739 1740 // Don't allow prediction to change from/to NEVER. 1741 if ((app.currentBucket == STANDBY_BUCKET_NEVER || newBucket == STANDBY_BUCKET_NEVER) 1742 && predicted) { 1743 return; 1744 } 1745 1746 final boolean wasForcedBySystem = 1747 (app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM; 1748 1749 // If the bucket was forced, don't allow prediction to override 1750 if (predicted 1751 && ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER 1752 || wasForcedBySystem)) { 1753 return; 1754 } 1755 1756 final boolean isForcedBySystem = 1757 (reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM; 1758 1759 if (app.currentBucket == newBucket && wasForcedBySystem && isForcedBySystem) { 1760 if (newBucket == STANDBY_BUCKET_RESTRICTED) { 1761 mAppIdleHistory 1762 .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason); 1763 } 1764 // Keep track of all restricting reasons 1765 reason = REASON_MAIN_FORCED_BY_SYSTEM 1766 | (app.bucketingReason & REASON_SUB_MASK) 1767 | (reason & REASON_SUB_MASK); 1768 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, 1769 newBucket, reason, resetTimeout); 1770 return; 1771 } 1772 1773 final boolean isForcedByUser = 1774 (reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER; 1775 1776 if (app.currentBucket == STANDBY_BUCKET_RESTRICTED) { 1777 if ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_TIMEOUT) { 1778 if (predicted && newBucket >= STANDBY_BUCKET_RARE) { 1779 // Predicting into RARE or below means we don't expect the user to use the 1780 // app anytime soon, so don't elevate it from RESTRICTED. 1781 return; 1782 } 1783 } else if (!isUserUsage(reason) && !isForcedByUser) { 1784 // If the current bucket is RESTRICTED, only user force or usage should bring 1785 // it out, unless the app was put into the bucket due to timing out. 1786 return; 1787 } 1788 } 1789 1790 if (newBucket == STANDBY_BUCKET_RESTRICTED) { 1791 mAppIdleHistory 1792 .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason); 1793 1794 if (isForcedByUser) { 1795 // Only user force can bypass the delay restriction. If the user forced the 1796 // app into the RESTRICTED bucket, then a toast confirming the action 1797 // shouldn't be surprising. 1798 // Exclude REASON_SUB_FORCED_USER_FLAG_INTERACTION since the RESTRICTED bucket 1799 // isn't directly visible in that flow. 1800 if (Build.IS_DEBUGGABLE 1801 && (reason & REASON_SUB_MASK) 1802 != REASON_SUB_FORCED_USER_FLAG_INTERACTION) { 1803 Toast.makeText(mContext, 1804 // Since AppStandbyController sits low in the lock hierarchy, 1805 // make sure not to call out with the lock held. 1806 mHandler.getLooper(), 1807 mContext.getResources().getString( 1808 R.string.as_app_forced_to_restricted_bucket, packageName), 1809 Toast.LENGTH_SHORT) 1810 .show(); 1811 } else { 1812 Slog.i(TAG, packageName + " restricted by user"); 1813 } 1814 } else { 1815 final long timeUntilRestrictPossibleMs = app.lastUsedByUserElapsedTime 1816 + mInjector.getAutoRestrictedBucketDelayMs() - elapsedRealtime; 1817 if (timeUntilRestrictPossibleMs > 0) { 1818 Slog.w(TAG, "Tried to restrict recently used app: " + packageName 1819 + " due to " + reason); 1820 mHandler.sendMessageDelayed( 1821 mHandler.obtainMessage( 1822 MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, packageName), 1823 timeUntilRestrictPossibleMs); 1824 return; 1825 } 1826 } 1827 } 1828 1829 // If the bucket is required to stay in a higher state for a specified duration, don't 1830 // override unless the duration has passed 1831 if (predicted) { 1832 // Check if the app is within one of the timeouts for forced bucket elevation 1833 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime); 1834 // In case of not using the prediction, just keep track of it for applying after 1835 // ACTIVE or WORKING_SET timeout. 1836 mAppIdleHistory.updateLastPrediction(app, elapsedTimeAdjusted, newBucket); 1837 1838 final int bucketWithValidExpiryTime = getMinBucketWithValidExpiryTime(app, 1839 newBucket, elapsedTimeAdjusted); 1840 if (bucketWithValidExpiryTime != STANDBY_BUCKET_UNKNOWN) { 1841 newBucket = bucketWithValidExpiryTime; 1842 if (newBucket == STANDBY_BUCKET_ACTIVE || app.currentBucket == newBucket) { 1843 reason = app.bucketingReason; 1844 } else { 1845 reason = REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT; 1846 } 1847 if (DEBUG) { 1848 Slog.d(TAG, " Keeping at " + standbyBucketToString(newBucket) 1849 + " due to min timeout"); 1850 } 1851 } else if (newBucket == STANDBY_BUCKET_RARE 1852 && mAllowRestrictedBucket 1853 && getBucketForLocked(packageName, userId, elapsedRealtime) 1854 == STANDBY_BUCKET_RESTRICTED) { 1855 // Prediction doesn't think the app will be used anytime soon and 1856 // it's been long enough that it could just time out into restricted, 1857 // so time it out there instead. Using TIMEOUT will allow prediction 1858 // to raise the bucket when it needs to. 1859 newBucket = STANDBY_BUCKET_RESTRICTED; 1860 reason = REASON_MAIN_TIMEOUT; 1861 if (DEBUG) { 1862 Slog.d(TAG, 1863 "Prediction to RARE overridden by timeout into RESTRICTED"); 1864 } 1865 } 1866 } 1867 1868 // Make sure we don't put the app in a lower bucket than it's supposed to be in. 1869 newBucket = Math.min(newBucket, getAppMinBucket(packageName, userId)); 1870 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, 1871 reason, resetTimeout); 1872 } 1873 maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, reason, false); 1874 } 1875 1876 @VisibleForTesting 1877 @Override isActiveDeviceAdmin(String packageName, int userId)1878 public boolean isActiveDeviceAdmin(String packageName, int userId) { 1879 synchronized (mActiveAdminApps) { 1880 final Set<String> adminPkgs = mActiveAdminApps.get(userId); 1881 return adminPkgs != null && adminPkgs.contains(packageName); 1882 } 1883 } 1884 isAdminProtectedPackages(String packageName, int userId)1885 private boolean isAdminProtectedPackages(String packageName, int userId) { 1886 synchronized (mAdminProtectedPackages) { 1887 if (mAdminProtectedPackages.contains(UserHandle.USER_ALL) 1888 && mAdminProtectedPackages.get(UserHandle.USER_ALL).contains(packageName)) { 1889 return true; 1890 } 1891 return mAdminProtectedPackages.contains(userId) 1892 && mAdminProtectedPackages.get(userId).contains(packageName); 1893 } 1894 } 1895 1896 @Override addActiveDeviceAdmin(String adminPkg, int userId)1897 public void addActiveDeviceAdmin(String adminPkg, int userId) { 1898 synchronized (mActiveAdminApps) { 1899 Set<String> adminPkgs = mActiveAdminApps.get(userId); 1900 if (adminPkgs == null) { 1901 adminPkgs = new ArraySet<>(); 1902 mActiveAdminApps.put(userId, adminPkgs); 1903 } 1904 adminPkgs.add(adminPkg); 1905 } 1906 } 1907 1908 @Override setActiveAdminApps(Set<String> adminPkgs, int userId)1909 public void setActiveAdminApps(Set<String> adminPkgs, int userId) { 1910 synchronized (mActiveAdminApps) { 1911 if (adminPkgs == null) { 1912 mActiveAdminApps.remove(userId); 1913 } else { 1914 mActiveAdminApps.put(userId, adminPkgs); 1915 } 1916 } 1917 } 1918 1919 @Override setAdminProtectedPackages(Set<String> packageNames, int userId)1920 public void setAdminProtectedPackages(Set<String> packageNames, int userId) { 1921 synchronized (mAdminProtectedPackages) { 1922 if (packageNames == null || packageNames.isEmpty()) { 1923 mAdminProtectedPackages.remove(userId); 1924 } else { 1925 mAdminProtectedPackages.put(userId, packageNames); 1926 } 1927 } 1928 } 1929 1930 @Override onAdminDataAvailable()1931 public void onAdminDataAvailable() { 1932 mAdminDataAvailableLatch.countDown(); 1933 } 1934 1935 /** 1936 * This will only ever be called once - during device boot. 1937 */ waitForAdminData()1938 private void waitForAdminData() { 1939 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) { 1940 ConcurrentUtils.waitForCountDownNoInterrupt(mAdminDataAvailableLatch, 1941 WAIT_FOR_ADMIN_DATA_TIMEOUT_MS, "Wait for admin data"); 1942 } 1943 } 1944 1945 @VisibleForTesting getActiveAdminAppsForTest(int userId)1946 Set<String> getActiveAdminAppsForTest(int userId) { 1947 synchronized (mActiveAdminApps) { 1948 return mActiveAdminApps.get(userId); 1949 } 1950 } 1951 1952 @VisibleForTesting getAdminProtectedPackagesForTest(int userId)1953 Set<String> getAdminProtectedPackagesForTest(int userId) { 1954 synchronized (mAdminProtectedPackages) { 1955 return mAdminProtectedPackages.get(userId); 1956 } 1957 } 1958 1959 /** 1960 * Returns {@code true} if the supplied package is the device provisioning app. Otherwise, 1961 * returns {@code false}. 1962 */ isDeviceProvisioningPackage(String packageName)1963 private boolean isDeviceProvisioningPackage(String packageName) { 1964 if (mCachedDeviceProvisioningPackage == null) { 1965 mCachedDeviceProvisioningPackage = mContext.getResources().getString( 1966 com.android.internal.R.string.config_deviceProvisioningPackage); 1967 } 1968 return mCachedDeviceProvisioningPackage.equals(packageName); 1969 } 1970 isCarrierApp(String packageName)1971 private boolean isCarrierApp(String packageName) { 1972 synchronized (mCarrierPrivilegedLock) { 1973 if (!mHaveCarrierPrivilegedApps) { 1974 fetchCarrierPrivilegedAppsCPL(); 1975 } 1976 if (mCarrierPrivilegedApps != null) { 1977 return mCarrierPrivilegedApps.contains(packageName); 1978 } 1979 return false; 1980 } 1981 } 1982 1983 @Override clearCarrierPrivilegedApps()1984 public void clearCarrierPrivilegedApps() { 1985 if (DEBUG) { 1986 Slog.i(TAG, "Clearing carrier privileged apps list"); 1987 } 1988 synchronized (mCarrierPrivilegedLock) { 1989 mHaveCarrierPrivilegedApps = false; 1990 mCarrierPrivilegedApps = null; // Need to be refetched. 1991 } 1992 } 1993 1994 @GuardedBy("mCarrierPrivilegedLock") fetchCarrierPrivilegedAppsCPL()1995 private void fetchCarrierPrivilegedAppsCPL() { 1996 TelephonyManager telephonyManager = 1997 mContext.getSystemService(TelephonyManager.class); 1998 mCarrierPrivilegedApps = 1999 telephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions(); 2000 mHaveCarrierPrivilegedApps = true; 2001 if (DEBUG) { 2002 Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps); 2003 } 2004 } 2005 isActiveNetworkScorer(@onNull String packageName)2006 private boolean isActiveNetworkScorer(@NonNull String packageName) { 2007 // Validity of network scorer cache is limited to a few seconds. Fetch it again 2008 // if longer since query. 2009 // This is a temporary optimization until there's a callback mechanism for changes to network scorer. 2010 final long now = SystemClock.elapsedRealtime(); 2011 if (mCachedNetworkScorer == null 2012 || mCachedNetworkScorerAtMillis < now - NETWORK_SCORER_CACHE_DURATION_MILLIS) { 2013 mCachedNetworkScorer = mInjector.getActiveNetworkScorer(); 2014 mCachedNetworkScorerAtMillis = now; 2015 } 2016 return packageName.equals(mCachedNetworkScorer); 2017 } 2018 informListeners(String packageName, int userId, int bucket, int reason, boolean userInteraction)2019 private void informListeners(String packageName, int userId, int bucket, int reason, 2020 boolean userInteraction) { 2021 final boolean idle = bucket >= STANDBY_BUCKET_RARE; 2022 synchronized (mPackageAccessListeners) { 2023 for (AppIdleStateChangeListener listener : mPackageAccessListeners) { 2024 listener.onAppIdleStateChanged(packageName, userId, idle, bucket, reason); 2025 if (userInteraction) { 2026 listener.onUserInteractionStarted(packageName, userId); 2027 } 2028 } 2029 } 2030 } 2031 informParoleStateChanged()2032 private void informParoleStateChanged() { 2033 final boolean paroled = isInParole(); 2034 synchronized (mPackageAccessListeners) { 2035 for (AppIdleStateChangeListener listener : mPackageAccessListeners) { 2036 listener.onParoleStateChanged(paroled); 2037 } 2038 } 2039 } 2040 2041 @Override getBroadcastResponseWindowDurationMs()2042 public long getBroadcastResponseWindowDurationMs() { 2043 return mBroadcastResponseWindowDurationMillis; 2044 } 2045 2046 @Override getBroadcastResponseFgThresholdState()2047 public int getBroadcastResponseFgThresholdState() { 2048 return mBroadcastResponseFgThresholdState; 2049 } 2050 2051 @Override getBroadcastSessionsDurationMs()2052 public long getBroadcastSessionsDurationMs() { 2053 return mBroadcastSessionsDurationMs; 2054 } 2055 2056 @Override getBroadcastSessionsWithResponseDurationMs()2057 public long getBroadcastSessionsWithResponseDurationMs() { 2058 return mBroadcastSessionsWithResponseDurationMs; 2059 } 2060 2061 @Override shouldNoteResponseEventForAllBroadcastSessions()2062 public boolean shouldNoteResponseEventForAllBroadcastSessions() { 2063 return mNoteResponseEventForAllBroadcastSessions; 2064 } 2065 2066 @Override 2067 @NonNull getBroadcastResponseExemptedRoles()2068 public List<String> getBroadcastResponseExemptedRoles() { 2069 return mBroadcastResponseExemptedRolesList; 2070 } 2071 2072 @Override 2073 @NonNull getBroadcastResponseExemptedPermissions()2074 public List<String> getBroadcastResponseExemptedPermissions() { 2075 return mBroadcastResponseExemptedPermissionsList; 2076 } 2077 2078 @Override 2079 @Nullable getAppStandbyConstant(@onNull String key)2080 public String getAppStandbyConstant(@NonNull String key) { 2081 return mAppStandbyProperties.get(key); 2082 } 2083 2084 @Override clearLastUsedTimestampsForTest(@onNull String packageName, @UserIdInt int userId)2085 public void clearLastUsedTimestampsForTest(@NonNull String packageName, @UserIdInt int userId) { 2086 synchronized (mAppIdleLock) { 2087 mAppIdleHistory.clearLastUsedTimestamps(packageName, userId); 2088 } 2089 } 2090 2091 @Override flushToDisk()2092 public void flushToDisk() { 2093 synchronized (mAppIdleLock) { 2094 mAppIdleHistory.writeAppIdleTimes(mInjector.elapsedRealtime()); 2095 mAppIdleHistory.writeAppIdleDurations(); 2096 } 2097 } 2098 isDisplayOn()2099 private boolean isDisplayOn() { 2100 return mInjector.isDefaultDisplayOn(); 2101 } 2102 2103 @VisibleForTesting clearAppIdleForPackage(String packageName, int userId)2104 void clearAppIdleForPackage(String packageName, int userId) { 2105 synchronized (mAppIdleLock) { 2106 mAppIdleHistory.clearUsage(packageName, userId); 2107 } 2108 } 2109 2110 /** 2111 * Remove an app from the {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} 2112 * bucket if it was forced into the bucket by the system because it was buggy. 2113 */ 2114 @VisibleForTesting maybeUnrestrictBuggyApp(@onNull String packageName, int userId)2115 void maybeUnrestrictBuggyApp(@NonNull String packageName, int userId) { 2116 maybeUnrestrictApp(packageName, userId, 2117 REASON_MAIN_FORCED_BY_SYSTEM, REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY, 2118 REASON_MAIN_DEFAULT, REASON_SUB_DEFAULT_APP_UPDATE); 2119 } 2120 2121 @Override maybeUnrestrictApp(@onNull String packageName, int userId, int prevMainReasonRestrict, int prevSubReasonRestrict, int mainReasonUnrestrict, int subReasonUnrestrict)2122 public void maybeUnrestrictApp(@NonNull String packageName, int userId, 2123 int prevMainReasonRestrict, int prevSubReasonRestrict, 2124 int mainReasonUnrestrict, int subReasonUnrestrict) { 2125 synchronized (mAppIdleLock) { 2126 final long elapsedRealtime = mInjector.elapsedRealtime(); 2127 final AppIdleHistory.AppUsageHistory app = 2128 mAppIdleHistory.getAppUsageHistory(packageName, userId, elapsedRealtime); 2129 if (app.currentBucket != STANDBY_BUCKET_RESTRICTED 2130 || (app.bucketingReason & REASON_MAIN_MASK) != prevMainReasonRestrict) { 2131 return; 2132 } 2133 2134 final int newBucket; 2135 final int newReason; 2136 if ((app.bucketingReason & REASON_SUB_MASK) == prevSubReasonRestrict) { 2137 // If it was the only reason the app should be restricted, then lift it out. 2138 newBucket = STANDBY_BUCKET_RARE; 2139 newReason = mainReasonUnrestrict | subReasonUnrestrict; 2140 } else { 2141 // There's another reason the app was restricted. Remove the subreason bit and call 2142 // it a day. 2143 newBucket = STANDBY_BUCKET_RESTRICTED; 2144 newReason = app.bucketingReason & ~prevSubReasonRestrict; 2145 } 2146 mAppIdleHistory.setAppStandbyBucket( 2147 packageName, userId, elapsedRealtime, newBucket, newReason); 2148 maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, 2149 newReason, false); 2150 } 2151 } 2152 updatePowerWhitelistCache()2153 private void updatePowerWhitelistCache() { 2154 if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) { 2155 return; 2156 } 2157 mInjector.updatePowerWhitelistCache(); 2158 postCheckIdleStates(UserHandle.USER_ALL); 2159 } 2160 2161 private class PackageReceiver extends BroadcastReceiver { 2162 @Override onReceive(Context context, Intent intent)2163 public void onReceive(Context context, Intent intent) { 2164 final String action = intent.getAction(); 2165 final String pkgName = intent.getData().getSchemeSpecificPart(); 2166 final int userId = getSendingUserId(); 2167 if (Intent.ACTION_PACKAGE_ADDED.equals(action) 2168 || Intent.ACTION_PACKAGE_CHANGED.equals(action)) { 2169 final String[] cmpList = intent.getStringArrayExtra( 2170 Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); 2171 // If this is PACKAGE_ADDED (cmpList == null), or if it's a whole-package 2172 // enable/disable event (cmpList is just the package name itself), drop 2173 // our carrier privileged app & system-app caches and let them refresh 2174 if (cmpList == null 2175 || (cmpList.length == 1 && pkgName.equals(cmpList[0]))) { 2176 clearCarrierPrivilegedApps(); 2177 evaluateSystemAppException(pkgName, userId); 2178 } 2179 // component-level enable/disable can affect bucketing, so we always 2180 // reevaluate that for any PACKAGE_CHANGED 2181 if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { 2182 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkgName) 2183 .sendToTarget(); 2184 } 2185 } 2186 if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) || 2187 Intent.ACTION_PACKAGE_ADDED.equals(action))) { 2188 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 2189 maybeUnrestrictBuggyApp(pkgName, userId); 2190 } else if (!Intent.ACTION_PACKAGE_ADDED.equals(action)) { 2191 clearAppIdleForPackage(pkgName, userId); 2192 } else { 2193 // Package was just added and it's not being replaced. 2194 if (mAppsToRestoreToRare.contains(userId, pkgName)) { 2195 restoreAppToRare(pkgName, userId, mInjector.elapsedRealtime(), 2196 REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_APP_RESTORED); 2197 mAppsToRestoreToRare.remove(userId, pkgName); 2198 } 2199 } 2200 } 2201 } 2202 } 2203 evaluateSystemAppException(String packageName, int userId)2204 private void evaluateSystemAppException(String packageName, int userId) { 2205 if (!mSystemServicesReady) { 2206 // The app will be evaluated in when services are ready. 2207 return; 2208 } 2209 try { 2210 PackageInfo pi = mPackageManager.getPackageInfoAsUser( 2211 packageName, HEADLESS_APP_CHECK_FLAGS, userId); 2212 maybeUpdateHeadlessSystemAppCache(pi); 2213 } catch (PackageManager.NameNotFoundException e) { 2214 synchronized (mHeadlessSystemApps) { 2215 mHeadlessSystemApps.remove(packageName); 2216 } 2217 } 2218 } 2219 2220 /** 2221 * Update the "headless system app" cache. 2222 * 2223 * @return true if the cache is updated. 2224 */ maybeUpdateHeadlessSystemAppCache(@ullable PackageInfo pkgInfo)2225 private boolean maybeUpdateHeadlessSystemAppCache(@Nullable PackageInfo pkgInfo) { 2226 if (pkgInfo == null || pkgInfo.applicationInfo == null 2227 || (!pkgInfo.applicationInfo.isSystemApp() 2228 && !pkgInfo.applicationInfo.isUpdatedSystemApp())) { 2229 return false; 2230 } 2231 final Intent frontDoorActivityIntent = new Intent(Intent.ACTION_MAIN) 2232 .addCategory(Intent.CATEGORY_LAUNCHER) 2233 .setPackage(pkgInfo.packageName); 2234 List<ResolveInfo> res = mPackageManager.queryIntentActivitiesAsUser(frontDoorActivityIntent, 2235 HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM); 2236 return updateHeadlessSystemAppCache(pkgInfo.packageName, ArrayUtils.isEmpty(res)); 2237 } 2238 updateHeadlessSystemAppCache(String packageName, boolean add)2239 private boolean updateHeadlessSystemAppCache(String packageName, boolean add) { 2240 synchronized (mHeadlessSystemApps) { 2241 if (add) { 2242 return mHeadlessSystemApps.add(packageName); 2243 } else { 2244 return mHeadlessSystemApps.remove(packageName); 2245 } 2246 } 2247 } 2248 2249 /** Call on a system version update to temporarily reset system app buckets. */ 2250 @Override initializeDefaultsForSystemApps(int userId)2251 public void initializeDefaultsForSystemApps(int userId) { 2252 if (!mSystemServicesReady) { 2253 // Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled 2254 mPendingInitializeDefaults = true; 2255 return; 2256 } 2257 Slog.d(TAG, "Initializing defaults for system apps on user " + userId + ", " 2258 + "appIdleEnabled=" + mAppIdleEnabled); 2259 final long elapsedRealtime = mInjector.elapsedRealtime(); 2260 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser( 2261 PackageManager.MATCH_DISABLED_COMPONENTS, 2262 userId); 2263 final int packageCount = packages.size(); 2264 synchronized (mAppIdleLock) { 2265 for (int i = 0; i < packageCount; i++) { 2266 final PackageInfo pi = packages.get(i); 2267 String packageName = pi.packageName; 2268 if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) { 2269 // Mark app as used for 2 hours. After that it can timeout to whatever the 2270 // past usage pattern was. 2271 mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, 2272 REASON_SUB_USAGE_SYSTEM_UPDATE, 0, 2273 elapsedRealtime + mSystemUpdateUsageTimeoutMillis); 2274 } 2275 } 2276 // Immediately persist defaults to disk 2277 mAppIdleHistory.writeAppIdleTimes(userId, elapsedRealtime); 2278 } 2279 } 2280 2281 /** Returns the packages that have launcher icons. */ getSystemPackagesWithLauncherActivities()2282 private Set<String> getSystemPackagesWithLauncherActivities() { 2283 final Intent intent = new Intent(Intent.ACTION_MAIN) 2284 .addCategory(Intent.CATEGORY_LAUNCHER); 2285 List<ResolveInfo> activities = mPackageManager.queryIntentActivitiesAsUser(intent, 2286 HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM); 2287 final ArraySet<String> ret = new ArraySet<>(); 2288 for (ResolveInfo ri : activities) { 2289 ret.add(ri.activityInfo.packageName); 2290 } 2291 return ret; 2292 } 2293 2294 /** Call on system boot to get the initial set of headless system apps. */ loadHeadlessSystemAppCache()2295 private void loadHeadlessSystemAppCache() { 2296 final long start = SystemClock.uptimeMillis(); 2297 final List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser( 2298 HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM); 2299 2300 final Set<String> systemLauncherActivities = getSystemPackagesWithLauncherActivities(); 2301 2302 final int packageCount = packages.size(); 2303 for (int i = 0; i < packageCount; i++) { 2304 final PackageInfo pkgInfo = packages.get(i); 2305 if (pkgInfo == null) { 2306 continue; 2307 } 2308 final String pkg = pkgInfo.packageName; 2309 final boolean isHeadLess = !systemLauncherActivities.contains(pkg); 2310 2311 if (updateHeadlessSystemAppCache(pkg, isHeadLess)) { 2312 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, 2313 UserHandle.USER_SYSTEM, -1, pkg) 2314 .sendToTarget(); 2315 } 2316 } 2317 final long end = SystemClock.uptimeMillis(); 2318 Slog.d(TAG, "Loaded headless system app cache in " + (end - start) + " ms:" 2319 + " appIdleEnabled=" + mAppIdleEnabled); 2320 } 2321 2322 @Override postReportContentProviderUsage(String name, String packageName, int userId)2323 public void postReportContentProviderUsage(String name, String packageName, int userId) { 2324 ContentProviderUsageRecord record = ContentProviderUsageRecord.obtain(name, packageName, 2325 userId); 2326 mHandler.obtainMessage(MSG_REPORT_CONTENT_PROVIDER_USAGE, record) 2327 .sendToTarget(); 2328 } 2329 2330 @Override postReportSyncScheduled(String packageName, int userId, boolean exempted)2331 public void postReportSyncScheduled(String packageName, int userId, boolean exempted) { 2332 mHandler.obtainMessage(MSG_REPORT_SYNC_SCHEDULED, userId, exempted ? 1 : 0, packageName) 2333 .sendToTarget(); 2334 } 2335 2336 @Override postReportExemptedSyncStart(String packageName, int userId)2337 public void postReportExemptedSyncStart(String packageName, int userId) { 2338 mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName) 2339 .sendToTarget(); 2340 } 2341 2342 @VisibleForTesting getAppIdleHistoryForTest()2343 AppIdleHistory getAppIdleHistoryForTest() { 2344 synchronized (mAppIdleLock) { 2345 return mAppIdleHistory; 2346 } 2347 } 2348 2349 @Override dumpUsers(IndentingPrintWriter idpw, int[] userIds, List<String> pkgs)2350 public void dumpUsers(IndentingPrintWriter idpw, int[] userIds, List<String> pkgs) { 2351 synchronized (mAppIdleLock) { 2352 mAppIdleHistory.dumpUsers(idpw, userIds, pkgs); 2353 } 2354 } 2355 2356 @Override dumpState(String[] args, PrintWriter pw)2357 public void dumpState(String[] args, PrintWriter pw) { 2358 synchronized (mCarrierPrivilegedLock) { 2359 pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps 2360 + "): " + mCarrierPrivilegedApps); 2361 } 2362 2363 pw.println(); 2364 pw.println("Settings:"); 2365 2366 pw.print(" mCheckIdleIntervalMillis="); 2367 TimeUtils.formatDuration(mCheckIdleIntervalMillis, pw); 2368 pw.println(); 2369 2370 pw.print(" mStrongUsageTimeoutMillis="); 2371 TimeUtils.formatDuration(mStrongUsageTimeoutMillis, pw); 2372 pw.println(); 2373 pw.print(" mNotificationSeenTimeoutMillis="); 2374 TimeUtils.formatDuration(mNotificationSeenTimeoutMillis, pw); 2375 pw.println(); 2376 pw.print(" mNotificationSeenPromotedBucket="); 2377 pw.print(standbyBucketToString(mNotificationSeenPromotedBucket)); 2378 pw.println(); 2379 pw.print(" mTriggerQuotaBumpOnNotificationSeen="); 2380 pw.print(mTriggerQuotaBumpOnNotificationSeen); 2381 pw.println(); 2382 pw.print(" mRetainNotificationSeenImpactForPreTApps="); 2383 pw.print(mRetainNotificationSeenImpactForPreTApps); 2384 pw.println(); 2385 pw.print(" mSlicePinnedTimeoutMillis="); 2386 TimeUtils.formatDuration(mSlicePinnedTimeoutMillis, pw); 2387 pw.println(); 2388 pw.print(" mSyncAdapterTimeoutMillis="); 2389 TimeUtils.formatDuration(mSyncAdapterTimeoutMillis, pw); 2390 pw.println(); 2391 pw.print(" mSystemInteractionTimeoutMillis="); 2392 TimeUtils.formatDuration(mSystemInteractionTimeoutMillis, pw); 2393 pw.println(); 2394 pw.print(" mInitialForegroundServiceStartTimeoutMillis="); 2395 TimeUtils.formatDuration(mInitialForegroundServiceStartTimeoutMillis, pw); 2396 pw.println(); 2397 2398 pw.print(" mPredictionTimeoutMillis="); 2399 TimeUtils.formatDuration(mPredictionTimeoutMillis, pw); 2400 pw.println(); 2401 2402 pw.print(" mExemptedSyncScheduledNonDozeTimeoutMillis="); 2403 TimeUtils.formatDuration(mExemptedSyncScheduledNonDozeTimeoutMillis, pw); 2404 pw.println(); 2405 pw.print(" mExemptedSyncScheduledDozeTimeoutMillis="); 2406 TimeUtils.formatDuration(mExemptedSyncScheduledDozeTimeoutMillis, pw); 2407 pw.println(); 2408 pw.print(" mExemptedSyncStartTimeoutMillis="); 2409 TimeUtils.formatDuration(mExemptedSyncStartTimeoutMillis, pw); 2410 pw.println(); 2411 pw.print(" mUnexemptedSyncScheduledTimeoutMillis="); 2412 TimeUtils.formatDuration(mUnexemptedSyncScheduledTimeoutMillis, pw); 2413 pw.println(); 2414 2415 pw.print(" mSystemUpdateUsageTimeoutMillis="); 2416 TimeUtils.formatDuration(mSystemUpdateUsageTimeoutMillis, pw); 2417 pw.println(); 2418 2419 pw.print(" mBroadcastResponseWindowDurationMillis="); 2420 TimeUtils.formatDuration(mBroadcastResponseWindowDurationMillis, pw); 2421 pw.println(); 2422 2423 pw.print(" mBroadcastResponseFgThresholdState="); 2424 pw.print(ActivityManager.procStateToString(mBroadcastResponseFgThresholdState)); 2425 pw.println(); 2426 2427 pw.print(" mBroadcastSessionsDurationMs="); 2428 TimeUtils.formatDuration(mBroadcastSessionsDurationMs, pw); 2429 pw.println(); 2430 2431 pw.print(" mBroadcastSessionsWithResponseDurationMs="); 2432 TimeUtils.formatDuration(mBroadcastSessionsWithResponseDurationMs, pw); 2433 pw.println(); 2434 2435 pw.print(" mNoteResponseEventForAllBroadcastSessions="); 2436 pw.print(mNoteResponseEventForAllBroadcastSessions); 2437 pw.println(); 2438 2439 pw.print(" mBroadcastResponseExemptedRoles"); 2440 pw.print(mBroadcastResponseExemptedRoles); 2441 pw.println(); 2442 2443 pw.print(" mBroadcastResponseExemptedPermissions"); 2444 pw.print(mBroadcastResponseExemptedPermissions); 2445 pw.println(); 2446 2447 pw.println(); 2448 pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled); 2449 pw.print(" mAllowRestrictedBucket="); 2450 pw.print(mAllowRestrictedBucket); 2451 pw.print(" mIsCharging="); 2452 pw.print(mIsCharging); 2453 pw.println(); 2454 pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds)); 2455 pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds)); 2456 pw.println(); 2457 2458 pw.println("mHeadlessSystemApps=["); 2459 synchronized (mHeadlessSystemApps) { 2460 for (int i = mHeadlessSystemApps.size() - 1; i >= 0; --i) { 2461 pw.print(" "); 2462 pw.print(mHeadlessSystemApps.valueAt(i)); 2463 if (i != 0) pw.println(","); 2464 } 2465 } 2466 pw.println("]"); 2467 pw.println(); 2468 2469 pw.println("mSystemPackagesAppIds=["); 2470 synchronized (mSystemPackagesAppIds) { 2471 for (int i = mSystemPackagesAppIds.size() - 1; i >= 0; --i) { 2472 pw.print(" "); 2473 pw.print(mSystemPackagesAppIds.get(i)); 2474 if (i != 0) pw.println(","); 2475 } 2476 } 2477 pw.println("]"); 2478 pw.println(); 2479 2480 mInjector.dump(pw); 2481 } 2482 2483 /** 2484 * Injector for interaction with external code. Override methods to provide a mock 2485 * implementation for tests. 2486 * onBootPhase() must be called with at least the PHASE_SYSTEM_SERVICES_READY 2487 */ 2488 static class Injector { 2489 2490 private final Context mContext; 2491 private final Looper mLooper; 2492 private IBatteryStats mBatteryStats; 2493 private BatteryManager mBatteryManager; 2494 private PackageManagerInternal mPackageManagerInternal; 2495 private DisplayManager mDisplayManager; 2496 private PowerManager mPowerManager; 2497 private IDeviceIdleController mDeviceIdleController; 2498 private CrossProfileAppsInternal mCrossProfileAppsInternal; 2499 private AlarmManagerInternal mAlarmManagerInternal; 2500 int mBootPhase; 2501 /** 2502 * The minimum amount of time required since the last user interaction before an app can be 2503 * automatically placed in the RESTRICTED bucket. 2504 */ 2505 long mAutoRestrictedBucketDelayMs = 2506 ConstantsObserver.DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS; 2507 /** 2508 * Cached set of apps that are power whitelisted, including those not whitelisted from idle. 2509 */ 2510 @GuardedBy("mPowerWhitelistedApps") 2511 private final ArraySet<String> mPowerWhitelistedApps = new ArraySet<>(); 2512 private String mWellbeingApp = null; 2513 Injector(Context context, Looper looper)2514 Injector(Context context, Looper looper) { 2515 mContext = context; 2516 mLooper = looper; 2517 } 2518 getContext()2519 Context getContext() { 2520 return mContext; 2521 } 2522 getLooper()2523 Looper getLooper() { 2524 return mLooper; 2525 } 2526 onBootPhase(int phase)2527 void onBootPhase(int phase) { 2528 if (phase == PHASE_SYSTEM_SERVICES_READY) { 2529 mDeviceIdleController = IDeviceIdleController.Stub.asInterface( 2530 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); 2531 mBatteryStats = IBatteryStats.Stub.asInterface( 2532 ServiceManager.getService(BatteryStats.SERVICE_NAME)); 2533 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); 2534 mDisplayManager = (DisplayManager) mContext.getSystemService( 2535 Context.DISPLAY_SERVICE); 2536 mPowerManager = mContext.getSystemService(PowerManager.class); 2537 mBatteryManager = mContext.getSystemService(BatteryManager.class); 2538 mCrossProfileAppsInternal = LocalServices.getService( 2539 CrossProfileAppsInternal.class); 2540 mAlarmManagerInternal = LocalServices.getService(AlarmManagerInternal.class); 2541 2542 final ActivityManager activityManager = 2543 (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); 2544 if (activityManager.isLowRamDevice() || ActivityManager.isSmallBatteryDevice()) { 2545 mAutoRestrictedBucketDelayMs = 12 * ONE_HOUR; 2546 } 2547 } else if (phase == PHASE_BOOT_COMPLETED) { 2548 // mWellbeingApp needs to be initialized lazily after boot to allow for roles to be 2549 // parsed and the wellbeing role-holder to be assigned 2550 final PackageManager packageManager = mContext.getPackageManager(); 2551 mWellbeingApp = packageManager.getWellbeingPackageName(); 2552 } 2553 mBootPhase = phase; 2554 } 2555 getBootPhase()2556 int getBootPhase() { 2557 return mBootPhase; 2558 } 2559 2560 /** 2561 * Returns the elapsed realtime since the device started. Override this 2562 * to control the clock. 2563 * @return elapsed realtime 2564 */ elapsedRealtime()2565 long elapsedRealtime() { 2566 return SystemClock.elapsedRealtime(); 2567 } 2568 currentTimeMillis()2569 long currentTimeMillis() { 2570 return System.currentTimeMillis(); 2571 } 2572 isAppIdleEnabled()2573 boolean isAppIdleEnabled() { 2574 final boolean buildFlag = mContext.getResources().getBoolean( 2575 com.android.internal.R.bool.config_enableAutoPowerModes); 2576 final boolean runtimeFlag = Global.getInt(mContext.getContentResolver(), 2577 Global.APP_STANDBY_ENABLED, 1) == 1 2578 && Global.getInt(mContext.getContentResolver(), 2579 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 1) == 1; 2580 return buildFlag && runtimeFlag; 2581 } 2582 isCharging()2583 boolean isCharging() { 2584 return mBatteryManager.isCharging(); 2585 } 2586 isNonIdleWhitelisted(String packageName)2587 boolean isNonIdleWhitelisted(String packageName) { 2588 if (mBootPhase < PHASE_SYSTEM_SERVICES_READY) { 2589 return false; 2590 } 2591 synchronized (mPowerWhitelistedApps) { 2592 return mPowerWhitelistedApps.contains(packageName); 2593 } 2594 } 2595 2596 /** 2597 * Returns {@code true} if the supplied package is the wellbeing app. Otherwise, 2598 * returns {@code false}. 2599 */ isWellbeingPackage(@onNull String packageName)2600 boolean isWellbeingPackage(@NonNull String packageName) { 2601 return packageName.equals(mWellbeingApp); 2602 } 2603 hasExactAlarmPermission(String packageName, int uid)2604 boolean hasExactAlarmPermission(String packageName, int uid) { 2605 return mAlarmManagerInternal.hasExactAlarmPermission(packageName, uid); 2606 } 2607 updatePowerWhitelistCache()2608 void updatePowerWhitelistCache() { 2609 try { 2610 // Don't call out to DeviceIdleController with the lock held. 2611 final String[] whitelistedPkgs = 2612 mDeviceIdleController.getFullPowerWhitelistExceptIdle(); 2613 synchronized (mPowerWhitelistedApps) { 2614 mPowerWhitelistedApps.clear(); 2615 final int len = whitelistedPkgs.length; 2616 for (int i = 0; i < len; ++i) { 2617 mPowerWhitelistedApps.add(whitelistedPkgs[i]); 2618 } 2619 } 2620 } catch (RemoteException e) { 2621 // Should not happen. 2622 Slog.wtf(TAG, "Failed to get power whitelist", e); 2623 } 2624 } 2625 isRestrictedBucketEnabled()2626 boolean isRestrictedBucketEnabled() { 2627 return Global.getInt(mContext.getContentResolver(), 2628 Global.ENABLE_RESTRICTED_BUCKET, 2629 Global.DEFAULT_ENABLE_RESTRICTED_BUCKET) == 1; 2630 } 2631 getDataSystemDirectory()2632 File getDataSystemDirectory() { 2633 return Environment.getDataSystemDirectory(); 2634 } 2635 2636 /** 2637 * Return the minimum amount of time that must have passed since the last user usage before 2638 * an app can be automatically put into the 2639 * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket. 2640 */ getAutoRestrictedBucketDelayMs()2641 long getAutoRestrictedBucketDelayMs() { 2642 return mAutoRestrictedBucketDelayMs; 2643 } 2644 noteEvent(int event, String packageName, int uid)2645 void noteEvent(int event, String packageName, int uid) throws RemoteException { 2646 mBatteryStats.noteEvent(event, packageName, uid); 2647 } 2648 getPackageManagerInternal()2649 PackageManagerInternal getPackageManagerInternal() { 2650 return mPackageManagerInternal; 2651 } 2652 isPackageEphemeral(int userId, String packageName)2653 boolean isPackageEphemeral(int userId, String packageName) { 2654 return mPackageManagerInternal.isPackageEphemeral(userId, packageName); 2655 } 2656 isPackageInstalled(String packageName, int flags, int userId)2657 boolean isPackageInstalled(String packageName, int flags, int userId) { 2658 return mPackageManagerInternal.getPackageUid(packageName, flags, userId) >= 0; 2659 } 2660 getRunningUserIds()2661 int[] getRunningUserIds() throws RemoteException { 2662 return ActivityManager.getService().getRunningUserIds(); 2663 } 2664 isDefaultDisplayOn()2665 boolean isDefaultDisplayOn() { 2666 return mDisplayManager 2667 .getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_ON; 2668 } 2669 registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler)2670 void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) { 2671 mDisplayManager.registerDisplayListener(listener, handler); 2672 } 2673 getActiveNetworkScorer()2674 String getActiveNetworkScorer() { 2675 NetworkScoreManager nsm = (NetworkScoreManager) mContext.getSystemService( 2676 Context.NETWORK_SCORE_SERVICE); 2677 return nsm.getActiveScorerPackage(); 2678 } 2679 isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName, int userId)2680 public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName, 2681 int userId) { 2682 return appWidgetManager.isBoundWidgetPackage(packageName, userId); 2683 } 2684 2685 @NonNull getDeviceConfigProperties(String... keys)2686 DeviceConfig.Properties getDeviceConfigProperties(String... keys) { 2687 return DeviceConfig.getProperties(DeviceConfig.NAMESPACE_APP_STANDBY, keys); 2688 } 2689 2690 /** Whether the device is in doze or not. */ isDeviceIdleMode()2691 public boolean isDeviceIdleMode() { 2692 return mPowerManager.isDeviceIdleMode(); 2693 } 2694 getValidCrossProfileTargets(String pkg, int userId)2695 public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) { 2696 final int uid = mPackageManagerInternal.getPackageUid(pkg, /* flags= */ 0, userId); 2697 final AndroidPackage aPkg = mPackageManagerInternal.getPackage(uid); 2698 if (uid < 0 2699 || aPkg == null 2700 || !aPkg.isCrossProfile() 2701 || !mCrossProfileAppsInternal 2702 .verifyUidHasInteractAcrossProfilePermission(pkg, uid)) { 2703 if (uid >= 0 && aPkg == null) { 2704 Slog.wtf(TAG, "Null package retrieved for UID " + uid); 2705 } 2706 return Collections.emptyList(); 2707 } 2708 return mCrossProfileAppsInternal.getTargetUserProfiles(pkg, userId); 2709 } 2710 registerDeviceConfigPropertiesChangedListener( @onNull DeviceConfig.OnPropertiesChangedListener listener)2711 void registerDeviceConfigPropertiesChangedListener( 2712 @NonNull DeviceConfig.OnPropertiesChangedListener listener) { 2713 DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APP_STANDBY, 2714 JobSchedulerBackgroundThread.getExecutor(), listener); 2715 } 2716 dump(PrintWriter pw)2717 void dump(PrintWriter pw) { 2718 pw.println("mPowerWhitelistedApps=["); 2719 synchronized (mPowerWhitelistedApps) { 2720 for (int i = mPowerWhitelistedApps.size() - 1; i >= 0; --i) { 2721 pw.print(" "); 2722 pw.print(mPowerWhitelistedApps.valueAt(i)); 2723 pw.println(","); 2724 } 2725 } 2726 pw.println("]"); 2727 pw.println(); 2728 } 2729 } 2730 2731 class AppStandbyHandler extends Handler { 2732 AppStandbyHandler(Looper looper)2733 AppStandbyHandler(Looper looper) { 2734 super(looper); 2735 } 2736 2737 @Override handleMessage(Message msg)2738 public void handleMessage(Message msg) { 2739 switch (msg.what) { 2740 case MSG_INFORM_LISTENERS: 2741 // TODO(230875908): Properly notify BatteryStats when apps change from active to 2742 // idle, and vice versa 2743 StandbyUpdateRecord r = (StandbyUpdateRecord) msg.obj; 2744 informListeners(r.packageName, r.userId, r.bucket, r.reason, 2745 r.isUserInteraction); 2746 r.recycle(); 2747 break; 2748 2749 case MSG_FORCE_IDLE_STATE: 2750 forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1); 2751 break; 2752 2753 case MSG_CHECK_IDLE_STATES: 2754 removeMessages(MSG_CHECK_IDLE_STATES); 2755 2756 long earliestCheck = Long.MAX_VALUE; 2757 final long nowElapsed = mInjector.elapsedRealtime(); 2758 synchronized (mPendingIdleStateChecks) { 2759 for (int i = mPendingIdleStateChecks.size() - 1; i >= 0; --i) { 2760 long expirationTime = mPendingIdleStateChecks.valueAt(i); 2761 2762 if (expirationTime <= nowElapsed) { 2763 final int userId = mPendingIdleStateChecks.keyAt(i); 2764 if (checkIdleStates(userId) && mAppIdleEnabled) { 2765 expirationTime = nowElapsed + mCheckIdleIntervalMillis; 2766 mPendingIdleStateChecks.put(userId, expirationTime); 2767 } else { 2768 mPendingIdleStateChecks.removeAt(i); 2769 continue; 2770 } 2771 } 2772 2773 earliestCheck = Math.min(earliestCheck, expirationTime); 2774 } 2775 } 2776 if (earliestCheck != Long.MAX_VALUE) { 2777 mHandler.sendMessageDelayed( 2778 mHandler.obtainMessage(MSG_CHECK_IDLE_STATES), 2779 earliestCheck - nowElapsed); 2780 } 2781 break; 2782 2783 case MSG_ONE_TIME_CHECK_IDLE_STATES: 2784 mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES); 2785 waitForAdminData(); 2786 checkIdleStates(UserHandle.USER_ALL); 2787 break; 2788 2789 case MSG_TRIGGER_LISTENER_QUOTA_BUMP: 2790 triggerListenerQuotaBump((String) msg.obj, msg.arg1); 2791 break; 2792 2793 case MSG_REPORT_CONTENT_PROVIDER_USAGE: 2794 ContentProviderUsageRecord record = (ContentProviderUsageRecord) msg.obj; 2795 reportContentProviderUsage(record.name, record.packageName, record.userId); 2796 record.recycle(); 2797 break; 2798 2799 case MSG_PAROLE_STATE_CHANGED: 2800 if (DEBUG) Slog.d(TAG, "Parole state: " + isInParole()); 2801 informParoleStateChanged(); 2802 break; 2803 2804 case MSG_CHECK_PACKAGE_IDLE_STATE: 2805 checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2, 2806 mInjector.elapsedRealtime()); 2807 break; 2808 2809 case MSG_REPORT_SYNC_SCHEDULED: 2810 final boolean exempted = msg.arg2 > 0 ? true : false; 2811 if (exempted) { 2812 reportExemptedSyncScheduled((String) msg.obj, msg.arg1); 2813 } else { 2814 reportUnexemptedSyncScheduled((String) msg.obj, msg.arg1); 2815 } 2816 break; 2817 2818 case MSG_REPORT_EXEMPTED_SYNC_START: 2819 reportExemptedSyncStart((String) msg.obj, msg.arg1); 2820 break; 2821 2822 default: 2823 super.handleMessage(msg); 2824 break; 2825 2826 } 2827 } 2828 }; 2829 2830 private class DeviceStateReceiver extends BroadcastReceiver { 2831 @Override onReceive(Context context, Intent intent)2832 public void onReceive(Context context, Intent intent) { 2833 switch (intent.getAction()) { 2834 case BatteryManager.ACTION_CHARGING: 2835 setChargingState(true); 2836 break; 2837 case BatteryManager.ACTION_DISCHARGING: 2838 setChargingState(false); 2839 break; 2840 case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED: 2841 if (mSystemServicesReady) { 2842 mHandler.post(AppStandbyController.this::updatePowerWhitelistCache); 2843 } 2844 break; 2845 } 2846 } 2847 } 2848 2849 private final DisplayManager.DisplayListener mDisplayListener 2850 = new DisplayManager.DisplayListener() { 2851 2852 @Override public void onDisplayAdded(int displayId) { 2853 } 2854 2855 @Override public void onDisplayRemoved(int displayId) { 2856 } 2857 2858 @Override public void onDisplayChanged(int displayId) { 2859 if (displayId == Display.DEFAULT_DISPLAY) { 2860 final boolean displayOn = isDisplayOn(); 2861 synchronized (mAppIdleLock) { 2862 mAppIdleHistory.updateDisplay(displayOn, mInjector.elapsedRealtime()); 2863 } 2864 } 2865 } 2866 }; 2867 2868 /** 2869 * Observe changes for {@link DeviceConfig#NAMESPACE_APP_STANDBY} and other standby related 2870 * Settings constants. 2871 */ 2872 private class ConstantsObserver extends ContentObserver implements 2873 DeviceConfig.OnPropertiesChangedListener { 2874 private static final String KEY_STRONG_USAGE_HOLD_DURATION = "strong_usage_duration"; 2875 private static final String KEY_NOTIFICATION_SEEN_HOLD_DURATION = 2876 "notification_seen_duration"; 2877 private static final String KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET = 2878 "notification_seen_promoted_bucket"; 2879 private static final String KEY_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS = 2880 "retain_notification_seen_impact_for_pre_t_apps"; 2881 private static final String KEY_TRIGGER_QUOTA_BUMP_ON_NOTIFICATION_SEEN = 2882 "trigger_quota_bump_on_notification_seen"; 2883 private static final String KEY_SLICE_PINNED_HOLD_DURATION = 2884 "slice_pinned_duration"; 2885 private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION = 2886 "system_update_usage_duration"; 2887 private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout"; 2888 private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration"; 2889 private static final String KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION = 2890 "exempted_sync_scheduled_nd_duration"; 2891 private static final String KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION = 2892 "exempted_sync_scheduled_d_duration"; 2893 private static final String KEY_EXEMPTED_SYNC_START_HOLD_DURATION = 2894 "exempted_sync_start_duration"; 2895 private static final String KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION = 2896 "unexempted_sync_scheduled_duration"; 2897 private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION = 2898 "system_interaction_duration"; 2899 private static final String KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION = 2900 "initial_foreground_service_start_duration"; 2901 private static final String KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS = 2902 "auto_restricted_bucket_delay_ms"; 2903 private static final String KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = 2904 "cross_profile_apps_share_standby_buckets"; 2905 private static final String KEY_PREFIX_SCREEN_TIME_THRESHOLD = "screen_threshold_"; 2906 private final String[] KEYS_SCREEN_TIME_THRESHOLDS = { 2907 KEY_PREFIX_SCREEN_TIME_THRESHOLD + "active", 2908 KEY_PREFIX_SCREEN_TIME_THRESHOLD + "working_set", 2909 KEY_PREFIX_SCREEN_TIME_THRESHOLD + "frequent", 2910 KEY_PREFIX_SCREEN_TIME_THRESHOLD + "rare", 2911 KEY_PREFIX_SCREEN_TIME_THRESHOLD + "restricted" 2912 }; 2913 private static final String KEY_PREFIX_ELAPSED_TIME_THRESHOLD = "elapsed_threshold_"; 2914 private final String[] KEYS_ELAPSED_TIME_THRESHOLDS = { 2915 KEY_PREFIX_ELAPSED_TIME_THRESHOLD + "active", 2916 KEY_PREFIX_ELAPSED_TIME_THRESHOLD + "working_set", 2917 KEY_PREFIX_ELAPSED_TIME_THRESHOLD + "frequent", 2918 KEY_PREFIX_ELAPSED_TIME_THRESHOLD + "rare", 2919 KEY_PREFIX_ELAPSED_TIME_THRESHOLD + "restricted" 2920 }; 2921 private static final String KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS = 2922 "broadcast_response_window_timeout_ms"; 2923 private static final String KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE = 2924 "broadcast_response_fg_threshold_state"; 2925 private static final String KEY_BROADCAST_SESSIONS_DURATION_MS = 2926 "broadcast_sessions_duration_ms"; 2927 private static final String KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS = 2928 "broadcast_sessions_with_response_duration_ms"; 2929 private static final String KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS = 2930 "note_response_event_for_all_broadcast_sessions"; 2931 private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES = 2932 "brodacast_response_exempted_roles"; 2933 private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS = 2934 "brodacast_response_exempted_permissions"; 2935 2936 public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS = 2937 COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR; 2938 public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 2939 COMPRESS_TIME ? ONE_MINUTE : 1 * ONE_HOUR; 2940 public static final long DEFAULT_NOTIFICATION_TIMEOUT = 2941 COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR; 2942 public static final long DEFAULT_SLICE_PINNED_TIMEOUT = 2943 COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR; 2944 public static final int DEFAULT_NOTIFICATION_SEEN_PROMOTED_BUCKET = 2945 STANDBY_BUCKET_WORKING_SET; 2946 public static final boolean DEFAULT_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS = false; 2947 public static final boolean DEFAULT_TRIGGER_QUOTA_BUMP_ON_NOTIFICATION_SEEN = false; 2948 public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2949 COMPRESS_TIME ? 2 * ONE_MINUTE : 2 * ONE_HOUR; 2950 public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 2951 COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE; 2952 public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 2953 COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE; 2954 public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT = 2955 COMPRESS_TIME ? (ONE_MINUTE / 2) : 10 * ONE_MINUTE; 2956 public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = 2957 COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR; 2958 public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 2959 COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE; 2960 public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 2961 COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE; 2962 public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 2963 COMPRESS_TIME ? ONE_MINUTE : 30 * ONE_MINUTE; 2964 public static final long DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS = 2965 COMPRESS_TIME ? ONE_MINUTE : ONE_DAY; 2966 public static final boolean DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = true; 2967 public static final long DEFAULT_BROADCAST_RESPONSE_WINDOW_DURATION_MS = 2968 2 * ONE_MINUTE; 2969 public static final int DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE = 2970 ActivityManager.PROCESS_STATE_TOP; 2971 public static final long DEFAULT_BROADCAST_SESSIONS_DURATION_MS = 2972 2 * ONE_MINUTE; 2973 public static final long DEFAULT_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS = 2974 2 * ONE_MINUTE; 2975 public static final boolean DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS = 2976 true; 2977 private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES = ""; 2978 private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS = ""; 2979 2980 private final TextUtils.SimpleStringSplitter mStringPipeSplitter = 2981 new TextUtils.SimpleStringSplitter('|'); 2982 ConstantsObserver(Handler handler)2983 ConstantsObserver(Handler handler) { 2984 super(handler); 2985 } 2986 start()2987 public void start() { 2988 final ContentResolver cr = mContext.getContentResolver(); 2989 // APP_STANDBY_ENABLED is a SystemApi that some apps may be watching, so best to 2990 // leave it in Settings. 2991 cr.registerContentObserver(Global.getUriFor(Global.APP_STANDBY_ENABLED), false, this); 2992 // Leave ENABLE_RESTRICTED_BUCKET as a user-controlled setting which will stay in 2993 // Settings. 2994 // TODO: make setting user-specific 2995 cr.registerContentObserver(Global.getUriFor(Global.ENABLE_RESTRICTED_BUCKET), 2996 false, this); 2997 // ADAPTIVE_BATTERY_MANAGEMENT_ENABLED is a user setting, so it has to stay in Settings. 2998 cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED), 2999 false, this); 3000 mInjector.registerDeviceConfigPropertiesChangedListener(this); 3001 // Load all the constants. 3002 // postOneTimeCheckIdleStates() doesn't need to be called on boot. 3003 processProperties(mInjector.getDeviceConfigProperties()); 3004 updateSettings(); 3005 } 3006 3007 @Override onChange(boolean selfChange)3008 public void onChange(boolean selfChange) { 3009 updateSettings(); 3010 postOneTimeCheckIdleStates(); 3011 } 3012 3013 @Override onPropertiesChanged(DeviceConfig.Properties properties)3014 public void onPropertiesChanged(DeviceConfig.Properties properties) { 3015 processProperties(properties); 3016 postOneTimeCheckIdleStates(); 3017 } 3018 processProperties(DeviceConfig.Properties properties)3019 private void processProperties(DeviceConfig.Properties properties) { 3020 boolean timeThresholdsUpdated = false; 3021 synchronized (mAppIdleLock) { 3022 for (String name : properties.getKeyset()) { 3023 if (name == null) { 3024 continue; 3025 } 3026 switch (name) { 3027 case KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS: 3028 mInjector.mAutoRestrictedBucketDelayMs = Math.max( 3029 COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR, 3030 properties.getLong(KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS, 3031 DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS)); 3032 break; 3033 case KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS: 3034 mLinkCrossProfileApps = properties.getBoolean( 3035 KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS, 3036 DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS); 3037 break; 3038 case KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION: 3039 mInitialForegroundServiceStartTimeoutMillis = properties.getLong( 3040 KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION, 3041 DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT); 3042 break; 3043 case KEY_NOTIFICATION_SEEN_HOLD_DURATION: 3044 mNotificationSeenTimeoutMillis = properties.getLong( 3045 KEY_NOTIFICATION_SEEN_HOLD_DURATION, 3046 DEFAULT_NOTIFICATION_TIMEOUT); 3047 break; 3048 case KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET: 3049 mNotificationSeenPromotedBucket = properties.getInt( 3050 KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET, 3051 DEFAULT_NOTIFICATION_SEEN_PROMOTED_BUCKET); 3052 break; 3053 case KEY_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS: 3054 mRetainNotificationSeenImpactForPreTApps = properties.getBoolean( 3055 KEY_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS, 3056 DEFAULT_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS); 3057 break; 3058 case KEY_TRIGGER_QUOTA_BUMP_ON_NOTIFICATION_SEEN: 3059 mTriggerQuotaBumpOnNotificationSeen = properties.getBoolean( 3060 KEY_TRIGGER_QUOTA_BUMP_ON_NOTIFICATION_SEEN, 3061 DEFAULT_TRIGGER_QUOTA_BUMP_ON_NOTIFICATION_SEEN); 3062 break; 3063 case KEY_SLICE_PINNED_HOLD_DURATION: 3064 mSlicePinnedTimeoutMillis = properties.getLong( 3065 KEY_SLICE_PINNED_HOLD_DURATION, 3066 DEFAULT_SLICE_PINNED_TIMEOUT); 3067 break; 3068 case KEY_STRONG_USAGE_HOLD_DURATION: 3069 mStrongUsageTimeoutMillis = properties.getLong( 3070 KEY_STRONG_USAGE_HOLD_DURATION, DEFAULT_STRONG_USAGE_TIMEOUT); 3071 break; 3072 case KEY_PREDICTION_TIMEOUT: 3073 mPredictionTimeoutMillis = properties.getLong( 3074 KEY_PREDICTION_TIMEOUT, DEFAULT_PREDICTION_TIMEOUT); 3075 break; 3076 case KEY_SYSTEM_INTERACTION_HOLD_DURATION: 3077 mSystemInteractionTimeoutMillis = properties.getLong( 3078 KEY_SYSTEM_INTERACTION_HOLD_DURATION, 3079 DEFAULT_SYSTEM_INTERACTION_TIMEOUT); 3080 break; 3081 case KEY_SYSTEM_UPDATE_HOLD_DURATION: 3082 mSystemUpdateUsageTimeoutMillis = properties.getLong( 3083 KEY_SYSTEM_UPDATE_HOLD_DURATION, DEFAULT_SYSTEM_UPDATE_TIMEOUT); 3084 break; 3085 case KEY_SYNC_ADAPTER_HOLD_DURATION: 3086 mSyncAdapterTimeoutMillis = properties.getLong( 3087 KEY_SYNC_ADAPTER_HOLD_DURATION, DEFAULT_SYNC_ADAPTER_TIMEOUT); 3088 break; 3089 case KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION: 3090 mExemptedSyncScheduledDozeTimeoutMillis = properties.getLong( 3091 KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION, 3092 DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT); 3093 break; 3094 case KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION: 3095 mExemptedSyncScheduledNonDozeTimeoutMillis = properties.getLong( 3096 KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION, 3097 DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT); 3098 break; 3099 case KEY_EXEMPTED_SYNC_START_HOLD_DURATION: 3100 mExemptedSyncStartTimeoutMillis = properties.getLong( 3101 KEY_EXEMPTED_SYNC_START_HOLD_DURATION, 3102 DEFAULT_EXEMPTED_SYNC_START_TIMEOUT); 3103 break; 3104 case KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION: 3105 mUnexemptedSyncScheduledTimeoutMillis = properties.getLong( 3106 KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION, 3107 DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT); 3108 break; 3109 case KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS: 3110 mBroadcastResponseWindowDurationMillis = properties.getLong( 3111 KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS, 3112 DEFAULT_BROADCAST_RESPONSE_WINDOW_DURATION_MS); 3113 break; 3114 case KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE: 3115 mBroadcastResponseFgThresholdState = properties.getInt( 3116 KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE, 3117 DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE); 3118 break; 3119 case KEY_BROADCAST_SESSIONS_DURATION_MS: 3120 mBroadcastSessionsDurationMs = properties.getLong( 3121 KEY_BROADCAST_SESSIONS_DURATION_MS, 3122 DEFAULT_BROADCAST_SESSIONS_DURATION_MS); 3123 break; 3124 case KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS: 3125 mBroadcastSessionsWithResponseDurationMs = properties.getLong( 3126 KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS, 3127 DEFAULT_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS); 3128 break; 3129 case KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS: 3130 mNoteResponseEventForAllBroadcastSessions = properties.getBoolean( 3131 KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS, 3132 DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS); 3133 break; 3134 case KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES: 3135 mBroadcastResponseExemptedRoles = properties.getString( 3136 KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES, 3137 DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES); 3138 mBroadcastResponseExemptedRolesList = splitPipeSeparatedString( 3139 mBroadcastResponseExemptedRoles); 3140 break; 3141 case KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS: 3142 mBroadcastResponseExemptedPermissions = properties.getString( 3143 KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS, 3144 DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS); 3145 mBroadcastResponseExemptedPermissionsList = splitPipeSeparatedString( 3146 mBroadcastResponseExemptedPermissions); 3147 break; 3148 default: 3149 if (!timeThresholdsUpdated 3150 && (name.startsWith(KEY_PREFIX_SCREEN_TIME_THRESHOLD) 3151 || name.startsWith(KEY_PREFIX_ELAPSED_TIME_THRESHOLD))) { 3152 updateTimeThresholds(); 3153 timeThresholdsUpdated = true; 3154 } 3155 break; 3156 } 3157 mAppStandbyProperties.put(name, properties.getString(name, null)); 3158 } 3159 } 3160 } 3161 splitPipeSeparatedString(String string)3162 private List<String> splitPipeSeparatedString(String string) { 3163 final List<String> values = new ArrayList<>(); 3164 mStringPipeSplitter.setString(string); 3165 while (mStringPipeSplitter.hasNext()) { 3166 values.add(mStringPipeSplitter.next()); 3167 } 3168 return values; 3169 } 3170 updateTimeThresholds()3171 private void updateTimeThresholds() { 3172 // Query the values as an atomic set. 3173 final DeviceConfig.Properties screenThresholdProperties = 3174 mInjector.getDeviceConfigProperties(KEYS_SCREEN_TIME_THRESHOLDS); 3175 final DeviceConfig.Properties elapsedThresholdProperties = 3176 mInjector.getDeviceConfigProperties(KEYS_ELAPSED_TIME_THRESHOLDS); 3177 mAppStandbyScreenThresholds = generateThresholdArray( 3178 screenThresholdProperties, KEYS_SCREEN_TIME_THRESHOLDS, 3179 DEFAULT_SCREEN_TIME_THRESHOLDS, MINIMUM_SCREEN_TIME_THRESHOLDS); 3180 mAppStandbyElapsedThresholds = generateThresholdArray( 3181 elapsedThresholdProperties, KEYS_ELAPSED_TIME_THRESHOLDS, 3182 DEFAULT_ELAPSED_TIME_THRESHOLDS, MINIMUM_ELAPSED_TIME_THRESHOLDS); 3183 mCheckIdleIntervalMillis = Math.min(mAppStandbyElapsedThresholds[1] / 4, 3184 DEFAULT_CHECK_IDLE_INTERVAL_MS); 3185 } 3186 updateSettings()3187 void updateSettings() { 3188 if (DEBUG) { 3189 Slog.d(TAG, 3190 "appidle=" + Global.getString(mContext.getContentResolver(), 3191 Global.APP_STANDBY_ENABLED)); 3192 Slog.d(TAG, 3193 "adaptivebat=" + Global.getString(mContext.getContentResolver(), 3194 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED)); 3195 } 3196 3197 synchronized (mAppIdleLock) { 3198 mAllowRestrictedBucket = mInjector.isRestrictedBucketEnabled(); 3199 } 3200 3201 setAppIdleEnabled(mInjector.isAppIdleEnabled()); 3202 } 3203 generateThresholdArray(@onNull DeviceConfig.Properties properties, @NonNull String[] keys, long[] defaults, long[] minValues)3204 long[] generateThresholdArray(@NonNull DeviceConfig.Properties properties, 3205 @NonNull String[] keys, long[] defaults, long[] minValues) { 3206 if (properties.getKeyset().isEmpty()) { 3207 // Reset to defaults 3208 return defaults; 3209 } 3210 if (keys.length != THRESHOLD_BUCKETS.length) { 3211 // This should only happen in development. 3212 throw new IllegalStateException( 3213 "# keys (" + keys.length + ") != # buckets (" 3214 + THRESHOLD_BUCKETS.length + ")"); 3215 } 3216 if (defaults.length != THRESHOLD_BUCKETS.length) { 3217 // This should only happen in development. 3218 throw new IllegalStateException( 3219 "# defaults (" + defaults.length + ") != # buckets (" 3220 + THRESHOLD_BUCKETS.length + ")"); 3221 } 3222 if (minValues.length != THRESHOLD_BUCKETS.length) { 3223 Slog.wtf(TAG, "minValues array is the wrong size"); 3224 // Use zeroes as the minimums. 3225 minValues = new long[THRESHOLD_BUCKETS.length]; 3226 } 3227 long[] array = new long[THRESHOLD_BUCKETS.length]; 3228 for (int i = 0; i < THRESHOLD_BUCKETS.length; i++) { 3229 array[i] = Math.max(minValues[i], properties.getLong(keys[i], defaults[i])); 3230 } 3231 return array; 3232 } 3233 } 3234 } 3235