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