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