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; 21 import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK; 22 import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED; 23 import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT; 24 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; 25 import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED; 26 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT; 27 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE; 28 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE; 29 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START; 30 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START; 31 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND; 32 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND; 33 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN; 34 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED; 35 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV; 36 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER; 37 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION; 38 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE; 39 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED; 40 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION; 41 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; 42 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED; 43 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; 44 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; 45 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; 46 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; 47 48 import static com.android.server.SystemService.PHASE_BOOT_COMPLETED; 49 import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; 50 51 import android.annotation.UserIdInt; 52 import android.app.ActivityManager; 53 import android.app.AppGlobals; 54 import android.app.usage.AppStandbyInfo; 55 import android.app.usage.UsageEvents; 56 import android.app.usage.UsageStatsManager.StandbyBuckets; 57 import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener; 58 import android.appwidget.AppWidgetManager; 59 import android.content.BroadcastReceiver; 60 import android.content.ContentResolver; 61 import android.content.Context; 62 import android.content.Intent; 63 import android.content.IntentFilter; 64 import android.content.pm.ApplicationInfo; 65 import android.content.pm.PackageInfo; 66 import android.content.pm.PackageManager; 67 import android.content.pm.PackageManagerInternal; 68 import android.content.pm.ParceledListSlice; 69 import android.database.ContentObserver; 70 import android.hardware.display.DisplayManager; 71 import android.net.ConnectivityManager; 72 import android.net.Network; 73 import android.net.NetworkInfo; 74 import android.net.NetworkRequest; 75 import android.net.NetworkScoreManager; 76 import android.os.BatteryManager; 77 import android.os.BatteryStats; 78 import android.os.Environment; 79 import android.os.Handler; 80 import android.os.IDeviceIdleController; 81 import android.os.Looper; 82 import android.os.Message; 83 import android.os.PowerManager; 84 import android.os.Process; 85 import android.os.RemoteException; 86 import android.os.ServiceManager; 87 import android.os.SystemClock; 88 import android.os.UserHandle; 89 import android.provider.Settings.Global; 90 import android.telephony.TelephonyManager; 91 import android.util.ArraySet; 92 import android.util.KeyValueListParser; 93 import android.util.Slog; 94 import android.util.SparseArray; 95 import android.util.SparseIntArray; 96 import android.util.TimeUtils; 97 import android.view.Display; 98 99 import com.android.internal.annotations.GuardedBy; 100 import com.android.internal.annotations.VisibleForTesting; 101 import com.android.internal.app.IBatteryStats; 102 import com.android.internal.os.SomeArgs; 103 import com.android.internal.util.ArrayUtils; 104 import com.android.internal.util.ConcurrentUtils; 105 import com.android.internal.util.IndentingPrintWriter; 106 import com.android.server.LocalServices; 107 import com.android.server.usage.AppIdleHistory.AppUsageHistory; 108 109 import java.io.File; 110 import java.io.PrintWriter; 111 import java.time.Duration; 112 import java.time.format.DateTimeParseException; 113 import java.util.ArrayList; 114 import java.util.Arrays; 115 import java.util.List; 116 import java.util.Set; 117 import java.util.concurrent.CountDownLatch; 118 119 /** 120 * Manages the standby state of an app, listening to various events. 121 * 122 * Unit test: 123 atest ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java 124 */ 125 public class AppStandbyController { 126 127 private static final String TAG = "AppStandbyController"; 128 static final boolean DEBUG = false; 129 130 static final boolean COMPRESS_TIME = false; 131 private static final long ONE_MINUTE = 60 * 1000; 132 private static final long ONE_HOUR = ONE_MINUTE * 60; 133 private static final long ONE_DAY = ONE_HOUR * 24; 134 135 static final long[] SCREEN_TIME_THRESHOLDS = { 136 0, 137 0, 138 COMPRESS_TIME ? 120 * 1000 : 1 * ONE_HOUR, 139 COMPRESS_TIME ? 240 * 1000 : 2 * ONE_HOUR 140 }; 141 142 static final long[] ELAPSED_TIME_THRESHOLDS = { 143 0, 144 COMPRESS_TIME ? 1 * ONE_MINUTE : 12 * ONE_HOUR, 145 COMPRESS_TIME ? 4 * ONE_MINUTE : 24 * ONE_HOUR, 146 COMPRESS_TIME ? 16 * ONE_MINUTE : 48 * ONE_HOUR 147 }; 148 149 static final int[] THRESHOLD_BUCKETS = { 150 STANDBY_BUCKET_ACTIVE, 151 STANDBY_BUCKET_WORKING_SET, 152 STANDBY_BUCKET_FREQUENT, 153 STANDBY_BUCKET_RARE 154 }; 155 156 /** Default expiration time for bucket prediction. After this, use thresholds to downgrade. */ 157 private static final long DEFAULT_PREDICTION_TIMEOUT = 12 * ONE_HOUR; 158 159 /** 160 * Indicates the maximum wait time for admin data to be available; 161 */ 162 private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000; 163 164 // To name the lock for stack traces 165 static class Lock {} 166 167 /** Lock to protect the app's standby state. Required for calls into AppIdleHistory */ 168 private final Object mAppIdleLock = new Lock(); 169 170 /** Keeps the history and state for each app. */ 171 @GuardedBy("mAppIdleLock") 172 private AppIdleHistory mAppIdleHistory; 173 174 @GuardedBy("mPackageAccessListeners") 175 private ArrayList<AppIdleStateChangeListener> 176 mPackageAccessListeners = new ArrayList<>(); 177 178 /** Whether we've queried the list of carrier privileged apps. */ 179 @GuardedBy("mAppIdleLock") 180 private boolean mHaveCarrierPrivilegedApps; 181 182 /** List of carrier-privileged apps that should be excluded from standby */ 183 @GuardedBy("mAppIdleLock") 184 private List<String> mCarrierPrivilegedApps; 185 186 @GuardedBy("mActiveAdminApps") 187 private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>(); 188 189 private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1); 190 191 // Messages for the handler 192 static final int MSG_INFORM_LISTENERS = 3; 193 static final int MSG_FORCE_IDLE_STATE = 4; 194 static final int MSG_CHECK_IDLE_STATES = 5; 195 static final int MSG_CHECK_PAROLE_TIMEOUT = 6; 196 static final int MSG_PAROLE_END_TIMEOUT = 7; 197 static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8; 198 static final int MSG_PAROLE_STATE_CHANGED = 9; 199 static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10; 200 /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */ 201 static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11; 202 static final int MSG_REPORT_SYNC_SCHEDULED = 12; 203 static final int MSG_REPORT_EXEMPTED_SYNC_START = 13; 204 static final int MSG_UPDATE_STABLE_CHARGING= 14; 205 206 long mCheckIdleIntervalMillis; 207 long mAppIdleParoleIntervalMillis; 208 long mAppIdleParoleWindowMillis; 209 long mAppIdleParoleDurationMillis; 210 long[] mAppStandbyScreenThresholds = SCREEN_TIME_THRESHOLDS; 211 long[] mAppStandbyElapsedThresholds = ELAPSED_TIME_THRESHOLDS; 212 /** Minimum time a strong usage event should keep the bucket elevated. */ 213 long mStrongUsageTimeoutMillis; 214 /** Minimum time a notification seen event should keep the bucket elevated. */ 215 long mNotificationSeenTimeoutMillis; 216 /** Minimum time a system update event should keep the buckets elevated. */ 217 long mSystemUpdateUsageTimeoutMillis; 218 /** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */ 219 long mPredictionTimeoutMillis; 220 /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */ 221 long mSyncAdapterTimeoutMillis; 222 /** 223 * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in 224 * non-doze 225 */ 226 long mExemptedSyncScheduledNonDozeTimeoutMillis; 227 /** 228 * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in 229 * doze 230 */ 231 long mExemptedSyncScheduledDozeTimeoutMillis; 232 /** 233 * Maximum time an exempted sync should keep the buckets elevated, when sync is started. 234 */ 235 long mExemptedSyncStartTimeoutMillis; 236 /** 237 * Maximum time an unexempted sync should keep the buckets elevated, when sync is scheduled 238 */ 239 long mUnexemptedSyncScheduledTimeoutMillis; 240 /** Maximum time a system interaction should keep the buckets elevated. */ 241 long mSystemInteractionTimeoutMillis; 242 /** 243 * Maximum time a foreground service start should keep the buckets elevated if the service 244 * start is the first usage of the app 245 */ 246 long mInitialForegroundServiceStartTimeoutMillis; 247 /** The length of time phone must be charging before considered stable enough to run jobs */ 248 long mStableChargingThresholdMillis; 249 250 volatile boolean mAppIdleEnabled; 251 boolean mAppIdleTempParoled; 252 boolean mCharging; 253 boolean mChargingStable; 254 private long mLastAppIdleParoledTime; 255 private boolean mSystemServicesReady = false; 256 // There was a system update, defaults need to be initialized after services are ready 257 private boolean mPendingInitializeDefaults; 258 259 private final DeviceStateReceiver mDeviceStateReceiver; 260 261 private volatile boolean mPendingOneTimeCheckIdleStates; 262 263 private final AppStandbyHandler mHandler; 264 private final Context mContext; 265 266 // TODO: Provide a mechanism to set an external bucketing service 267 268 private AppWidgetManager mAppWidgetManager; 269 private ConnectivityManager mConnectivityManager; 270 private PowerManager mPowerManager; 271 private PackageManager mPackageManager; 272 Injector mInjector; 273 274 static final ArrayList<StandbyUpdateRecord> sStandbyUpdatePool = new ArrayList<>(4); 275 276 public static class StandbyUpdateRecord { 277 // Identity of the app whose standby state has changed 278 String packageName; 279 int userId; 280 281 // What the standby bucket the app is now in 282 int bucket; 283 284 // Whether the bucket change is because the user has started interacting with the app 285 boolean isUserInteraction; 286 287 // Reason for bucket change 288 int reason; 289 StandbyUpdateRecord(String pkgName, int userId, int bucket, int reason, boolean isInteraction)290 StandbyUpdateRecord(String pkgName, int userId, int bucket, int reason, 291 boolean isInteraction) { 292 this.packageName = pkgName; 293 this.userId = userId; 294 this.bucket = bucket; 295 this.reason = reason; 296 this.isUserInteraction = isInteraction; 297 } 298 obtain(String pkgName, int userId, int bucket, int reason, boolean isInteraction)299 public static StandbyUpdateRecord obtain(String pkgName, int userId, 300 int bucket, int reason, boolean isInteraction) { 301 synchronized (sStandbyUpdatePool) { 302 final int size = sStandbyUpdatePool.size(); 303 if (size < 1) { 304 return new StandbyUpdateRecord(pkgName, userId, bucket, reason, isInteraction); 305 } 306 StandbyUpdateRecord r = sStandbyUpdatePool.remove(size - 1); 307 r.packageName = pkgName; 308 r.userId = userId; 309 r.bucket = bucket; 310 r.reason = reason; 311 r.isUserInteraction = isInteraction; 312 return r; 313 } 314 } 315 recycle()316 public void recycle() { 317 synchronized (sStandbyUpdatePool) { 318 sStandbyUpdatePool.add(this); 319 } 320 } 321 } 322 AppStandbyController(Context context, Looper looper)323 AppStandbyController(Context context, Looper looper) { 324 this(new Injector(context, looper)); 325 } 326 AppStandbyController(Injector injector)327 AppStandbyController(Injector injector) { 328 mInjector = injector; 329 mContext = mInjector.getContext(); 330 mHandler = new AppStandbyHandler(mInjector.getLooper()); 331 mPackageManager = mContext.getPackageManager(); 332 mDeviceStateReceiver = new DeviceStateReceiver(); 333 334 IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING); 335 deviceStates.addAction(BatteryManager.ACTION_DISCHARGING); 336 deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 337 mContext.registerReceiver(mDeviceStateReceiver, deviceStates); 338 339 synchronized (mAppIdleLock) { 340 mAppIdleHistory = new AppIdleHistory(mInjector.getDataSystemDirectory(), 341 mInjector.elapsedRealtime()); 342 } 343 344 IntentFilter packageFilter = new IntentFilter(); 345 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 346 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 347 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 348 packageFilter.addDataScheme("package"); 349 350 mContext.registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter, 351 null, mHandler); 352 } 353 setAppIdleEnabled(boolean enabled)354 void setAppIdleEnabled(boolean enabled) { 355 synchronized (mAppIdleLock) { 356 if (mAppIdleEnabled != enabled) { 357 final boolean oldParoleState = isParoledOrCharging(); 358 mAppIdleEnabled = enabled; 359 if (isParoledOrCharging() != oldParoleState) { 360 postParoleStateChanged(); 361 } 362 } 363 } 364 } 365 onBootPhase(int phase)366 public void onBootPhase(int phase) { 367 mInjector.onBootPhase(phase); 368 if (phase == PHASE_SYSTEM_SERVICES_READY) { 369 Slog.d(TAG, "Setting app idle enabled state"); 370 // Observe changes to the threshold 371 SettingsObserver settingsObserver = new SettingsObserver(mHandler); 372 settingsObserver.registerObserver(); 373 settingsObserver.updateSettings(); 374 375 mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class); 376 mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); 377 mPowerManager = mContext.getSystemService(PowerManager.class); 378 379 mInjector.registerDisplayListener(mDisplayListener, mHandler); 380 synchronized (mAppIdleLock) { 381 mAppIdleHistory.updateDisplay(isDisplayOn(), mInjector.elapsedRealtime()); 382 } 383 384 mSystemServicesReady = true; 385 386 boolean userFileExists; 387 synchronized (mAppIdleLock) { 388 userFileExists = mAppIdleHistory.userFileExists(UserHandle.USER_SYSTEM); 389 } 390 391 if (mPendingInitializeDefaults || !userFileExists) { 392 initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM); 393 } 394 395 if (mPendingOneTimeCheckIdleStates) { 396 postOneTimeCheckIdleStates(); 397 } 398 } else if (phase == PHASE_BOOT_COMPLETED) { 399 setChargingState(mInjector.isCharging()); 400 } 401 } 402 reportContentProviderUsage(String authority, String providerPkgName, int userId)403 void reportContentProviderUsage(String authority, String providerPkgName, int userId) { 404 if (!mAppIdleEnabled) return; 405 406 // Get sync adapters for the authority 407 String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser( 408 authority, userId); 409 final long elapsedRealtime = mInjector.elapsedRealtime(); 410 for (String packageName: packages) { 411 // Only force the sync adapters to active if the provider is not in the same package and 412 // the sync adapter is a system package. 413 try { 414 PackageInfo pi = mPackageManager.getPackageInfoAsUser( 415 packageName, PackageManager.MATCH_SYSTEM_ONLY, userId); 416 if (pi == null || pi.applicationInfo == null) { 417 continue; 418 } 419 if (!packageName.equals(providerPkgName)) { 420 synchronized (mAppIdleLock) { 421 AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, 422 STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER, 423 0, 424 elapsedRealtime + mSyncAdapterTimeoutMillis); 425 maybeInformListeners(packageName, userId, elapsedRealtime, 426 appUsage.currentBucket, appUsage.bucketingReason, false); 427 } 428 } 429 } catch (PackageManager.NameNotFoundException e) { 430 // Shouldn't happen 431 } 432 } 433 } 434 reportExemptedSyncScheduled(String packageName, int userId)435 void reportExemptedSyncScheduled(String packageName, int userId) { 436 if (!mAppIdleEnabled) return; 437 438 final int bucketToPromote; 439 final int usageReason; 440 final long durationMillis; 441 442 if (!mInjector.isDeviceIdleMode()) { 443 // Not dozing. 444 bucketToPromote = STANDBY_BUCKET_ACTIVE; 445 usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE; 446 durationMillis = mExemptedSyncScheduledNonDozeTimeoutMillis; 447 } else { 448 // Dozing. 449 bucketToPromote = STANDBY_BUCKET_WORKING_SET; 450 usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE; 451 durationMillis = mExemptedSyncScheduledDozeTimeoutMillis; 452 } 453 454 final long elapsedRealtime = mInjector.elapsedRealtime(); 455 456 synchronized (mAppIdleLock) { 457 AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, 458 bucketToPromote, usageReason, 459 0, 460 elapsedRealtime + durationMillis); 461 maybeInformListeners(packageName, userId, elapsedRealtime, 462 appUsage.currentBucket, appUsage.bucketingReason, false); 463 } 464 } 465 reportUnexemptedSyncScheduled(String packageName, int userId)466 void reportUnexemptedSyncScheduled(String packageName, int userId) { 467 if (!mAppIdleEnabled) return; 468 469 final long elapsedRealtime = mInjector.elapsedRealtime(); 470 synchronized (mAppIdleLock) { 471 final int currentBucket = 472 mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime); 473 if (currentBucket == STANDBY_BUCKET_NEVER) { 474 // Bring the app out of the never bucket 475 AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, 476 STANDBY_BUCKET_WORKING_SET, REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED, 477 0, 478 elapsedRealtime + mUnexemptedSyncScheduledTimeoutMillis); 479 maybeInformListeners(packageName, userId, elapsedRealtime, 480 appUsage.currentBucket, appUsage.bucketingReason, false); 481 } 482 } 483 } 484 reportExemptedSyncStart(String packageName, int userId)485 void reportExemptedSyncStart(String packageName, int userId) { 486 if (!mAppIdleEnabled) return; 487 488 final long elapsedRealtime = mInjector.elapsedRealtime(); 489 490 synchronized (mAppIdleLock) { 491 AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, 492 STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_EXEMPTED_SYNC_START, 493 0, 494 elapsedRealtime + mExemptedSyncStartTimeoutMillis); 495 maybeInformListeners(packageName, userId, elapsedRealtime, 496 appUsage.currentBucket, appUsage.bucketingReason, false); 497 } 498 } 499 setChargingState(boolean charging)500 void setChargingState(boolean charging) { 501 synchronized (mAppIdleLock) { 502 if (mCharging != charging) { 503 mCharging = charging; 504 if (DEBUG) Slog.d(TAG, "Setting mCharging to " + charging); 505 if (charging) { 506 if (DEBUG) { 507 Slog.d(TAG, "Scheduling MSG_UPDATE_STABLE_CHARGING delay = " 508 + mStableChargingThresholdMillis); 509 } 510 mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STABLE_CHARGING, 511 mStableChargingThresholdMillis); 512 } else { 513 mHandler.removeMessages(MSG_UPDATE_STABLE_CHARGING); 514 updateChargingStableState(); 515 } 516 } 517 } 518 } 519 updateChargingStableState()520 void updateChargingStableState() { 521 synchronized (mAppIdleLock) { 522 if (mChargingStable != mCharging) { 523 if (DEBUG) Slog.d(TAG, "Setting mChargingStable to " + mCharging); 524 mChargingStable = mCharging; 525 postParoleStateChanged(); 526 } 527 } 528 } 529 530 /** Paroled here means temporary pardon from being inactive */ setAppIdleParoled(boolean paroled)531 void setAppIdleParoled(boolean paroled) { 532 synchronized (mAppIdleLock) { 533 final long now = mInjector.currentTimeMillis(); 534 if (mAppIdleTempParoled != paroled) { 535 mAppIdleTempParoled = paroled; 536 if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleTempParoled); 537 if (paroled) { 538 postParoleEndTimeout(); 539 } else { 540 mLastAppIdleParoledTime = now; 541 postNextParoleTimeout(now, false); 542 } 543 postParoleStateChanged(); 544 } 545 } 546 } 547 isParoledOrCharging()548 boolean isParoledOrCharging() { 549 if (!mAppIdleEnabled) return true; 550 synchronized (mAppIdleLock) { 551 // Only consider stable charging when determining charge state. 552 return mAppIdleTempParoled || mChargingStable; 553 } 554 } 555 postNextParoleTimeout(long now, boolean forced)556 private void postNextParoleTimeout(long now, boolean forced) { 557 if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT"); 558 mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT); 559 // Compute when the next parole needs to happen. We check more frequently than necessary 560 // since the message handler delays are based on elapsedRealTime and not wallclock time. 561 // The comparison is done in wallclock time. 562 long timeLeft = (mLastAppIdleParoledTime + mAppIdleParoleIntervalMillis) - now; 563 if (forced) { 564 // Set next timeout for the end of the parole window 565 // If parole is not set by the end of the window it will be forced 566 timeLeft += mAppIdleParoleWindowMillis; 567 } 568 if (timeLeft < 0) { 569 timeLeft = 0; 570 } 571 mHandler.sendEmptyMessageDelayed(MSG_CHECK_PAROLE_TIMEOUT, timeLeft); 572 } 573 postParoleEndTimeout()574 private void postParoleEndTimeout() { 575 if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_END_TIMEOUT"); 576 mHandler.removeMessages(MSG_PAROLE_END_TIMEOUT); 577 mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, mAppIdleParoleDurationMillis); 578 } 579 postParoleStateChanged()580 private void postParoleStateChanged() { 581 if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED"); 582 mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED); 583 mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED); 584 } 585 postCheckIdleStates(int userId)586 void postCheckIdleStates(int userId) { 587 mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0)); 588 } 589 590 /** 591 * We send a different message to check idle states once, otherwise we would end up 592 * scheduling a series of repeating checkIdleStates each time we fired off one. 593 */ postOneTimeCheckIdleStates()594 void postOneTimeCheckIdleStates() { 595 if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) { 596 // Not booted yet; wait for it! 597 mPendingOneTimeCheckIdleStates = true; 598 } else { 599 mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES); 600 mPendingOneTimeCheckIdleStates = false; 601 } 602 } 603 604 /** 605 * Check all running users' or specified user's apps to see if they enter an idle state. 606 * @return Returns whether checking should continue periodically. 607 */ checkIdleStates(int checkUserId)608 boolean checkIdleStates(int checkUserId) { 609 if (!mAppIdleEnabled) { 610 return false; 611 } 612 613 final int[] runningUserIds; 614 try { 615 runningUserIds = mInjector.getRunningUserIds(); 616 if (checkUserId != UserHandle.USER_ALL 617 && !ArrayUtils.contains(runningUserIds, checkUserId)) { 618 return false; 619 } 620 } catch (RemoteException re) { 621 throw re.rethrowFromSystemServer(); 622 } 623 624 final long elapsedRealtime = mInjector.elapsedRealtime(); 625 for (int i = 0; i < runningUserIds.length; i++) { 626 final int userId = runningUserIds[i]; 627 if (checkUserId != UserHandle.USER_ALL && checkUserId != userId) { 628 continue; 629 } 630 if (DEBUG) { 631 Slog.d(TAG, "Checking idle state for user " + userId); 632 } 633 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser( 634 PackageManager.MATCH_DISABLED_COMPONENTS, 635 userId); 636 final int packageCount = packages.size(); 637 for (int p = 0; p < packageCount; p++) { 638 final PackageInfo pi = packages.get(p); 639 final String packageName = pi.packageName; 640 checkAndUpdateStandbyState(packageName, userId, pi.applicationInfo.uid, 641 elapsedRealtime); 642 } 643 } 644 if (DEBUG) { 645 Slog.d(TAG, "checkIdleStates took " 646 + (mInjector.elapsedRealtime() - elapsedRealtime)); 647 } 648 return true; 649 } 650 651 /** Check if we need to update the standby state of a specific app. */ checkAndUpdateStandbyState(String packageName, @UserIdInt int userId, int uid, long elapsedRealtime)652 private void checkAndUpdateStandbyState(String packageName, @UserIdInt int userId, 653 int uid, long elapsedRealtime) { 654 if (uid <= 0) { 655 try { 656 uid = mPackageManager.getPackageUidAsUser(packageName, userId); 657 } catch (PackageManager.NameNotFoundException e) { 658 // Not a valid package for this user, nothing to do 659 // TODO: Remove any history of removed packages 660 return; 661 } 662 } 663 final boolean isSpecial = isAppSpecial(packageName, 664 UserHandle.getAppId(uid), 665 userId); 666 if (DEBUG) { 667 Slog.d(TAG, " Checking idle state for " + packageName + " special=" + 668 isSpecial); 669 } 670 if (isSpecial) { 671 synchronized (mAppIdleLock) { 672 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, 673 STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT); 674 } 675 maybeInformListeners(packageName, userId, elapsedRealtime, 676 STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT, false); 677 } else { 678 synchronized (mAppIdleLock) { 679 final AppIdleHistory.AppUsageHistory app = 680 mAppIdleHistory.getAppUsageHistory(packageName, 681 userId, elapsedRealtime); 682 int reason = app.bucketingReason; 683 final int oldMainReason = reason & REASON_MAIN_MASK; 684 685 // If the bucket was forced by the user/developer, leave it alone. 686 // A usage event will be the only way to bring it out of this forced state 687 if (oldMainReason == REASON_MAIN_FORCED) { 688 return; 689 } 690 final int oldBucket = app.currentBucket; 691 int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED 692 boolean predictionLate = predictionTimedOut(app, elapsedRealtime); 693 // Compute age-based bucket 694 if (oldMainReason == REASON_MAIN_DEFAULT 695 || oldMainReason == REASON_MAIN_USAGE 696 || oldMainReason == REASON_MAIN_TIMEOUT 697 || predictionLate) { 698 699 if (!predictionLate && app.lastPredictedBucket >= STANDBY_BUCKET_ACTIVE 700 && app.lastPredictedBucket <= STANDBY_BUCKET_RARE) { 701 newBucket = app.lastPredictedBucket; 702 reason = REASON_MAIN_PREDICTED | REASON_SUB_PREDICTED_RESTORED; 703 if (DEBUG) { 704 Slog.d(TAG, "Restored predicted newBucket = " + newBucket); 705 } 706 } else { 707 newBucket = getBucketForLocked(packageName, userId, 708 elapsedRealtime); 709 if (DEBUG) { 710 Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket); 711 } 712 reason = REASON_MAIN_TIMEOUT; 713 } 714 } 715 716 // Check if the app is within one of the timeouts for forced bucket elevation 717 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime); 718 if (newBucket >= STANDBY_BUCKET_ACTIVE 719 && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) { 720 newBucket = STANDBY_BUCKET_ACTIVE; 721 reason = app.bucketingReason; 722 if (DEBUG) { 723 Slog.d(TAG, " Keeping at ACTIVE due to min timeout"); 724 } 725 } else if (newBucket >= STANDBY_BUCKET_WORKING_SET 726 && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) { 727 newBucket = STANDBY_BUCKET_WORKING_SET; 728 // If it was already there, keep the reason, else assume timeout to WS 729 reason = (newBucket == oldBucket) 730 ? app.bucketingReason 731 : REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT; 732 if (DEBUG) { 733 Slog.d(TAG, " Keeping at WORKING_SET due to min timeout"); 734 } 735 } 736 if (DEBUG) { 737 Slog.d(TAG, " Old bucket=" + oldBucket 738 + ", newBucket=" + newBucket); 739 } 740 if (oldBucket < newBucket || predictionLate) { 741 mAppIdleHistory.setAppStandbyBucket(packageName, userId, 742 elapsedRealtime, newBucket, reason); 743 maybeInformListeners(packageName, userId, elapsedRealtime, 744 newBucket, reason, false); 745 } 746 } 747 } 748 } 749 750 /** Returns true if there hasn't been a prediction for the app in a while. */ predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime)751 private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) { 752 return app.lastPredictedTime > 0 753 && mAppIdleHistory.getElapsedTime(elapsedRealtime) 754 - app.lastPredictedTime > mPredictionTimeoutMillis; 755 } 756 757 /** 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)758 private void maybeInformListeners(String packageName, int userId, 759 long elapsedRealtime, int bucket, int reason, boolean userStartedInteracting) { 760 synchronized (mAppIdleLock) { 761 if (mAppIdleHistory.shouldInformListeners(packageName, userId, 762 elapsedRealtime, bucket)) { 763 final StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId, 764 bucket, reason, userStartedInteracting); 765 if (DEBUG) Slog.d(TAG, "Standby bucket for " + packageName + "=" + bucket); 766 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, r)); 767 } 768 } 769 } 770 771 /** 772 * Evaluates next bucket based on time since last used and the bucketing thresholds. 773 * @param packageName the app 774 * @param userId the user 775 * @param elapsedRealtime as the name suggests, current elapsed time 776 * @return the bucket for the app, based on time since last used 777 */ 778 @GuardedBy("mAppIdleLock") getBucketForLocked(String packageName, int userId, long elapsedRealtime)779 @StandbyBuckets int getBucketForLocked(String packageName, int userId, 780 long elapsedRealtime) { 781 int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId, 782 elapsedRealtime, mAppStandbyScreenThresholds, mAppStandbyElapsedThresholds); 783 return THRESHOLD_BUCKETS[bucketIndex]; 784 } 785 786 /** 787 * Check if it's been a while since last parole and let idle apps do some work. 788 * If network is not available, delay parole until it is available up until the end of the 789 * parole window. Force the parole to be set if end of the parole window is reached. 790 */ checkParoleTimeout()791 void checkParoleTimeout() { 792 boolean setParoled = false; 793 boolean waitForNetwork = false; 794 NetworkInfo activeNetwork = mConnectivityManager.getActiveNetworkInfo(); 795 boolean networkActive = activeNetwork != null && 796 activeNetwork.isConnected(); 797 798 synchronized (mAppIdleLock) { 799 final long now = mInjector.currentTimeMillis(); 800 if (!mAppIdleTempParoled) { 801 final long timeSinceLastParole = now - mLastAppIdleParoledTime; 802 if (timeSinceLastParole > mAppIdleParoleIntervalMillis) { 803 if (DEBUG) Slog.d(TAG, "Crossed default parole interval"); 804 if (networkActive) { 805 // If network is active set parole 806 setParoled = true; 807 } else { 808 if (timeSinceLastParole 809 > mAppIdleParoleIntervalMillis + mAppIdleParoleWindowMillis) { 810 if (DEBUG) Slog.d(TAG, "Crossed end of parole window, force parole"); 811 setParoled = true; 812 } else { 813 if (DEBUG) Slog.d(TAG, "Network unavailable, delaying parole"); 814 waitForNetwork = true; 815 postNextParoleTimeout(now, true); 816 } 817 } 818 } else { 819 if (DEBUG) Slog.d(TAG, "Not long enough to go to parole"); 820 postNextParoleTimeout(now, false); 821 } 822 } 823 } 824 if (waitForNetwork) { 825 mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback); 826 } 827 if (setParoled) { 828 // Set parole if network is available 829 setAppIdleParoled(true); 830 } 831 } 832 notifyBatteryStats(String packageName, int userId, boolean idle)833 private void notifyBatteryStats(String packageName, int userId, boolean idle) { 834 try { 835 final int uid = mPackageManager.getPackageUidAsUser(packageName, 836 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); 837 if (idle) { 838 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE, 839 packageName, uid); 840 } else { 841 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE, 842 packageName, uid); 843 } 844 } catch (PackageManager.NameNotFoundException | RemoteException e) { 845 } 846 } 847 onDeviceIdleModeChanged()848 void onDeviceIdleModeChanged() { 849 final boolean deviceIdle = mPowerManager.isDeviceIdleMode(); 850 if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle); 851 boolean paroled = false; 852 synchronized (mAppIdleLock) { 853 final long timeSinceLastParole = 854 mInjector.currentTimeMillis() - mLastAppIdleParoledTime; 855 if (!deviceIdle 856 && timeSinceLastParole >= mAppIdleParoleIntervalMillis) { 857 if (DEBUG) { 858 Slog.i(TAG, 859 "Bringing idle apps out of inactive state due to deviceIdleMode=false"); 860 } 861 paroled = true; 862 } else if (deviceIdle) { 863 if (DEBUG) Slog.i(TAG, "Device idle, back to prison"); 864 paroled = false; 865 } else { 866 return; 867 } 868 } 869 setAppIdleParoled(paroled); 870 } 871 reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId)872 void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId) { 873 if (!mAppIdleEnabled) return; 874 synchronized (mAppIdleLock) { 875 // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back 876 // about apps that are on some kind of whitelist anyway. 877 final boolean previouslyIdle = mAppIdleHistory.isIdle( 878 event.mPackage, userId, elapsedRealtime); 879 // Inform listeners if necessary 880 if ((event.mEventType == UsageEvents.Event.ACTIVITY_RESUMED 881 || event.mEventType == UsageEvents.Event.ACTIVITY_PAUSED 882 || event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION 883 || event.mEventType == UsageEvents.Event.USER_INTERACTION 884 || event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN 885 || event.mEventType == UsageEvents.Event.SLICE_PINNED 886 || event.mEventType == UsageEvents.Event.SLICE_PINNED_PRIV 887 || event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) { 888 889 final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory( 890 event.mPackage, userId, elapsedRealtime); 891 final int prevBucket = appHistory.currentBucket; 892 final int prevBucketReason = appHistory.bucketingReason; 893 final long nextCheckTime; 894 final int subReason = usageEventToSubReason(event.mEventType); 895 final int reason = REASON_MAIN_USAGE | subReason; 896 if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN 897 || event.mEventType == UsageEvents.Event.SLICE_PINNED) { 898 // Mild usage elevates to WORKING_SET but doesn't change usage time. 899 mAppIdleHistory.reportUsage(appHistory, event.mPackage, 900 STANDBY_BUCKET_WORKING_SET, subReason, 901 0, elapsedRealtime + mNotificationSeenTimeoutMillis); 902 nextCheckTime = mNotificationSeenTimeoutMillis; 903 } else if (event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION) { 904 mAppIdleHistory.reportUsage(appHistory, event.mPackage, 905 STANDBY_BUCKET_ACTIVE, subReason, 906 0, elapsedRealtime + mSystemInteractionTimeoutMillis); 907 nextCheckTime = mSystemInteractionTimeoutMillis; 908 } else if (event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START) { 909 // Only elevate bucket if this is the first usage of the app 910 if (prevBucket != STANDBY_BUCKET_NEVER) return; 911 mAppIdleHistory.reportUsage(appHistory, event.mPackage, 912 STANDBY_BUCKET_ACTIVE, subReason, 913 0, elapsedRealtime + mInitialForegroundServiceStartTimeoutMillis); 914 nextCheckTime = mInitialForegroundServiceStartTimeoutMillis; 915 } else { 916 mAppIdleHistory.reportUsage(appHistory, event.mPackage, 917 STANDBY_BUCKET_ACTIVE, subReason, 918 elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis); 919 nextCheckTime = mStrongUsageTimeoutMillis; 920 } 921 mHandler.sendMessageDelayed(mHandler.obtainMessage 922 (MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, event.mPackage), 923 nextCheckTime); 924 final boolean userStartedInteracting = 925 appHistory.currentBucket == STANDBY_BUCKET_ACTIVE && 926 prevBucket != appHistory.currentBucket && 927 (prevBucketReason & REASON_MAIN_MASK) != REASON_MAIN_USAGE; 928 maybeInformListeners(event.mPackage, userId, elapsedRealtime, 929 appHistory.currentBucket, reason, userStartedInteracting); 930 931 if (previouslyIdle) { 932 notifyBatteryStats(event.mPackage, userId, false); 933 } 934 } 935 } 936 } 937 usageEventToSubReason(int eventType)938 private int usageEventToSubReason(int eventType) { 939 switch (eventType) { 940 case UsageEvents.Event.ACTIVITY_RESUMED: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND; 941 case UsageEvents.Event.ACTIVITY_PAUSED: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND; 942 case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION; 943 case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION; 944 case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN; 945 case UsageEvents.Event.SLICE_PINNED: return REASON_SUB_USAGE_SLICE_PINNED; 946 case UsageEvents.Event.SLICE_PINNED_PRIV: return REASON_SUB_USAGE_SLICE_PINNED_PRIV; 947 case UsageEvents.Event.FOREGROUND_SERVICE_START: 948 return REASON_SUB_USAGE_FOREGROUND_SERVICE_START; 949 default: return 0; 950 } 951 } 952 953 /** 954 * Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle, 955 * then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind 956 * the threshold for idle. 957 * 958 * This method is always called from the handler thread, so not much synchronization is 959 * required. 960 */ forceIdleState(String packageName, int userId, boolean idle)961 void forceIdleState(String packageName, int userId, boolean idle) { 962 if (!mAppIdleEnabled) return; 963 964 final int appId = getAppId(packageName); 965 if (appId < 0) return; 966 final long elapsedRealtime = mInjector.elapsedRealtime(); 967 968 final boolean previouslyIdle = isAppIdleFiltered(packageName, appId, 969 userId, elapsedRealtime); 970 final int standbyBucket; 971 synchronized (mAppIdleLock) { 972 standbyBucket = mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime); 973 } 974 final boolean stillIdle = isAppIdleFiltered(packageName, appId, 975 userId, elapsedRealtime); 976 // Inform listeners if necessary 977 if (previouslyIdle != stillIdle) { 978 maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket, 979 REASON_MAIN_FORCED, false); 980 if (!stillIdle) { 981 notifyBatteryStats(packageName, userId, idle); 982 } 983 } 984 } 985 setLastJobRunTime(String packageName, int userId, long elapsedRealtime)986 public void setLastJobRunTime(String packageName, int userId, long elapsedRealtime) { 987 synchronized (mAppIdleLock) { 988 mAppIdleHistory.setLastJobRunTime(packageName, userId, elapsedRealtime); 989 } 990 } 991 getTimeSinceLastJobRun(String packageName, int userId)992 public long getTimeSinceLastJobRun(String packageName, int userId) { 993 final long elapsedRealtime = mInjector.elapsedRealtime(); 994 synchronized (mAppIdleLock) { 995 return mAppIdleHistory.getTimeSinceLastJobRun(packageName, userId, elapsedRealtime); 996 } 997 } 998 onUserRemoved(int userId)999 public void onUserRemoved(int userId) { 1000 synchronized (mAppIdleLock) { 1001 mAppIdleHistory.onUserRemoved(userId); 1002 synchronized (mActiveAdminApps) { 1003 mActiveAdminApps.remove(userId); 1004 } 1005 } 1006 } 1007 isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime)1008 private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) { 1009 synchronized (mAppIdleLock) { 1010 return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime); 1011 } 1012 } 1013 addListener(AppIdleStateChangeListener listener)1014 void addListener(AppIdleStateChangeListener listener) { 1015 synchronized (mPackageAccessListeners) { 1016 if (!mPackageAccessListeners.contains(listener)) { 1017 mPackageAccessListeners.add(listener); 1018 } 1019 } 1020 } 1021 removeListener(AppIdleStateChangeListener listener)1022 void removeListener(AppIdleStateChangeListener listener) { 1023 synchronized (mPackageAccessListeners) { 1024 mPackageAccessListeners.remove(listener); 1025 } 1026 } 1027 getAppId(String packageName)1028 int getAppId(String packageName) { 1029 try { 1030 ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName, 1031 PackageManager.MATCH_ANY_USER 1032 | PackageManager.MATCH_DISABLED_COMPONENTS); 1033 return ai.uid; 1034 } catch (PackageManager.NameNotFoundException re) { 1035 return -1; 1036 } 1037 } 1038 isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps)1039 boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime, 1040 boolean shouldObfuscateInstantApps) { 1041 if (isParoledOrCharging()) { 1042 return false; 1043 } 1044 if (shouldObfuscateInstantApps && 1045 mInjector.isPackageEphemeral(userId, packageName)) { 1046 return false; 1047 } 1048 return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime); 1049 } 1050 1051 /** Returns true if this app should be whitelisted for some reason, to never go into standby */ isAppSpecial(String packageName, int appId, int userId)1052 boolean isAppSpecial(String packageName, int appId, int userId) { 1053 if (packageName == null) return false; 1054 // If not enabled at all, of course nobody is ever idle. 1055 if (!mAppIdleEnabled) { 1056 return true; 1057 } 1058 if (appId < Process.FIRST_APPLICATION_UID) { 1059 // System uids never go idle. 1060 return true; 1061 } 1062 if (packageName.equals("android")) { 1063 // Nor does the framework (which should be redundant with the above, but for MR1 we will 1064 // retain this for safety). 1065 return true; 1066 } 1067 if (mSystemServicesReady) { 1068 try { 1069 // We allow all whitelisted apps, including those that don't want to be whitelisted 1070 // for idle mode, because app idle (aka app standby) is really not as big an issue 1071 // for controlling who participates vs. doze mode. 1072 if (mInjector.isPowerSaveWhitelistExceptIdleApp(packageName)) { 1073 return true; 1074 } 1075 } catch (RemoteException re) { 1076 throw re.rethrowFromSystemServer(); 1077 } 1078 1079 if (isActiveDeviceAdmin(packageName, userId)) { 1080 return true; 1081 } 1082 1083 if (isActiveNetworkScorer(packageName)) { 1084 return true; 1085 } 1086 1087 if (mAppWidgetManager != null 1088 && mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) { 1089 return true; 1090 } 1091 1092 if (isDeviceProvisioningPackage(packageName)) { 1093 return true; 1094 } 1095 } 1096 1097 // Check this last, as it can be the most expensive check 1098 if (isCarrierApp(packageName)) { 1099 return true; 1100 } 1101 1102 return false; 1103 } 1104 1105 /** 1106 * Checks if an app has been idle for a while and filters out apps that are excluded. 1107 * It returns false if the current system state allows all apps to be considered active. 1108 * This happens if the device is plugged in or temporarily allowed to make exceptions. 1109 * Called by interface impls. 1110 */ isAppIdleFiltered(String packageName, int appId, int userId, long elapsedRealtime)1111 boolean isAppIdleFiltered(String packageName, int appId, int userId, 1112 long elapsedRealtime) { 1113 if (isAppSpecial(packageName, appId, userId)) { 1114 return false; 1115 } else { 1116 return isAppIdleUnfiltered(packageName, userId, elapsedRealtime); 1117 } 1118 } 1119 getIdleUidsForUser(int userId)1120 int[] getIdleUidsForUser(int userId) { 1121 if (!mAppIdleEnabled) { 1122 return new int[0]; 1123 } 1124 1125 final long elapsedRealtime = mInjector.elapsedRealtime(); 1126 1127 List<ApplicationInfo> apps; 1128 try { 1129 ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager() 1130 .getInstalledApplications(/* flags= */ 0, userId); 1131 if (slice == null) { 1132 return new int[0]; 1133 } 1134 apps = slice.getList(); 1135 } catch (RemoteException e) { 1136 throw e.rethrowFromSystemServer(); 1137 } 1138 1139 // State of each uid. Key is the uid. Value lower 16 bits is the number of apps 1140 // associated with that uid, upper 16 bits is the number of those apps that is idle. 1141 SparseIntArray uidStates = new SparseIntArray(); 1142 1143 // Now resolve all app state. Iterating over all apps, keeping track of how many 1144 // we find for each uid and how many of those are idle. 1145 for (int i = apps.size() - 1; i >= 0; i--) { 1146 ApplicationInfo ai = apps.get(i); 1147 1148 // Check whether this app is idle. 1149 boolean idle = isAppIdleFiltered(ai.packageName, UserHandle.getAppId(ai.uid), 1150 userId, elapsedRealtime); 1151 1152 int index = uidStates.indexOfKey(ai.uid); 1153 if (index < 0) { 1154 uidStates.put(ai.uid, 1 + (idle ? 1<<16 : 0)); 1155 } else { 1156 int value = uidStates.valueAt(index); 1157 uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0)); 1158 } 1159 } 1160 if (DEBUG) { 1161 Slog.d(TAG, "getIdleUids took " + (mInjector.elapsedRealtime() - elapsedRealtime)); 1162 } 1163 int numIdle = 0; 1164 for (int i = uidStates.size() - 1; i >= 0; i--) { 1165 int value = uidStates.valueAt(i); 1166 if ((value&0x7fff) == (value>>16)) { 1167 numIdle++; 1168 } 1169 } 1170 1171 int[] res = new int[numIdle]; 1172 numIdle = 0; 1173 for (int i = uidStates.size() - 1; i >= 0; i--) { 1174 int value = uidStates.valueAt(i); 1175 if ((value&0x7fff) == (value>>16)) { 1176 res[numIdle] = uidStates.keyAt(i); 1177 numIdle++; 1178 } 1179 } 1180 1181 return res; 1182 } 1183 setAppIdleAsync(String packageName, boolean idle, int userId)1184 void setAppIdleAsync(String packageName, boolean idle, int userId) { 1185 if (packageName == null || !mAppIdleEnabled) return; 1186 1187 mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName) 1188 .sendToTarget(); 1189 } 1190 getAppStandbyBucket(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps)1191 @StandbyBuckets public int getAppStandbyBucket(String packageName, int userId, 1192 long elapsedRealtime, boolean shouldObfuscateInstantApps) { 1193 if (!mAppIdleEnabled || (shouldObfuscateInstantApps 1194 && mInjector.isPackageEphemeral(userId, packageName))) { 1195 return STANDBY_BUCKET_ACTIVE; 1196 } 1197 1198 synchronized (mAppIdleLock) { 1199 return mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime); 1200 } 1201 } 1202 getAppStandbyBuckets(int userId)1203 public List<AppStandbyInfo> getAppStandbyBuckets(int userId) { 1204 synchronized (mAppIdleLock) { 1205 return mAppIdleHistory.getAppStandbyBuckets(userId, mAppIdleEnabled); 1206 } 1207 } 1208 setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime)1209 void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, 1210 int reason, long elapsedRealtime) { 1211 setAppStandbyBucket(packageName, userId, newBucket, reason, elapsedRealtime, false); 1212 } 1213 setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime, boolean resetTimeout)1214 void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, 1215 int reason, long elapsedRealtime, boolean resetTimeout) { 1216 synchronized (mAppIdleLock) { 1217 // If the package is not installed, don't allow the bucket to be set. 1218 if (!mInjector.isPackageInstalled(packageName, 0, userId)) { 1219 return; 1220 } 1221 AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName, 1222 userId, elapsedRealtime); 1223 boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED; 1224 1225 // Don't allow changing bucket if higher than ACTIVE 1226 if (app.currentBucket < STANDBY_BUCKET_ACTIVE) return; 1227 1228 // Don't allow prediction to change from/to NEVER 1229 if ((app.currentBucket == STANDBY_BUCKET_NEVER 1230 || newBucket == STANDBY_BUCKET_NEVER) 1231 && predicted) { 1232 return; 1233 } 1234 1235 // If the bucket was forced, don't allow prediction to override 1236 if ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED && predicted) return; 1237 1238 // If the bucket is required to stay in a higher state for a specified duration, don't 1239 // override unless the duration has passed 1240 if (predicted) { 1241 // Check if the app is within one of the timeouts for forced bucket elevation 1242 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime); 1243 // In case of not using the prediction, just keep track of it for applying after 1244 // ACTIVE or WORKING_SET timeout. 1245 mAppIdleHistory.updateLastPrediction(app, elapsedTimeAdjusted, newBucket); 1246 1247 if (newBucket > STANDBY_BUCKET_ACTIVE 1248 && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) { 1249 newBucket = STANDBY_BUCKET_ACTIVE; 1250 reason = app.bucketingReason; 1251 if (DEBUG) { 1252 Slog.d(TAG, " Keeping at ACTIVE due to min timeout"); 1253 } 1254 } else if (newBucket > STANDBY_BUCKET_WORKING_SET 1255 && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) { 1256 newBucket = STANDBY_BUCKET_WORKING_SET; 1257 if (app.currentBucket != newBucket) { 1258 reason = REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT; 1259 } else { 1260 reason = app.bucketingReason; 1261 } 1262 if (DEBUG) { 1263 Slog.d(TAG, " Keeping at WORKING_SET due to min timeout"); 1264 } 1265 } 1266 } 1267 1268 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, 1269 reason, resetTimeout); 1270 } 1271 maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, reason, false); 1272 } 1273 1274 @VisibleForTesting isActiveDeviceAdmin(String packageName, int userId)1275 boolean isActiveDeviceAdmin(String packageName, int userId) { 1276 synchronized (mActiveAdminApps) { 1277 final Set<String> adminPkgs = mActiveAdminApps.get(userId); 1278 return adminPkgs != null && adminPkgs.contains(packageName); 1279 } 1280 } 1281 addActiveDeviceAdmin(String adminPkg, int userId)1282 public void addActiveDeviceAdmin(String adminPkg, int userId) { 1283 synchronized (mActiveAdminApps) { 1284 Set<String> adminPkgs = mActiveAdminApps.get(userId); 1285 if (adminPkgs == null) { 1286 adminPkgs = new ArraySet<>(); 1287 mActiveAdminApps.put(userId, adminPkgs); 1288 } 1289 adminPkgs.add(adminPkg); 1290 } 1291 } 1292 setActiveAdminApps(Set<String> adminPkgs, int userId)1293 public void setActiveAdminApps(Set<String> adminPkgs, int userId) { 1294 synchronized (mActiveAdminApps) { 1295 if (adminPkgs == null) { 1296 mActiveAdminApps.remove(userId); 1297 } else { 1298 mActiveAdminApps.put(userId, adminPkgs); 1299 } 1300 } 1301 } 1302 onAdminDataAvailable()1303 public void onAdminDataAvailable() { 1304 mAdminDataAvailableLatch.countDown(); 1305 } 1306 1307 /** 1308 * This will only ever be called once - during device boot. 1309 */ waitForAdminData()1310 private void waitForAdminData() { 1311 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) { 1312 ConcurrentUtils.waitForCountDownNoInterrupt(mAdminDataAvailableLatch, 1313 WAIT_FOR_ADMIN_DATA_TIMEOUT_MS, "Wait for admin data"); 1314 } 1315 } 1316 getActiveAdminAppsForTest(int userId)1317 Set<String> getActiveAdminAppsForTest(int userId) { 1318 synchronized (mActiveAdminApps) { 1319 return mActiveAdminApps.get(userId); 1320 } 1321 } 1322 1323 /** 1324 * Returns {@code true} if the supplied package is the device provisioning app. Otherwise, 1325 * returns {@code false}. 1326 */ isDeviceProvisioningPackage(String packageName)1327 private boolean isDeviceProvisioningPackage(String packageName) { 1328 String deviceProvisioningPackage = mContext.getResources().getString( 1329 com.android.internal.R.string.config_deviceProvisioningPackage); 1330 return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName); 1331 } 1332 isCarrierApp(String packageName)1333 private boolean isCarrierApp(String packageName) { 1334 synchronized (mAppIdleLock) { 1335 if (!mHaveCarrierPrivilegedApps) { 1336 fetchCarrierPrivilegedAppsLocked(); 1337 } 1338 if (mCarrierPrivilegedApps != null) { 1339 return mCarrierPrivilegedApps.contains(packageName); 1340 } 1341 return false; 1342 } 1343 } 1344 clearCarrierPrivilegedApps()1345 void clearCarrierPrivilegedApps() { 1346 if (DEBUG) { 1347 Slog.i(TAG, "Clearing carrier privileged apps list"); 1348 } 1349 synchronized (mAppIdleLock) { 1350 mHaveCarrierPrivilegedApps = false; 1351 mCarrierPrivilegedApps = null; // Need to be refetched. 1352 } 1353 } 1354 1355 @GuardedBy("mAppIdleLock") fetchCarrierPrivilegedAppsLocked()1356 private void fetchCarrierPrivilegedAppsLocked() { 1357 TelephonyManager telephonyManager = 1358 mContext.getSystemService(TelephonyManager.class); 1359 mCarrierPrivilegedApps = 1360 telephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions(); 1361 mHaveCarrierPrivilegedApps = true; 1362 if (DEBUG) { 1363 Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps); 1364 } 1365 } 1366 isActiveNetworkScorer(String packageName)1367 private boolean isActiveNetworkScorer(String packageName) { 1368 String activeScorer = mInjector.getActiveNetworkScorer(); 1369 return packageName != null && packageName.equals(activeScorer); 1370 } 1371 informListeners(String packageName, int userId, int bucket, int reason, boolean userInteraction)1372 void informListeners(String packageName, int userId, int bucket, int reason, 1373 boolean userInteraction) { 1374 final boolean idle = bucket >= STANDBY_BUCKET_RARE; 1375 synchronized (mPackageAccessListeners) { 1376 for (AppIdleStateChangeListener listener : mPackageAccessListeners) { 1377 listener.onAppIdleStateChanged(packageName, userId, idle, bucket, reason); 1378 if (userInteraction) { 1379 listener.onUserInteractionStarted(packageName, userId); 1380 } 1381 } 1382 } 1383 } 1384 informParoleStateChanged()1385 void informParoleStateChanged() { 1386 final boolean paroled = isParoledOrCharging(); 1387 synchronized (mPackageAccessListeners) { 1388 for (AppIdleStateChangeListener listener : mPackageAccessListeners) { 1389 listener.onParoleStateChanged(paroled); 1390 } 1391 } 1392 } 1393 flushToDisk(int userId)1394 void flushToDisk(int userId) { 1395 synchronized (mAppIdleLock) { 1396 mAppIdleHistory.writeAppIdleTimes(userId); 1397 } 1398 } 1399 flushDurationsToDisk()1400 void flushDurationsToDisk() { 1401 // Persist elapsed and screen on time. If this fails for whatever reason, the apps will be 1402 // considered not-idle, which is the safest outcome in such an event. 1403 synchronized (mAppIdleLock) { 1404 mAppIdleHistory.writeAppIdleDurations(); 1405 } 1406 } 1407 isDisplayOn()1408 boolean isDisplayOn() { 1409 return mInjector.isDefaultDisplayOn(); 1410 } 1411 clearAppIdleForPackage(String packageName, int userId)1412 void clearAppIdleForPackage(String packageName, int userId) { 1413 synchronized (mAppIdleLock) { 1414 mAppIdleHistory.clearUsage(packageName, userId); 1415 } 1416 } 1417 1418 private class PackageReceiver extends BroadcastReceiver { 1419 @Override onReceive(Context context, Intent intent)1420 public void onReceive(Context context, Intent intent) { 1421 final String action = intent.getAction(); 1422 if (Intent.ACTION_PACKAGE_ADDED.equals(action) 1423 || Intent.ACTION_PACKAGE_CHANGED.equals(action)) { 1424 clearCarrierPrivilegedApps(); 1425 } 1426 if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) || 1427 Intent.ACTION_PACKAGE_ADDED.equals(action)) 1428 && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 1429 clearAppIdleForPackage(intent.getData().getSchemeSpecificPart(), 1430 getSendingUserId()); 1431 } 1432 } 1433 } 1434 initializeDefaultsForSystemApps(int userId)1435 void initializeDefaultsForSystemApps(int userId) { 1436 if (!mSystemServicesReady) { 1437 // Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled 1438 mPendingInitializeDefaults = true; 1439 return; 1440 } 1441 Slog.d(TAG, "Initializing defaults for system apps on user " + userId + ", " 1442 + "appIdleEnabled=" + mAppIdleEnabled); 1443 final long elapsedRealtime = mInjector.elapsedRealtime(); 1444 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser( 1445 PackageManager.MATCH_DISABLED_COMPONENTS, 1446 userId); 1447 final int packageCount = packages.size(); 1448 synchronized (mAppIdleLock) { 1449 for (int i = 0; i < packageCount; i++) { 1450 final PackageInfo pi = packages.get(i); 1451 String packageName = pi.packageName; 1452 if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) { 1453 // Mark app as used for 2 hours. After that it can timeout to whatever the 1454 // past usage pattern was. 1455 mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, 1456 REASON_SUB_USAGE_SYSTEM_UPDATE, 0, 1457 elapsedRealtime + mSystemUpdateUsageTimeoutMillis); 1458 } 1459 } 1460 // Immediately persist defaults to disk 1461 mAppIdleHistory.writeAppIdleTimes(userId); 1462 } 1463 } 1464 postReportContentProviderUsage(String name, String packageName, int userId)1465 void postReportContentProviderUsage(String name, String packageName, int userId) { 1466 SomeArgs args = SomeArgs.obtain(); 1467 args.arg1 = name; 1468 args.arg2 = packageName; 1469 args.arg3 = userId; 1470 mHandler.obtainMessage(MSG_REPORT_CONTENT_PROVIDER_USAGE, args) 1471 .sendToTarget(); 1472 } 1473 postReportSyncScheduled(String packageName, int userId, boolean exempted)1474 void postReportSyncScheduled(String packageName, int userId, boolean exempted) { 1475 mHandler.obtainMessage(MSG_REPORT_SYNC_SCHEDULED, userId, exempted ? 1 : 0, packageName) 1476 .sendToTarget(); 1477 } 1478 postReportExemptedSyncStart(String packageName, int userId)1479 void postReportExemptedSyncStart(String packageName, int userId) { 1480 mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName) 1481 .sendToTarget(); 1482 } 1483 dumpUser(IndentingPrintWriter idpw, int userId, String pkg)1484 void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) { 1485 synchronized (mAppIdleLock) { 1486 mAppIdleHistory.dump(idpw, userId, pkg); 1487 } 1488 } 1489 dumpState(String[] args, PrintWriter pw)1490 void dumpState(String[] args, PrintWriter pw) { 1491 synchronized (mAppIdleLock) { 1492 pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps 1493 + "): " + mCarrierPrivilegedApps); 1494 } 1495 1496 final long now = System.currentTimeMillis(); 1497 1498 pw.println(); 1499 pw.println("Settings:"); 1500 1501 pw.print(" mCheckIdleIntervalMillis="); 1502 TimeUtils.formatDuration(mCheckIdleIntervalMillis, pw); 1503 pw.println(); 1504 1505 pw.print(" mAppIdleParoleIntervalMillis="); 1506 TimeUtils.formatDuration(mAppIdleParoleIntervalMillis, pw); 1507 pw.println(); 1508 1509 pw.print(" mAppIdleParoleWindowMillis="); 1510 TimeUtils.formatDuration(mAppIdleParoleWindowMillis, pw); 1511 pw.println(); 1512 1513 pw.print(" mAppIdleParoleDurationMillis="); 1514 TimeUtils.formatDuration(mAppIdleParoleDurationMillis, pw); 1515 pw.println(); 1516 1517 pw.print(" mStrongUsageTimeoutMillis="); 1518 TimeUtils.formatDuration(mStrongUsageTimeoutMillis, pw); 1519 pw.println(); 1520 pw.print(" mNotificationSeenTimeoutMillis="); 1521 TimeUtils.formatDuration(mNotificationSeenTimeoutMillis, pw); 1522 pw.println(); 1523 pw.print(" mSyncAdapterTimeoutMillis="); 1524 TimeUtils.formatDuration(mSyncAdapterTimeoutMillis, pw); 1525 pw.println(); 1526 pw.print(" mSystemInteractionTimeoutMillis="); 1527 TimeUtils.formatDuration(mSystemInteractionTimeoutMillis, pw); 1528 pw.println(); 1529 pw.print(" mInitialForegroundServiceStartTimeoutMillis="); 1530 TimeUtils.formatDuration(mInitialForegroundServiceStartTimeoutMillis, pw); 1531 pw.println(); 1532 1533 pw.print(" mPredictionTimeoutMillis="); 1534 TimeUtils.formatDuration(mPredictionTimeoutMillis, pw); 1535 pw.println(); 1536 1537 pw.print(" mExemptedSyncScheduledNonDozeTimeoutMillis="); 1538 TimeUtils.formatDuration(mExemptedSyncScheduledNonDozeTimeoutMillis, pw); 1539 pw.println(); 1540 pw.print(" mExemptedSyncScheduledDozeTimeoutMillis="); 1541 TimeUtils.formatDuration(mExemptedSyncScheduledDozeTimeoutMillis, pw); 1542 pw.println(); 1543 pw.print(" mExemptedSyncStartTimeoutMillis="); 1544 TimeUtils.formatDuration(mExemptedSyncStartTimeoutMillis, pw); 1545 pw.println(); 1546 pw.print(" mUnexemptedSyncScheduledTimeoutMillis="); 1547 TimeUtils.formatDuration(mUnexemptedSyncScheduledTimeoutMillis, pw); 1548 pw.println(); 1549 1550 pw.print(" mSystemUpdateUsageTimeoutMillis="); 1551 TimeUtils.formatDuration(mSystemUpdateUsageTimeoutMillis, pw); 1552 pw.println(); 1553 1554 pw.print(" mStableChargingThresholdMillis="); 1555 TimeUtils.formatDuration(mStableChargingThresholdMillis, pw); 1556 pw.println(); 1557 1558 pw.println(); 1559 pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled); 1560 pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled); 1561 pw.print(" mCharging="); pw.print(mCharging); 1562 pw.print(" mChargingStable="); pw.print(mChargingStable); 1563 pw.print(" mLastAppIdleParoledTime="); 1564 TimeUtils.formatDuration(now - mLastAppIdleParoledTime, pw); 1565 pw.println(); 1566 pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds)); 1567 pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds)); 1568 pw.print("mStableChargingThresholdMillis="); 1569 TimeUtils.formatDuration(mStableChargingThresholdMillis, pw); 1570 pw.println(); 1571 } 1572 1573 /** 1574 * Injector for interaction with external code. Override methods to provide a mock 1575 * implementation for tests. 1576 * onBootPhase() must be called with at least the PHASE_SYSTEM_SERVICES_READY 1577 */ 1578 static class Injector { 1579 1580 private final Context mContext; 1581 private final Looper mLooper; 1582 private IDeviceIdleController mDeviceIdleController; 1583 private IBatteryStats mBatteryStats; 1584 private PackageManagerInternal mPackageManagerInternal; 1585 private DisplayManager mDisplayManager; 1586 private PowerManager mPowerManager; 1587 int mBootPhase; 1588 Injector(Context context, Looper looper)1589 Injector(Context context, Looper looper) { 1590 mContext = context; 1591 mLooper = looper; 1592 } 1593 getContext()1594 Context getContext() { 1595 return mContext; 1596 } 1597 getLooper()1598 Looper getLooper() { 1599 return mLooper; 1600 } 1601 onBootPhase(int phase)1602 void onBootPhase(int phase) { 1603 if (phase == PHASE_SYSTEM_SERVICES_READY) { 1604 mDeviceIdleController = IDeviceIdleController.Stub.asInterface( 1605 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); 1606 mBatteryStats = IBatteryStats.Stub.asInterface( 1607 ServiceManager.getService(BatteryStats.SERVICE_NAME)); 1608 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); 1609 mDisplayManager = (DisplayManager) mContext.getSystemService( 1610 Context.DISPLAY_SERVICE); 1611 mPowerManager = mContext.getSystemService(PowerManager.class); 1612 } 1613 mBootPhase = phase; 1614 } 1615 getBootPhase()1616 int getBootPhase() { 1617 return mBootPhase; 1618 } 1619 1620 /** 1621 * Returns the elapsed realtime since the device started. Override this 1622 * to control the clock. 1623 * @return elapsed realtime 1624 */ elapsedRealtime()1625 long elapsedRealtime() { 1626 return SystemClock.elapsedRealtime(); 1627 } 1628 currentTimeMillis()1629 long currentTimeMillis() { 1630 return System.currentTimeMillis(); 1631 } 1632 isAppIdleEnabled()1633 boolean isAppIdleEnabled() { 1634 final boolean buildFlag = mContext.getResources().getBoolean( 1635 com.android.internal.R.bool.config_enableAutoPowerModes); 1636 final boolean runtimeFlag = Global.getInt(mContext.getContentResolver(), 1637 Global.APP_STANDBY_ENABLED, 1) == 1 1638 && Global.getInt(mContext.getContentResolver(), 1639 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 1) == 1; 1640 return buildFlag && runtimeFlag; 1641 } 1642 isCharging()1643 boolean isCharging() { 1644 return mContext.getSystemService(BatteryManager.class).isCharging(); 1645 } 1646 isPowerSaveWhitelistExceptIdleApp(String packageName)1647 boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException { 1648 return mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName); 1649 } 1650 getDataSystemDirectory()1651 File getDataSystemDirectory() { 1652 return Environment.getDataSystemDirectory(); 1653 } 1654 noteEvent(int event, String packageName, int uid)1655 void noteEvent(int event, String packageName, int uid) throws RemoteException { 1656 mBatteryStats.noteEvent(event, packageName, uid); 1657 } 1658 isPackageEphemeral(int userId, String packageName)1659 boolean isPackageEphemeral(int userId, String packageName) { 1660 return mPackageManagerInternal.isPackageEphemeral(userId, packageName); 1661 } 1662 isPackageInstalled(String packageName, int flags, int userId)1663 boolean isPackageInstalled(String packageName, int flags, int userId) { 1664 return mPackageManagerInternal.getPackageUid(packageName, flags, userId) >= 0; 1665 } 1666 getRunningUserIds()1667 int[] getRunningUserIds() throws RemoteException { 1668 return ActivityManager.getService().getRunningUserIds(); 1669 } 1670 isDefaultDisplayOn()1671 boolean isDefaultDisplayOn() { 1672 return mDisplayManager 1673 .getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_ON; 1674 } 1675 registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler)1676 void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) { 1677 mDisplayManager.registerDisplayListener(listener, handler); 1678 } 1679 getActiveNetworkScorer()1680 String getActiveNetworkScorer() { 1681 NetworkScoreManager nsm = (NetworkScoreManager) mContext.getSystemService( 1682 Context.NETWORK_SCORE_SERVICE); 1683 return nsm.getActiveScorerPackage(); 1684 } 1685 isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName, int userId)1686 public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName, 1687 int userId) { 1688 return appWidgetManager.isBoundWidgetPackage(packageName, userId); 1689 } 1690 getAppIdleSettings()1691 String getAppIdleSettings() { 1692 return Global.getString(mContext.getContentResolver(), 1693 Global.APP_IDLE_CONSTANTS); 1694 } 1695 1696 /** Whether the device is in doze or not. */ isDeviceIdleMode()1697 public boolean isDeviceIdleMode() { 1698 return mPowerManager.isDeviceIdleMode(); 1699 } 1700 } 1701 1702 class AppStandbyHandler extends Handler { 1703 AppStandbyHandler(Looper looper)1704 AppStandbyHandler(Looper looper) { 1705 super(looper); 1706 } 1707 1708 @Override handleMessage(Message msg)1709 public void handleMessage(Message msg) { 1710 switch (msg.what) { 1711 case MSG_INFORM_LISTENERS: 1712 StandbyUpdateRecord r = (StandbyUpdateRecord) msg.obj; 1713 informListeners(r.packageName, r.userId, r.bucket, r.reason, 1714 r.isUserInteraction); 1715 r.recycle(); 1716 break; 1717 1718 case MSG_FORCE_IDLE_STATE: 1719 forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1); 1720 break; 1721 1722 case MSG_CHECK_IDLE_STATES: 1723 if (checkIdleStates(msg.arg1) && mAppIdleEnabled) { 1724 mHandler.sendMessageDelayed(mHandler.obtainMessage( 1725 MSG_CHECK_IDLE_STATES, msg.arg1, 0), 1726 mCheckIdleIntervalMillis); 1727 } 1728 break; 1729 1730 case MSG_ONE_TIME_CHECK_IDLE_STATES: 1731 mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES); 1732 waitForAdminData(); 1733 checkIdleStates(UserHandle.USER_ALL); 1734 break; 1735 1736 case MSG_CHECK_PAROLE_TIMEOUT: 1737 checkParoleTimeout(); 1738 break; 1739 1740 case MSG_PAROLE_END_TIMEOUT: 1741 if (DEBUG) Slog.d(TAG, "Ending parole"); 1742 setAppIdleParoled(false); 1743 break; 1744 1745 case MSG_REPORT_CONTENT_PROVIDER_USAGE: 1746 SomeArgs args = (SomeArgs) msg.obj; 1747 reportContentProviderUsage((String) args.arg1, // authority name 1748 (String) args.arg2, // package name 1749 (int) args.arg3); // userId 1750 args.recycle(); 1751 break; 1752 1753 case MSG_PAROLE_STATE_CHANGED: 1754 if (DEBUG) Slog.d(TAG, "Parole state: " + mAppIdleTempParoled 1755 + ", Charging state:" + mChargingStable); 1756 informParoleStateChanged(); 1757 break; 1758 case MSG_CHECK_PACKAGE_IDLE_STATE: 1759 checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2, 1760 mInjector.elapsedRealtime()); 1761 break; 1762 1763 case MSG_REPORT_SYNC_SCHEDULED: 1764 final boolean exempted = msg.arg1 > 0 ? true : false; 1765 if (exempted) { 1766 reportExemptedSyncScheduled((String) msg.obj, msg.arg1); 1767 } else { 1768 reportUnexemptedSyncScheduled((String) msg.obj, msg.arg1); 1769 } 1770 break; 1771 1772 case MSG_REPORT_EXEMPTED_SYNC_START: 1773 reportExemptedSyncStart((String) msg.obj, msg.arg1); 1774 break; 1775 1776 case MSG_UPDATE_STABLE_CHARGING: 1777 updateChargingStableState(); 1778 break; 1779 1780 default: 1781 super.handleMessage(msg); 1782 break; 1783 1784 } 1785 } 1786 }; 1787 1788 private class DeviceStateReceiver extends BroadcastReceiver { 1789 @Override onReceive(Context context, Intent intent)1790 public void onReceive(Context context, Intent intent) { 1791 switch (intent.getAction()) { 1792 case BatteryManager.ACTION_CHARGING: 1793 setChargingState(true); 1794 break; 1795 case BatteryManager.ACTION_DISCHARGING: 1796 setChargingState(false); 1797 break; 1798 case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED: 1799 onDeviceIdleModeChanged(); 1800 break; 1801 } 1802 } 1803 } 1804 1805 private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder().build(); 1806 1807 private final ConnectivityManager.NetworkCallback mNetworkCallback 1808 = new ConnectivityManager.NetworkCallback() { 1809 @Override 1810 public void onAvailable(Network network) { 1811 mConnectivityManager.unregisterNetworkCallback(this); 1812 checkParoleTimeout(); 1813 } 1814 }; 1815 1816 private final DisplayManager.DisplayListener mDisplayListener 1817 = new DisplayManager.DisplayListener() { 1818 1819 @Override public void onDisplayAdded(int displayId) { 1820 } 1821 1822 @Override public void onDisplayRemoved(int displayId) { 1823 } 1824 1825 @Override public void onDisplayChanged(int displayId) { 1826 if (displayId == Display.DEFAULT_DISPLAY) { 1827 final boolean displayOn = isDisplayOn(); 1828 synchronized (mAppIdleLock) { 1829 mAppIdleHistory.updateDisplay(displayOn, mInjector.elapsedRealtime()); 1830 } 1831 } 1832 } 1833 }; 1834 1835 /** 1836 * Observe settings changes for {@link Global#APP_IDLE_CONSTANTS}. 1837 */ 1838 private class SettingsObserver extends ContentObserver { 1839 /** 1840 * This flag has been used to disable app idle on older builds with bug b/26355386. 1841 */ 1842 @Deprecated 1843 private static final String KEY_IDLE_DURATION_OLD = "idle_duration"; 1844 @Deprecated 1845 private static final String KEY_IDLE_DURATION = "idle_duration2"; 1846 @Deprecated 1847 private static final String KEY_WALLCLOCK_THRESHOLD = "wallclock_threshold"; 1848 1849 private static final String KEY_PAROLE_INTERVAL = "parole_interval"; 1850 private static final String KEY_PAROLE_WINDOW = "parole_window"; 1851 private static final String KEY_PAROLE_DURATION = "parole_duration"; 1852 private static final String KEY_SCREEN_TIME_THRESHOLDS = "screen_thresholds"; 1853 private static final String KEY_ELAPSED_TIME_THRESHOLDS = "elapsed_thresholds"; 1854 private static final String KEY_STRONG_USAGE_HOLD_DURATION = "strong_usage_duration"; 1855 private static final String KEY_NOTIFICATION_SEEN_HOLD_DURATION = 1856 "notification_seen_duration"; 1857 private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION = 1858 "system_update_usage_duration"; 1859 private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout"; 1860 private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration"; 1861 private static final String KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION = 1862 "exempted_sync_scheduled_nd_duration"; 1863 private static final String KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION = 1864 "exempted_sync_scheduled_d_duration"; 1865 private static final String KEY_EXEMPTED_SYNC_START_HOLD_DURATION = 1866 "exempted_sync_start_duration"; 1867 private static final String KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION = 1868 "unexempted_sync_scheduled_duration"; 1869 private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION = 1870 "system_interaction_duration"; 1871 private static final String KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION = 1872 "initial_foreground_service_start_duration"; 1873 private static final String KEY_STABLE_CHARGING_THRESHOLD = "stable_charging_threshold"; 1874 public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR; 1875 public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR; 1876 public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR; 1877 public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE; 1878 public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE; 1879 public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT = 10 * ONE_MINUTE; 1880 public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = 4 * ONE_HOUR; 1881 public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 10 * ONE_MINUTE; 1882 public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 10 * ONE_MINUTE; 1883 public static final long DEFAULT_STABLE_CHARGING_THRESHOLD = 10 * ONE_MINUTE; 1884 public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE; 1885 1886 private final KeyValueListParser mParser = new KeyValueListParser(','); 1887 SettingsObserver(Handler handler)1888 SettingsObserver(Handler handler) { 1889 super(handler); 1890 } 1891 registerObserver()1892 void registerObserver() { 1893 final ContentResolver cr = mContext.getContentResolver(); 1894 cr.registerContentObserver(Global.getUriFor(Global.APP_IDLE_CONSTANTS), false, this); 1895 cr.registerContentObserver(Global.getUriFor(Global.APP_STANDBY_ENABLED), false, this); 1896 cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED), 1897 false, this); 1898 } 1899 1900 @Override onChange(boolean selfChange)1901 public void onChange(boolean selfChange) { 1902 updateSettings(); 1903 postOneTimeCheckIdleStates(); 1904 } 1905 updateSettings()1906 void updateSettings() { 1907 if (DEBUG) { 1908 Slog.d(TAG, 1909 "appidle=" + Global.getString(mContext.getContentResolver(), 1910 Global.APP_STANDBY_ENABLED)); 1911 Slog.d(TAG, 1912 "adaptivebat=" + Global.getString(mContext.getContentResolver(), 1913 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED)); 1914 Slog.d(TAG, "appidleconstants=" + Global.getString( 1915 mContext.getContentResolver(), 1916 Global.APP_IDLE_CONSTANTS)); 1917 } 1918 1919 // Look at global settings for this. 1920 // TODO: Maybe apply different thresholds for different users. 1921 try { 1922 mParser.setString(mInjector.getAppIdleSettings()); 1923 } catch (IllegalArgumentException e) { 1924 Slog.e(TAG, "Bad value for app idle settings: " + e.getMessage()); 1925 // fallthrough, mParser is empty and all defaults will be returned. 1926 } 1927 1928 synchronized (mAppIdleLock) { 1929 1930 // Default: 24 hours between paroles 1931 mAppIdleParoleIntervalMillis = mParser.getDurationMillis(KEY_PAROLE_INTERVAL, 1932 COMPRESS_TIME ? ONE_MINUTE * 10 : 24 * 60 * ONE_MINUTE); 1933 1934 // Default: 2 hours to wait on network 1935 mAppIdleParoleWindowMillis = mParser.getDurationMillis(KEY_PAROLE_WINDOW, 1936 COMPRESS_TIME ? ONE_MINUTE * 2 : 2 * 60 * ONE_MINUTE); 1937 1938 mAppIdleParoleDurationMillis = mParser.getDurationMillis(KEY_PAROLE_DURATION, 1939 COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE); // 10 minutes 1940 1941 String screenThresholdsValue = mParser.getString(KEY_SCREEN_TIME_THRESHOLDS, null); 1942 mAppStandbyScreenThresholds = parseLongArray(screenThresholdsValue, 1943 SCREEN_TIME_THRESHOLDS); 1944 1945 String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS, 1946 null); 1947 mAppStandbyElapsedThresholds = parseLongArray(elapsedThresholdsValue, 1948 ELAPSED_TIME_THRESHOLDS); 1949 mCheckIdleIntervalMillis = Math.min(mAppStandbyElapsedThresholds[1] / 4, 1950 COMPRESS_TIME ? ONE_MINUTE : 4 * 60 * ONE_MINUTE); // 4 hours 1951 mStrongUsageTimeoutMillis = mParser.getDurationMillis( 1952 KEY_STRONG_USAGE_HOLD_DURATION, 1953 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STRONG_USAGE_TIMEOUT); 1954 mNotificationSeenTimeoutMillis = mParser.getDurationMillis( 1955 KEY_NOTIFICATION_SEEN_HOLD_DURATION, 1956 COMPRESS_TIME ? 12 * ONE_MINUTE : DEFAULT_NOTIFICATION_TIMEOUT); 1957 mSystemUpdateUsageTimeoutMillis = mParser.getDurationMillis( 1958 KEY_SYSTEM_UPDATE_HOLD_DURATION, 1959 COMPRESS_TIME ? 2 * ONE_MINUTE : DEFAULT_SYSTEM_UPDATE_TIMEOUT); 1960 mPredictionTimeoutMillis = mParser.getDurationMillis( 1961 KEY_PREDICTION_TIMEOUT, 1962 COMPRESS_TIME ? 10 * ONE_MINUTE : DEFAULT_PREDICTION_TIMEOUT); 1963 mSyncAdapterTimeoutMillis = mParser.getDurationMillis( 1964 KEY_SYNC_ADAPTER_HOLD_DURATION, 1965 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT); 1966 1967 mExemptedSyncScheduledNonDozeTimeoutMillis = mParser.getDurationMillis( 1968 KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION, 1969 COMPRESS_TIME ? (ONE_MINUTE / 2) 1970 : DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT); 1971 1972 mExemptedSyncScheduledDozeTimeoutMillis = mParser.getDurationMillis( 1973 KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION, 1974 COMPRESS_TIME ? ONE_MINUTE 1975 : DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT); 1976 1977 mExemptedSyncStartTimeoutMillis = mParser.getDurationMillis( 1978 KEY_EXEMPTED_SYNC_START_HOLD_DURATION, 1979 COMPRESS_TIME ? ONE_MINUTE 1980 : DEFAULT_EXEMPTED_SYNC_START_TIMEOUT); 1981 1982 mUnexemptedSyncScheduledTimeoutMillis = mParser.getDurationMillis( 1983 KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION, 1984 COMPRESS_TIME ? ONE_MINUTE 1985 : DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT); // TODO 1986 1987 mSystemInteractionTimeoutMillis = mParser.getDurationMillis( 1988 KEY_SYSTEM_INTERACTION_HOLD_DURATION, 1989 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT); 1990 1991 mInitialForegroundServiceStartTimeoutMillis = mParser.getDurationMillis( 1992 KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION, 1993 COMPRESS_TIME ? ONE_MINUTE : 1994 DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT); 1995 1996 mStableChargingThresholdMillis = mParser.getDurationMillis( 1997 KEY_STABLE_CHARGING_THRESHOLD, 1998 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD); 1999 } 2000 2001 // Check if app_idle_enabled has changed. Do this after getting the rest of the settings 2002 // in case we need to change something based on the new values. 2003 setAppIdleEnabled(mInjector.isAppIdleEnabled()); 2004 } 2005 parseLongArray(String values, long[] defaults)2006 long[] parseLongArray(String values, long[] defaults) { 2007 if (values == null) return defaults; 2008 if (values.isEmpty()) { 2009 // Reset to defaults 2010 return defaults; 2011 } else { 2012 String[] thresholds = values.split("/"); 2013 if (thresholds.length == THRESHOLD_BUCKETS.length) { 2014 long[] array = new long[THRESHOLD_BUCKETS.length]; 2015 for (int i = 0; i < THRESHOLD_BUCKETS.length; i++) { 2016 try { 2017 if (thresholds[i].startsWith("P") || thresholds[i].startsWith("p")) { 2018 array[i] = Duration.parse(thresholds[i]).toMillis(); 2019 } else { 2020 array[i] = Long.parseLong(thresholds[i]); 2021 } 2022 } catch (NumberFormatException|DateTimeParseException e) { 2023 return defaults; 2024 } 2025 } 2026 return array; 2027 } else { 2028 return defaults; 2029 } 2030 } 2031 } 2032 } 2033 } 2034