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