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