• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy
6  * of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations
14  * under the License.
15  */
16 
17 package com.android.server.usage;
18 
19 import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
20 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
21 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
22 import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK;
23 import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
24 import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
25 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
26 import static android.app.usage.UsageStatsManager.REASON_SUB_DEFAULT_APP_UPDATE;
27 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY;
28 import static android.app.usage.UsageStatsManager.REASON_SUB_MASK;
29 import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
30 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
31 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
32 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
33 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START;
34 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
35 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
36 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
37 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
38 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
39 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
40 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER;
41 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
42 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
43 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED;
44 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
45 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
46 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
47 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
48 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
49 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
50 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED;
51 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
52 
53 import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
54 import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
55 
56 import android.annotation.NonNull;
57 import android.annotation.Nullable;
58 import android.annotation.UserIdInt;
59 import android.app.ActivityManager;
60 import android.app.AppGlobals;
61 import android.app.usage.AppStandbyInfo;
62 import android.app.usage.UsageEvents;
63 import android.app.usage.UsageStatsManager.StandbyBuckets;
64 import android.app.usage.UsageStatsManager.SystemForcedReasons;
65 import android.appwidget.AppWidgetManager;
66 import android.content.BroadcastReceiver;
67 import android.content.ContentResolver;
68 import android.content.Context;
69 import android.content.Intent;
70 import android.content.IntentFilter;
71 import android.content.pm.ApplicationInfo;
72 import android.content.pm.CrossProfileAppsInternal;
73 import android.content.pm.PackageInfo;
74 import android.content.pm.PackageManager;
75 import android.content.pm.PackageManagerInternal;
76 import android.content.pm.ParceledListSlice;
77 import android.database.ContentObserver;
78 import android.hardware.display.DisplayManager;
79 import android.net.NetworkScoreManager;
80 import android.os.BatteryManager;
81 import android.os.BatteryStats;
82 import android.os.Build;
83 import android.os.Environment;
84 import android.os.Handler;
85 import android.os.IDeviceIdleController;
86 import android.os.Looper;
87 import android.os.Message;
88 import android.os.PowerManager;
89 import android.os.Process;
90 import android.os.RemoteException;
91 import android.os.ServiceManager;
92 import android.os.SystemClock;
93 import android.os.Trace;
94 import android.os.UserHandle;
95 import android.provider.Settings.Global;
96 import android.telephony.TelephonyManager;
97 import android.util.ArraySet;
98 import android.util.KeyValueListParser;
99 import android.util.Slog;
100 import android.util.SparseArray;
101 import android.util.SparseIntArray;
102 import android.util.TimeUtils;
103 import android.view.Display;
104 import android.widget.Toast;
105 
106 import com.android.internal.R;
107 import com.android.internal.annotations.GuardedBy;
108 import com.android.internal.annotations.VisibleForTesting;
109 import com.android.internal.app.IBatteryStats;
110 import com.android.internal.os.SomeArgs;
111 import com.android.internal.util.ArrayUtils;
112 import com.android.internal.util.ConcurrentUtils;
113 import com.android.internal.util.IndentingPrintWriter;
114 import com.android.server.LocalServices;
115 import com.android.server.pm.parsing.pkg.AndroidPackage;
116 import com.android.server.usage.AppIdleHistory.AppUsageHistory;
117 
118 import java.io.File;
119 import java.io.PrintWriter;
120 import java.time.Duration;
121 import java.time.format.DateTimeParseException;
122 import java.util.ArrayList;
123 import java.util.Arrays;
124 import java.util.Collections;
125 import java.util.List;
126 import java.util.Set;
127 import java.util.concurrent.CountDownLatch;
128 
129 /**
130  * Manages the standby state of an app, listening to various events.
131  *
132  * Unit test:
133    atest com.android.server.usage.AppStandbyControllerTests
134  */
135 public class AppStandbyController implements AppStandbyInternal {
136 
137     private static final String TAG = "AppStandbyController";
138     // Do not submit with true.
139     static final boolean DEBUG = false;
140 
141     static final boolean COMPRESS_TIME = false;
142     private static final long ONE_MINUTE = 60 * 1000;
143     private static final long ONE_HOUR = ONE_MINUTE * 60;
144     private static final long ONE_DAY = ONE_HOUR * 24;
145 
146     /**
147      * The minimum amount of time the screen must have been on before an app can time out from its
148      * current bucket to the next bucket.
149      */
150     private static final long[] SCREEN_TIME_THRESHOLDS = {
151             0,
152             0,
153             COMPRESS_TIME ? 2 * ONE_MINUTE : 1 * ONE_HOUR,
154             COMPRESS_TIME ? 4 * ONE_MINUTE : 2 * ONE_HOUR,
155             COMPRESS_TIME ? 8 * ONE_MINUTE : 6 * ONE_HOUR
156     };
157 
158     /** The minimum allowed values for each index in {@link #SCREEN_TIME_THRESHOLDS}. */
159     private static final long[] MINIMUM_SCREEN_TIME_THRESHOLDS = COMPRESS_TIME
160             ? new long[SCREEN_TIME_THRESHOLDS.length]
161             : new long[]{
162                     0,
163                     0,
164                     0,
165                     30 * ONE_MINUTE,
166                     ONE_HOUR
167             };
168 
169     /**
170      * The minimum amount of elapsed time that must have passed before an app can time out from its
171      * current bucket to the next bucket.
172      */
173     private static final long[] ELAPSED_TIME_THRESHOLDS = {
174             0,
175             COMPRESS_TIME ?  1 * ONE_MINUTE : 12 * ONE_HOUR,
176             COMPRESS_TIME ?  4 * ONE_MINUTE : 24 * ONE_HOUR,
177             COMPRESS_TIME ? 16 * ONE_MINUTE : 48 * ONE_HOUR,
178             COMPRESS_TIME ? 32 * ONE_MINUTE : 30 * ONE_DAY
179     };
180 
181     /** The minimum allowed values for each index in {@link #ELAPSED_TIME_THRESHOLDS}. */
182     private static final long[] MINIMUM_ELAPSED_TIME_THRESHOLDS = COMPRESS_TIME
183             ? new long[ELAPSED_TIME_THRESHOLDS.length]
184             : new long[]{
185                     0,
186                     ONE_HOUR,
187                     ONE_HOUR,
188                     2 * ONE_HOUR,
189                     4 * ONE_DAY
190             };
191 
192     private static final int[] THRESHOLD_BUCKETS = {
193             STANDBY_BUCKET_ACTIVE,
194             STANDBY_BUCKET_WORKING_SET,
195             STANDBY_BUCKET_FREQUENT,
196             STANDBY_BUCKET_RARE,
197             STANDBY_BUCKET_RESTRICTED
198     };
199 
200     /** Default expiration time for bucket prediction. After this, use thresholds to downgrade. */
201     private static final long DEFAULT_PREDICTION_TIMEOUT = 12 * ONE_HOUR;
202 
203     /**
204      * Indicates the maximum wait time for admin data to be available;
205      */
206     private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;
207 
208     private static final int HEADLESS_APP_CHECK_FLAGS =
209             PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
210                     | PackageManager.GET_ACTIVITIES | PackageManager.MATCH_DISABLED_COMPONENTS;
211 
212     // To name the lock for stack traces
213     static class Lock {}
214 
215     /** Lock to protect the app's standby state. Required for calls into AppIdleHistory */
216     private final Object mAppIdleLock = new Lock();
217 
218     /** Keeps the history and state for each app. */
219     @GuardedBy("mAppIdleLock")
220     private AppIdleHistory mAppIdleHistory;
221 
222     @GuardedBy("mPackageAccessListeners")
223     private final ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>();
224 
225     /** Whether we've queried the list of carrier privileged apps. */
226     @GuardedBy("mAppIdleLock")
227     private boolean mHaveCarrierPrivilegedApps;
228 
229     /** List of carrier-privileged apps that should be excluded from standby */
230     @GuardedBy("mAppIdleLock")
231     private List<String> mCarrierPrivilegedApps;
232 
233     @GuardedBy("mActiveAdminApps")
234     private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
235 
236     /**
237      * Set of system apps that are headless (don't have any declared activities, enabled or
238      * disabled). Presence in this map indicates that the app is a headless system app.
239      */
240     @GuardedBy("mHeadlessSystemApps")
241     private final ArraySet<String> mHeadlessSystemApps = new ArraySet<>();
242 
243     private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1);
244 
245     // Cache the active network scorer queried from the network scorer service
246     private volatile String mCachedNetworkScorer = null;
247     // The last time the network scorer service was queried
248     private volatile long mCachedNetworkScorerAtMillis = 0L;
249     // How long before querying the network scorer again. During this time, subsequent queries will
250     // get the cached value
251     private static final long NETWORK_SCORER_CACHE_DURATION_MILLIS = 5000L;
252 
253     // Messages for the handler
254     static final int MSG_INFORM_LISTENERS = 3;
255     static final int MSG_FORCE_IDLE_STATE = 4;
256     static final int MSG_CHECK_IDLE_STATES = 5;
257     static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
258     static final int MSG_PAROLE_STATE_CHANGED = 9;
259     static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
260     /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
261     static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
262     static final int MSG_REPORT_SYNC_SCHEDULED = 12;
263     static final int MSG_REPORT_EXEMPTED_SYNC_START = 13;
264 
265     long mCheckIdleIntervalMillis;
266     /**
267      * The minimum amount of time the screen must have been on before an app can time out from its
268      * current bucket to the next bucket.
269      */
270     long[] mAppStandbyScreenThresholds = SCREEN_TIME_THRESHOLDS;
271     /**
272      * The minimum amount of elapsed time that must have passed before an app can time out from its
273      * current bucket to the next bucket.
274      */
275     long[] mAppStandbyElapsedThresholds = ELAPSED_TIME_THRESHOLDS;
276     /** Minimum time a strong usage event should keep the bucket elevated. */
277     long mStrongUsageTimeoutMillis;
278     /** Minimum time a notification seen event should keep the bucket elevated. */
279     long mNotificationSeenTimeoutMillis;
280     /** Minimum time a system update event should keep the buckets elevated. */
281     long mSystemUpdateUsageTimeoutMillis;
282     /** Maximum time to wait for a prediction before using simple timeouts to downgrade buckets. */
283     long mPredictionTimeoutMillis;
284     /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */
285     long mSyncAdapterTimeoutMillis;
286     /**
287      * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
288      * non-doze
289      */
290     long mExemptedSyncScheduledNonDozeTimeoutMillis;
291     /**
292      * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
293      * doze
294      */
295     long mExemptedSyncScheduledDozeTimeoutMillis;
296     /**
297      * Maximum time an exempted sync should keep the buckets elevated, when sync is started.
298      */
299     long mExemptedSyncStartTimeoutMillis;
300     /**
301      * Maximum time an unexempted sync should keep the buckets elevated, when sync is scheduled
302      */
303     long mUnexemptedSyncScheduledTimeoutMillis;
304     /** Maximum time a system interaction should keep the buckets elevated. */
305     long mSystemInteractionTimeoutMillis;
306     /**
307      * Maximum time a foreground service start should keep the buckets elevated if the service
308      * start is the first usage of the app
309      */
310     long mInitialForegroundServiceStartTimeoutMillis;
311     /**
312      * User usage that would elevate an app's standby bucket will also elevate the standby bucket of
313      * cross profile connected apps. Explicit standby bucket setting via
314      * {@link #setAppStandbyBucket(String, int, int, int, int)} will not be propagated.
315      */
316     boolean mLinkCrossProfileApps;
317     /**
318      * Whether we should allow apps into the
319      * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not.
320      * If false, any attempts to put an app into the bucket will put the app into the
321      * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RARE} bucket instead.
322      */
323     private boolean mAllowRestrictedBucket;
324 
325     private volatile boolean mAppIdleEnabled;
326     private boolean mIsCharging;
327     private boolean mSystemServicesReady = false;
328     // There was a system update, defaults need to be initialized after services are ready
329     private boolean mPendingInitializeDefaults;
330 
331     private volatile boolean mPendingOneTimeCheckIdleStates;
332 
333     private final AppStandbyHandler mHandler;
334     private final Context mContext;
335 
336     private AppWidgetManager mAppWidgetManager;
337     private PackageManager mPackageManager;
338     Injector mInjector;
339 
340     static final ArrayList<StandbyUpdateRecord> sStandbyUpdatePool = new ArrayList<>(4);
341 
342     public static class StandbyUpdateRecord {
343         // Identity of the app whose standby state has changed
344         String packageName;
345         int userId;
346 
347         // What the standby bucket the app is now in
348         int bucket;
349 
350         // Whether the bucket change is because the user has started interacting with the app
351         boolean isUserInteraction;
352 
353         // Reason for bucket change
354         int reason;
355 
StandbyUpdateRecord(String pkgName, int userId, int bucket, int reason, boolean isInteraction)356         StandbyUpdateRecord(String pkgName, int userId, int bucket, int reason,
357                 boolean isInteraction) {
358             this.packageName = pkgName;
359             this.userId = userId;
360             this.bucket = bucket;
361             this.reason = reason;
362             this.isUserInteraction = isInteraction;
363         }
364 
obtain(String pkgName, int userId, int bucket, int reason, boolean isInteraction)365         public static StandbyUpdateRecord obtain(String pkgName, int userId,
366                 int bucket, int reason, boolean isInteraction) {
367             synchronized (sStandbyUpdatePool) {
368                 final int size = sStandbyUpdatePool.size();
369                 if (size < 1) {
370                     return new StandbyUpdateRecord(pkgName, userId, bucket, reason, isInteraction);
371                 }
372                 StandbyUpdateRecord r = sStandbyUpdatePool.remove(size - 1);
373                 r.packageName = pkgName;
374                 r.userId = userId;
375                 r.bucket = bucket;
376                 r.reason = reason;
377                 r.isUserInteraction = isInteraction;
378                 return r;
379             }
380         }
381 
recycle()382         public void recycle() {
383             synchronized (sStandbyUpdatePool) {
384                 sStandbyUpdatePool.add(this);
385             }
386         }
387     }
388 
AppStandbyController(Context context, Looper looper)389     public AppStandbyController(Context context, Looper looper) {
390         this(new Injector(context, looper));
391     }
392 
AppStandbyController(Injector injector)393     AppStandbyController(Injector injector) {
394         mInjector = injector;
395         mContext = mInjector.getContext();
396         mHandler = new AppStandbyHandler(mInjector.getLooper());
397         mPackageManager = mContext.getPackageManager();
398 
399         DeviceStateReceiver deviceStateReceiver = new DeviceStateReceiver();
400         IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
401         deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
402         deviceStates.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
403         mContext.registerReceiver(deviceStateReceiver, deviceStates);
404 
405         synchronized (mAppIdleLock) {
406             mAppIdleHistory = new AppIdleHistory(mInjector.getDataSystemDirectory(),
407                     mInjector.elapsedRealtime());
408         }
409 
410         IntentFilter packageFilter = new IntentFilter();
411         packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
412         packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
413         packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
414         packageFilter.addDataScheme("package");
415 
416         mContext.registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter,
417                 null, mHandler);
418     }
419 
420     @VisibleForTesting
setAppIdleEnabled(boolean enabled)421     void setAppIdleEnabled(boolean enabled) {
422         synchronized (mAppIdleLock) {
423             if (mAppIdleEnabled != enabled) {
424                 final boolean oldParoleState = isInParole();
425                 mAppIdleEnabled = enabled;
426                 if (isInParole() != oldParoleState) {
427                     postParoleStateChanged();
428                 }
429             }
430         }
431 
432     }
433 
434     @Override
isAppIdleEnabled()435     public boolean isAppIdleEnabled() {
436         return mAppIdleEnabled;
437     }
438 
439     @Override
onBootPhase(int phase)440     public void onBootPhase(int phase) {
441         mInjector.onBootPhase(phase);
442         if (phase == PHASE_SYSTEM_SERVICES_READY) {
443             Slog.d(TAG, "Setting app idle enabled state");
444             // Observe changes to the threshold
445             SettingsObserver settingsObserver = new SettingsObserver(mHandler);
446             settingsObserver.registerObserver();
447             settingsObserver.updateSettings();
448 
449             mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class);
450 
451             mInjector.registerDisplayListener(mDisplayListener, mHandler);
452             synchronized (mAppIdleLock) {
453                 mAppIdleHistory.updateDisplay(isDisplayOn(), mInjector.elapsedRealtime());
454             }
455 
456             mSystemServicesReady = true;
457 
458             boolean userFileExists;
459             synchronized (mAppIdleLock) {
460                 userFileExists = mAppIdleHistory.userFileExists(UserHandle.USER_SYSTEM);
461             }
462 
463             if (mPendingInitializeDefaults || !userFileExists) {
464                 initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM);
465             }
466 
467             if (mPendingOneTimeCheckIdleStates) {
468                 postOneTimeCheckIdleStates();
469             }
470         } else if (phase == PHASE_BOOT_COMPLETED) {
471             setChargingState(mInjector.isCharging());
472 
473             // Offload to handler thread after boot completed to avoid boot time impact. This means
474             // that app standby buckets may be slightly out of date and headless system apps may be
475             // put in a lower bucket until boot has completed.
476             mHandler.post(AppStandbyController.this::updatePowerWhitelistCache);
477             mHandler.post(this::loadHeadlessSystemAppCache);
478         }
479     }
480 
reportContentProviderUsage(String authority, String providerPkgName, int userId)481     private void reportContentProviderUsage(String authority, String providerPkgName, int userId) {
482         if (!mAppIdleEnabled) return;
483 
484         // Get sync adapters for the authority
485         String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser(
486                 authority, userId);
487         final long elapsedRealtime = mInjector.elapsedRealtime();
488         for (String packageName: packages) {
489             // Only force the sync adapters to active if the provider is not in the same package and
490             // the sync adapter is a system package.
491             try {
492                 PackageInfo pi = mPackageManager.getPackageInfoAsUser(
493                         packageName, PackageManager.MATCH_SYSTEM_ONLY, userId);
494                 if (pi == null || pi.applicationInfo == null) {
495                     continue;
496                 }
497                 if (!packageName.equals(providerPkgName)) {
498                     final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName,
499                             userId);
500                     synchronized (mAppIdleLock) {
501                         reportNoninteractiveUsageCrossUserLocked(packageName, userId,
502                                 STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_SYNC_ADAPTER,
503                                 elapsedRealtime, mSyncAdapterTimeoutMillis, linkedProfiles);
504                     }
505                 }
506             } catch (PackageManager.NameNotFoundException e) {
507                 // Shouldn't happen
508             }
509         }
510     }
511 
reportExemptedSyncScheduled(String packageName, int userId)512     private void reportExemptedSyncScheduled(String packageName, int userId) {
513         if (!mAppIdleEnabled) return;
514 
515         final int bucketToPromote;
516         final int usageReason;
517         final long durationMillis;
518 
519         if (!mInjector.isDeviceIdleMode()) {
520             // Not dozing.
521             bucketToPromote = STANDBY_BUCKET_ACTIVE;
522             usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
523             durationMillis = mExemptedSyncScheduledNonDozeTimeoutMillis;
524         } else {
525             // Dozing.
526             bucketToPromote = STANDBY_BUCKET_WORKING_SET;
527             usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
528             durationMillis = mExemptedSyncScheduledDozeTimeoutMillis;
529         }
530 
531         final long elapsedRealtime = mInjector.elapsedRealtime();
532         final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
533         synchronized (mAppIdleLock) {
534             reportNoninteractiveUsageCrossUserLocked(packageName, userId, bucketToPromote,
535                     usageReason, elapsedRealtime, durationMillis, linkedProfiles);
536         }
537     }
538 
reportUnexemptedSyncScheduled(String packageName, int userId)539     private void reportUnexemptedSyncScheduled(String packageName, int userId) {
540         if (!mAppIdleEnabled) return;
541 
542         final long elapsedRealtime = mInjector.elapsedRealtime();
543         synchronized (mAppIdleLock) {
544             final int currentBucket =
545                     mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
546             if (currentBucket == STANDBY_BUCKET_NEVER) {
547                 final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
548                 // Bring the app out of the never bucket
549                 reportNoninteractiveUsageCrossUserLocked(packageName, userId,
550                         STANDBY_BUCKET_WORKING_SET, REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED,
551                         elapsedRealtime, mUnexemptedSyncScheduledTimeoutMillis, linkedProfiles);
552             }
553         }
554     }
555 
reportExemptedSyncStart(String packageName, int userId)556     private void reportExemptedSyncStart(String packageName, int userId) {
557         if (!mAppIdleEnabled) return;
558 
559         final long elapsedRealtime = mInjector.elapsedRealtime();
560         final List<UserHandle> linkedProfiles = getCrossProfileTargets(packageName, userId);
561         synchronized (mAppIdleLock) {
562             reportNoninteractiveUsageCrossUserLocked(packageName, userId, STANDBY_BUCKET_ACTIVE,
563                     REASON_SUB_USAGE_EXEMPTED_SYNC_START, elapsedRealtime,
564                     mExemptedSyncStartTimeoutMillis, linkedProfiles);
565         }
566     }
567 
568     /**
569      * Helper method to report indirect user usage of an app and handle reporting the usage
570      * against cross profile connected apps. <br>
571      * Use {@link #reportNoninteractiveUsageLocked(String, int, int, int, long, long)} if
572      * cross profile connected apps do not need to be handled.
573      */
reportNoninteractiveUsageCrossUserLocked(String packageName, int userId, int bucket, int subReason, long elapsedRealtime, long nextCheckDelay, List<UserHandle> otherProfiles)574     private void reportNoninteractiveUsageCrossUserLocked(String packageName, int userId,
575             int bucket, int subReason, long elapsedRealtime, long nextCheckDelay,
576             List<UserHandle> otherProfiles) {
577         reportNoninteractiveUsageLocked(packageName, userId, bucket, subReason, elapsedRealtime,
578                 nextCheckDelay);
579         final int size = otherProfiles.size();
580         for (int profileIndex = 0; profileIndex < size; profileIndex++) {
581             final int otherUserId = otherProfiles.get(profileIndex).getIdentifier();
582             reportNoninteractiveUsageLocked(packageName, otherUserId, bucket, subReason,
583                     elapsedRealtime, nextCheckDelay);
584         }
585     }
586 
587     /**
588      * Helper method to report indirect user usage of an app. <br>
589      * Use
590      * {@link #reportNoninteractiveUsageCrossUserLocked(String, int, int, int, long, long, List)}
591      * if cross profile connected apps need to be handled.
592      */
reportNoninteractiveUsageLocked(String packageName, int userId, int bucket, int subReason, long elapsedRealtime, long nextCheckDelay)593     private void reportNoninteractiveUsageLocked(String packageName, int userId, int bucket,
594             int subReason, long elapsedRealtime, long nextCheckDelay) {
595         final AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId, bucket,
596                 subReason, 0, elapsedRealtime + nextCheckDelay);
597         mHandler.sendMessageDelayed(
598                 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, packageName),
599                 nextCheckDelay);
600         maybeInformListeners(packageName, userId, elapsedRealtime, appUsage.currentBucket,
601                 appUsage.bucketingReason, false);
602     }
603 
604     @VisibleForTesting
setChargingState(boolean isCharging)605     void setChargingState(boolean isCharging) {
606         synchronized (mAppIdleLock) {
607             if (mIsCharging != isCharging) {
608                 if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging);
609                 mIsCharging = isCharging;
610                 postParoleStateChanged();
611             }
612         }
613     }
614 
615     @Override
isInParole()616     public boolean isInParole() {
617         return !mAppIdleEnabled || mIsCharging;
618     }
619 
postParoleStateChanged()620     private void postParoleStateChanged() {
621         if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED");
622         mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED);
623         mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED);
624     }
625 
626     @Override
postCheckIdleStates(int userId)627     public void postCheckIdleStates(int userId) {
628         mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
629     }
630 
631     @Override
postOneTimeCheckIdleStates()632     public void postOneTimeCheckIdleStates() {
633         if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) {
634             // Not booted yet; wait for it!
635             mPendingOneTimeCheckIdleStates = true;
636         } else {
637             mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
638             mPendingOneTimeCheckIdleStates = false;
639         }
640     }
641 
642     @VisibleForTesting
checkIdleStates(int checkUserId)643     boolean checkIdleStates(int checkUserId) {
644         if (!mAppIdleEnabled) {
645             return false;
646         }
647 
648         final int[] runningUserIds;
649         try {
650             runningUserIds = mInjector.getRunningUserIds();
651             if (checkUserId != UserHandle.USER_ALL
652                     && !ArrayUtils.contains(runningUserIds, checkUserId)) {
653                 return false;
654             }
655         } catch (RemoteException re) {
656             throw re.rethrowFromSystemServer();
657         }
658 
659         final long elapsedRealtime = mInjector.elapsedRealtime();
660         for (int i = 0; i < runningUserIds.length; i++) {
661             final int userId = runningUserIds[i];
662             if (checkUserId != UserHandle.USER_ALL && checkUserId != userId) {
663                 continue;
664             }
665             if (DEBUG) {
666                 Slog.d(TAG, "Checking idle state for user " + userId);
667             }
668             List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
669                     PackageManager.MATCH_DISABLED_COMPONENTS,
670                     userId);
671             final int packageCount = packages.size();
672             for (int p = 0; p < packageCount; p++) {
673                 final PackageInfo pi = packages.get(p);
674                 final String packageName = pi.packageName;
675                 checkAndUpdateStandbyState(packageName, userId, pi.applicationInfo.uid,
676                         elapsedRealtime);
677             }
678         }
679         if (DEBUG) {
680             Slog.d(TAG, "checkIdleStates took "
681                     + (mInjector.elapsedRealtime() - elapsedRealtime));
682         }
683         return true;
684     }
685 
686     /** Check if we need to update the standby state of a specific app. */
checkAndUpdateStandbyState(String packageName, @UserIdInt int userId, int uid, long elapsedRealtime)687     private void checkAndUpdateStandbyState(String packageName, @UserIdInt int userId,
688             int uid, long elapsedRealtime) {
689         if (uid <= 0) {
690             try {
691                 uid = mPackageManager.getPackageUidAsUser(packageName, userId);
692             } catch (PackageManager.NameNotFoundException e) {
693                 // Not a valid package for this user, nothing to do
694                 // TODO: Remove any history of removed packages
695                 return;
696             }
697         }
698         final int minBucket = getAppMinBucket(packageName,
699                 UserHandle.getAppId(uid),
700                 userId);
701         if (DEBUG) {
702             Slog.d(TAG, "   Checking idle state for " + packageName
703                     + " minBucket=" + minBucket);
704         }
705         if (minBucket <= STANDBY_BUCKET_ACTIVE) {
706             // No extra processing needed for ACTIVE or higher since apps can't drop into lower
707             // buckets.
708             synchronized (mAppIdleLock) {
709                 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
710                         minBucket, REASON_MAIN_DEFAULT);
711             }
712             maybeInformListeners(packageName, userId, elapsedRealtime,
713                     minBucket, REASON_MAIN_DEFAULT, false);
714         } else {
715             synchronized (mAppIdleLock) {
716                 final AppIdleHistory.AppUsageHistory app =
717                         mAppIdleHistory.getAppUsageHistory(packageName,
718                         userId, elapsedRealtime);
719                 int reason = app.bucketingReason;
720                 final int oldMainReason = reason & REASON_MAIN_MASK;
721 
722                 // If the bucket was forced by the user/developer, leave it alone.
723                 // A usage event will be the only way to bring it out of this forced state
724                 if (oldMainReason == REASON_MAIN_FORCED_BY_USER) {
725                     return;
726                 }
727                 final int oldBucket = app.currentBucket;
728                 if (oldBucket == STANDBY_BUCKET_NEVER) {
729                     // None of this should bring an app out of the NEVER bucket.
730                     return;
731                 }
732                 int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
733                 boolean predictionLate = predictionTimedOut(app, elapsedRealtime);
734                 // Compute age-based bucket
735                 if (oldMainReason == REASON_MAIN_DEFAULT
736                         || oldMainReason == REASON_MAIN_USAGE
737                         || oldMainReason == REASON_MAIN_TIMEOUT
738                         || predictionLate) {
739 
740                     if (!predictionLate && app.lastPredictedBucket >= STANDBY_BUCKET_ACTIVE
741                             && app.lastPredictedBucket <= STANDBY_BUCKET_RARE) {
742                         newBucket = app.lastPredictedBucket;
743                         reason = REASON_MAIN_PREDICTED | REASON_SUB_PREDICTED_RESTORED;
744                         if (DEBUG) {
745                             Slog.d(TAG, "Restored predicted newBucket = " + newBucket);
746                         }
747                     } else {
748                         newBucket = getBucketForLocked(packageName, userId,
749                                 elapsedRealtime);
750                         if (DEBUG) {
751                             Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket);
752                         }
753                         reason = REASON_MAIN_TIMEOUT;
754                     }
755                 }
756 
757                 // Check if the app is within one of the timeouts for forced bucket elevation
758                 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
759                 if (newBucket >= STANDBY_BUCKET_ACTIVE
760                         && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
761                     newBucket = STANDBY_BUCKET_ACTIVE;
762                     reason = app.bucketingReason;
763                     if (DEBUG) {
764                         Slog.d(TAG, "    Keeping at ACTIVE due to min timeout");
765                     }
766                 } else if (newBucket >= STANDBY_BUCKET_WORKING_SET
767                         && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
768                     newBucket = STANDBY_BUCKET_WORKING_SET;
769                     // If it was already there, keep the reason, else assume timeout to WS
770                     reason = (newBucket == oldBucket)
771                             ? app.bucketingReason
772                             : REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT;
773                     if (DEBUG) {
774                         Slog.d(TAG, "    Keeping at WORKING_SET due to min timeout");
775                     }
776                 }
777 
778                 if (app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime
779                         && elapsedTimeAdjusted - app.lastUsedByUserElapsedTime
780                         >= mInjector.getAutoRestrictedBucketDelayMs()) {
781                     newBucket = STANDBY_BUCKET_RESTRICTED;
782                     reason = app.lastRestrictReason;
783                     if (DEBUG) {
784                         Slog.d(TAG, "Bringing down to RESTRICTED due to timeout");
785                     }
786                 }
787                 if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) {
788                     newBucket = STANDBY_BUCKET_RARE;
789                     // Leave the reason alone.
790                     if (DEBUG) {
791                         Slog.d(TAG, "Bringing up from RESTRICTED to RARE due to off switch");
792                     }
793                 }
794                 if (newBucket > minBucket) {
795                     newBucket = minBucket;
796                     // Leave the reason alone.
797                     if (DEBUG) {
798                         Slog.d(TAG, "Bringing up from " + newBucket + " to " + minBucket
799                                 + " due to min bucketing");
800                     }
801                 }
802                 if (DEBUG) {
803                     Slog.d(TAG, "     Old bucket=" + oldBucket
804                             + ", newBucket=" + newBucket);
805                 }
806                 if (oldBucket != newBucket || predictionLate) {
807                     mAppIdleHistory.setAppStandbyBucket(packageName, userId,
808                             elapsedRealtime, newBucket, reason);
809                     maybeInformListeners(packageName, userId, elapsedRealtime,
810                             newBucket, reason, false);
811                 }
812             }
813         }
814     }
815 
816     /** Returns true if there hasn't been a prediction for the app in a while. */
predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime)817     private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
818         return app.lastPredictedTime > 0
819                 && mAppIdleHistory.getElapsedTime(elapsedRealtime)
820                     - app.lastPredictedTime > mPredictionTimeoutMillis;
821     }
822 
823     /** 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)824     private void maybeInformListeners(String packageName, int userId,
825             long elapsedRealtime, int bucket, int reason, boolean userStartedInteracting) {
826         synchronized (mAppIdleLock) {
827             if (mAppIdleHistory.shouldInformListeners(packageName, userId,
828                     elapsedRealtime, bucket)) {
829                 final StandbyUpdateRecord r = StandbyUpdateRecord.obtain(packageName, userId,
830                         bucket, reason, userStartedInteracting);
831                 if (DEBUG) Slog.d(TAG, "Standby bucket for " + packageName + "=" + bucket);
832                 mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, r));
833             }
834         }
835     }
836 
837     /**
838      * Evaluates next bucket based on time since last used and the bucketing thresholds.
839      * @param packageName the app
840      * @param userId the user
841      * @param elapsedRealtime as the name suggests, current elapsed time
842      * @return the bucket for the app, based on time since last used
843      */
844     @GuardedBy("mAppIdleLock")
845     @StandbyBuckets
getBucketForLocked(String packageName, int userId, long elapsedRealtime)846     private int getBucketForLocked(String packageName, int userId,
847             long elapsedRealtime) {
848         int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId,
849                 elapsedRealtime, mAppStandbyScreenThresholds, mAppStandbyElapsedThresholds);
850         return THRESHOLD_BUCKETS[bucketIndex];
851     }
852 
notifyBatteryStats(String packageName, int userId, boolean idle)853     private void notifyBatteryStats(String packageName, int userId, boolean idle) {
854         try {
855             final int uid = mPackageManager.getPackageUidAsUser(packageName,
856                     PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
857             if (idle) {
858                 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
859                         packageName, uid);
860             } else {
861                 mInjector.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE,
862                         packageName, uid);
863             }
864         } catch (PackageManager.NameNotFoundException | RemoteException e) {
865         }
866     }
867 
868     @Override
reportEvent(UsageEvents.Event event, int userId)869     public void reportEvent(UsageEvents.Event event, int userId) {
870         if (!mAppIdleEnabled) return;
871         final int eventType = event.getEventType();
872         if ((eventType == UsageEvents.Event.ACTIVITY_RESUMED
873                 || eventType == UsageEvents.Event.ACTIVITY_PAUSED
874                 || eventType == UsageEvents.Event.SYSTEM_INTERACTION
875                 || eventType == UsageEvents.Event.USER_INTERACTION
876                 || eventType == UsageEvents.Event.NOTIFICATION_SEEN
877                 || eventType == UsageEvents.Event.SLICE_PINNED
878                 || eventType == UsageEvents.Event.SLICE_PINNED_PRIV
879                 || eventType == UsageEvents.Event.FOREGROUND_SERVICE_START)) {
880             final String pkg = event.getPackageName();
881             final List<UserHandle> linkedProfiles = getCrossProfileTargets(pkg, userId);
882             synchronized (mAppIdleLock) {
883                 final long elapsedRealtime = mInjector.elapsedRealtime();
884                 reportEventLocked(pkg, eventType, elapsedRealtime, userId);
885 
886                 final int size = linkedProfiles.size();
887                 for (int profileIndex = 0; profileIndex < size; profileIndex++) {
888                     final int linkedUserId = linkedProfiles.get(profileIndex).getIdentifier();
889                     reportEventLocked(pkg, eventType, elapsedRealtime, linkedUserId);
890                 }
891             }
892         }
893     }
894 
reportEventLocked(String pkg, int eventType, long elapsedRealtime, int userId)895     private void reportEventLocked(String pkg, int eventType, long elapsedRealtime, int userId) {
896         // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
897         // about apps that are on some kind of whitelist anyway.
898         final boolean previouslyIdle = mAppIdleHistory.isIdle(
899                 pkg, userId, elapsedRealtime);
900 
901         final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory(
902                 pkg, userId, elapsedRealtime);
903         final int prevBucket = appHistory.currentBucket;
904         final int prevBucketReason = appHistory.bucketingReason;
905         final long nextCheckDelay;
906         final int subReason = usageEventToSubReason(eventType);
907         final int reason = REASON_MAIN_USAGE | subReason;
908         if (eventType == UsageEvents.Event.NOTIFICATION_SEEN
909                 || eventType == UsageEvents.Event.SLICE_PINNED) {
910             // Mild usage elevates to WORKING_SET but doesn't change usage time.
911             mAppIdleHistory.reportUsage(appHistory, pkg, userId,
912                     STANDBY_BUCKET_WORKING_SET, subReason,
913                     0, elapsedRealtime + mNotificationSeenTimeoutMillis);
914             nextCheckDelay = mNotificationSeenTimeoutMillis;
915         } else if (eventType == UsageEvents.Event.SYSTEM_INTERACTION) {
916             mAppIdleHistory.reportUsage(appHistory, pkg, userId,
917                     STANDBY_BUCKET_ACTIVE, subReason,
918                     0, elapsedRealtime + mSystemInteractionTimeoutMillis);
919             nextCheckDelay = mSystemInteractionTimeoutMillis;
920         } else if (eventType == UsageEvents.Event.FOREGROUND_SERVICE_START) {
921             // Only elevate bucket if this is the first usage of the app
922             if (prevBucket != STANDBY_BUCKET_NEVER) return;
923             mAppIdleHistory.reportUsage(appHistory, pkg, userId,
924                     STANDBY_BUCKET_ACTIVE, subReason,
925                     0, elapsedRealtime + mInitialForegroundServiceStartTimeoutMillis);
926             nextCheckDelay = mInitialForegroundServiceStartTimeoutMillis;
927         } else {
928             mAppIdleHistory.reportUsage(appHistory, pkg, userId,
929                     STANDBY_BUCKET_ACTIVE, subReason,
930                     elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
931             nextCheckDelay = mStrongUsageTimeoutMillis;
932         }
933         if (appHistory.currentBucket != prevBucket) {
934             mHandler.sendMessageDelayed(
935                     mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkg),
936                     nextCheckDelay);
937             final boolean userStartedInteracting =
938                     appHistory.currentBucket == STANDBY_BUCKET_ACTIVE
939                             && (prevBucketReason & REASON_MAIN_MASK) != REASON_MAIN_USAGE;
940             maybeInformListeners(pkg, userId, elapsedRealtime,
941                     appHistory.currentBucket, reason, userStartedInteracting);
942         }
943 
944         if (previouslyIdle) {
945             notifyBatteryStats(pkg, userId, false);
946         }
947     }
948 
949     /**
950      * Note: don't call this with the lock held since it makes calls to other system services.
951      */
getCrossProfileTargets(String pkg, int userId)952     private @NonNull List<UserHandle> getCrossProfileTargets(String pkg, int userId) {
953         synchronized (mAppIdleLock) {
954             if (!mLinkCrossProfileApps) return Collections.emptyList();
955         }
956         return mInjector.getValidCrossProfileTargets(pkg, userId);
957     }
958 
usageEventToSubReason(int eventType)959     private int usageEventToSubReason(int eventType) {
960         switch (eventType) {
961             case UsageEvents.Event.ACTIVITY_RESUMED: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
962             case UsageEvents.Event.ACTIVITY_PAUSED: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
963             case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION;
964             case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION;
965             case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN;
966             case UsageEvents.Event.SLICE_PINNED: return REASON_SUB_USAGE_SLICE_PINNED;
967             case UsageEvents.Event.SLICE_PINNED_PRIV: return REASON_SUB_USAGE_SLICE_PINNED_PRIV;
968             case UsageEvents.Event.FOREGROUND_SERVICE_START:
969                 return REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
970             default: return 0;
971         }
972     }
973 
974     @VisibleForTesting
forceIdleState(String packageName, int userId, boolean idle)975     void forceIdleState(String packageName, int userId, boolean idle) {
976         if (!mAppIdleEnabled) return;
977 
978         final int appId = getAppId(packageName);
979         if (appId < 0) return;
980         final long elapsedRealtime = mInjector.elapsedRealtime();
981 
982         final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
983                 userId, elapsedRealtime);
984         final int standbyBucket;
985         synchronized (mAppIdleLock) {
986             standbyBucket = mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime);
987         }
988         final boolean stillIdle = isAppIdleFiltered(packageName, appId,
989                 userId, elapsedRealtime);
990         // Inform listeners if necessary
991         if (previouslyIdle != stillIdle) {
992             maybeInformListeners(packageName, userId, elapsedRealtime, standbyBucket,
993                     REASON_MAIN_FORCED_BY_USER, false);
994             if (!stillIdle) {
995                 notifyBatteryStats(packageName, userId, idle);
996             }
997         }
998     }
999 
1000     @Override
setLastJobRunTime(String packageName, int userId, long elapsedRealtime)1001     public void setLastJobRunTime(String packageName, int userId, long elapsedRealtime) {
1002         synchronized (mAppIdleLock) {
1003             mAppIdleHistory.setLastJobRunTime(packageName, userId, elapsedRealtime);
1004         }
1005     }
1006 
1007     @Override
getTimeSinceLastJobRun(String packageName, int userId)1008     public long getTimeSinceLastJobRun(String packageName, int userId) {
1009         final long elapsedRealtime = mInjector.elapsedRealtime();
1010         synchronized (mAppIdleLock) {
1011             return mAppIdleHistory.getTimeSinceLastJobRun(packageName, userId, elapsedRealtime);
1012         }
1013     }
1014 
1015     @Override
onUserRemoved(int userId)1016     public void onUserRemoved(int userId) {
1017         synchronized (mAppIdleLock) {
1018             mAppIdleHistory.onUserRemoved(userId);
1019             synchronized (mActiveAdminApps) {
1020                 mActiveAdminApps.remove(userId);
1021             }
1022         }
1023     }
1024 
isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime)1025     private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) {
1026         synchronized (mAppIdleLock) {
1027             return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
1028         }
1029     }
1030 
1031     @Override
addListener(AppIdleStateChangeListener listener)1032     public void addListener(AppIdleStateChangeListener listener) {
1033         synchronized (mPackageAccessListeners) {
1034             if (!mPackageAccessListeners.contains(listener)) {
1035                 mPackageAccessListeners.add(listener);
1036             }
1037         }
1038     }
1039 
1040     @Override
removeListener(AppIdleStateChangeListener listener)1041     public void removeListener(AppIdleStateChangeListener listener) {
1042         synchronized (mPackageAccessListeners) {
1043             mPackageAccessListeners.remove(listener);
1044         }
1045     }
1046 
1047     @Override
getAppId(String packageName)1048     public int getAppId(String packageName) {
1049         try {
1050             ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName,
1051                     PackageManager.MATCH_ANY_USER
1052                             | PackageManager.MATCH_DISABLED_COMPONENTS);
1053             return ai.uid;
1054         } catch (PackageManager.NameNotFoundException re) {
1055             return -1;
1056         }
1057     }
1058 
1059     @Override
isAppIdleFiltered(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps)1060     public boolean isAppIdleFiltered(String packageName, int userId, long elapsedRealtime,
1061             boolean shouldObfuscateInstantApps) {
1062         if (shouldObfuscateInstantApps &&
1063                 mInjector.isPackageEphemeral(userId, packageName)) {
1064             return false;
1065         }
1066         return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
1067     }
1068 
1069     @StandbyBuckets
getAppMinBucket(String packageName, int userId)1070     private int getAppMinBucket(String packageName, int userId) {
1071         try {
1072             final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
1073             return getAppMinBucket(packageName, UserHandle.getAppId(uid), userId);
1074         } catch (PackageManager.NameNotFoundException e) {
1075             // Not a valid package for this user, nothing to do
1076             return STANDBY_BUCKET_NEVER;
1077         }
1078     }
1079 
1080     /**
1081      * Return the lowest bucket this app should ever enter.
1082      */
1083     @StandbyBuckets
getAppMinBucket(String packageName, int appId, int userId)1084     private int getAppMinBucket(String packageName, int appId, int userId) {
1085         if (packageName == null) return STANDBY_BUCKET_NEVER;
1086         // If not enabled at all, of course nobody is ever idle.
1087         if (!mAppIdleEnabled) {
1088             return STANDBY_BUCKET_EXEMPTED;
1089         }
1090         if (appId < Process.FIRST_APPLICATION_UID) {
1091             // System uids never go idle.
1092             return STANDBY_BUCKET_EXEMPTED;
1093         }
1094         if (packageName.equals("android")) {
1095             // Nor does the framework (which should be redundant with the above, but for MR1 we will
1096             // retain this for safety).
1097             return STANDBY_BUCKET_EXEMPTED;
1098         }
1099         if (mSystemServicesReady) {
1100             // We allow all whitelisted apps, including those that don't want to be whitelisted
1101             // for idle mode, because app idle (aka app standby) is really not as big an issue
1102             // for controlling who participates vs. doze mode.
1103             if (mInjector.isNonIdleWhitelisted(packageName)) {
1104                 return STANDBY_BUCKET_EXEMPTED;
1105             }
1106 
1107             if (isActiveDeviceAdmin(packageName, userId)) {
1108                 return STANDBY_BUCKET_EXEMPTED;
1109             }
1110 
1111             if (isActiveNetworkScorer(packageName)) {
1112                 return STANDBY_BUCKET_EXEMPTED;
1113             }
1114 
1115             if (mAppWidgetManager != null
1116                     && mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) {
1117                 return STANDBY_BUCKET_ACTIVE;
1118             }
1119 
1120             if (isDeviceProvisioningPackage(packageName)) {
1121                 return STANDBY_BUCKET_EXEMPTED;
1122             }
1123 
1124             if (mInjector.isWellbeingPackage(packageName)) {
1125                 return STANDBY_BUCKET_WORKING_SET;
1126             }
1127         }
1128 
1129         // Check this last, as it can be the most expensive check
1130         if (isCarrierApp(packageName)) {
1131             return STANDBY_BUCKET_EXEMPTED;
1132         }
1133 
1134         if (isHeadlessSystemApp(packageName)) {
1135             return STANDBY_BUCKET_ACTIVE;
1136         }
1137 
1138         return STANDBY_BUCKET_NEVER;
1139     }
1140 
isHeadlessSystemApp(String packageName)1141     private boolean isHeadlessSystemApp(String packageName) {
1142         synchronized (mHeadlessSystemApps) {
1143             return mHeadlessSystemApps.contains(packageName);
1144         }
1145     }
1146 
1147     @Override
isAppIdleFiltered(String packageName, int appId, int userId, long elapsedRealtime)1148     public boolean isAppIdleFiltered(String packageName, int appId, int userId,
1149             long elapsedRealtime) {
1150         if (getAppMinBucket(packageName, appId, userId) < AppIdleHistory.IDLE_BUCKET_CUTOFF) {
1151             return false;
1152         } else {
1153             synchronized (mAppIdleLock) {
1154                 if (!mAppIdleEnabled || mIsCharging) {
1155                     return false;
1156                 }
1157             }
1158             return isAppIdleUnfiltered(packageName, userId, elapsedRealtime);
1159         }
1160     }
1161 
isUserUsage(int reason)1162     static boolean isUserUsage(int reason) {
1163         if ((reason & REASON_MAIN_MASK) == REASON_MAIN_USAGE) {
1164             final int subReason = reason & REASON_SUB_MASK;
1165             return subReason == REASON_SUB_USAGE_USER_INTERACTION
1166                     || subReason == REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
1167         }
1168         return false;
1169     }
1170 
1171     @Override
getIdleUidsForUser(int userId)1172     public int[] getIdleUidsForUser(int userId) {
1173         if (!mAppIdleEnabled) {
1174             return new int[0];
1175         }
1176 
1177         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "getIdleUidsForUser");
1178 
1179         final long elapsedRealtime = mInjector.elapsedRealtime();
1180 
1181         List<ApplicationInfo> apps;
1182         try {
1183             ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager()
1184                     .getInstalledApplications(/* flags= */ 0, userId);
1185             if (slice == null) {
1186                 return new int[0];
1187             }
1188             apps = slice.getList();
1189         } catch (RemoteException e) {
1190             throw e.rethrowFromSystemServer();
1191         }
1192 
1193         // State of each uid.  Key is the uid.  Value lower 16 bits is the number of apps
1194         // associated with that uid, upper 16 bits is the number of those apps that is idle.
1195         SparseIntArray uidStates = new SparseIntArray();
1196 
1197         // Now resolve all app state.  Iterating over all apps, keeping track of how many
1198         // we find for each uid and how many of those are idle.
1199         for (int i = apps.size() - 1; i >= 0; i--) {
1200             ApplicationInfo ai = apps.get(i);
1201 
1202             // Check whether this app is idle.
1203             boolean idle = isAppIdleFiltered(ai.packageName, UserHandle.getAppId(ai.uid),
1204                     userId, elapsedRealtime);
1205 
1206             int index = uidStates.indexOfKey(ai.uid);
1207             if (index < 0) {
1208                 uidStates.put(ai.uid, 1 + (idle ? 1<<16 : 0));
1209             } else {
1210                 int value = uidStates.valueAt(index);
1211                 uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0));
1212             }
1213         }
1214 
1215         if (DEBUG) {
1216             Slog.d(TAG, "getIdleUids took " + (mInjector.elapsedRealtime() - elapsedRealtime));
1217         }
1218         int numIdle = 0;
1219         for (int i = uidStates.size() - 1; i >= 0; i--) {
1220             int value = uidStates.valueAt(i);
1221             if ((value&0x7fff) == (value>>16)) {
1222                 numIdle++;
1223             }
1224         }
1225 
1226         int[] res = new int[numIdle];
1227         numIdle = 0;
1228         for (int i = uidStates.size() - 1; i >= 0; i--) {
1229             int value = uidStates.valueAt(i);
1230             if ((value&0x7fff) == (value>>16)) {
1231                 res[numIdle] = uidStates.keyAt(i);
1232                 numIdle++;
1233             }
1234         }
1235 
1236         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1237 
1238         return res;
1239     }
1240 
1241     @Override
setAppIdleAsync(String packageName, boolean idle, int userId)1242     public void setAppIdleAsync(String packageName, boolean idle, int userId) {
1243         if (packageName == null || !mAppIdleEnabled) return;
1244 
1245         mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
1246                 .sendToTarget();
1247     }
1248 
1249     @Override
getAppStandbyBucket(String packageName, int userId, long elapsedRealtime, boolean shouldObfuscateInstantApps)1250     @StandbyBuckets public int getAppStandbyBucket(String packageName, int userId,
1251             long elapsedRealtime, boolean shouldObfuscateInstantApps) {
1252         if (!mAppIdleEnabled || (shouldObfuscateInstantApps
1253                 && mInjector.isPackageEphemeral(userId, packageName))) {
1254             return STANDBY_BUCKET_ACTIVE;
1255         }
1256 
1257         synchronized (mAppIdleLock) {
1258             return mAppIdleHistory.getAppStandbyBucket(packageName, userId, elapsedRealtime);
1259         }
1260     }
1261 
1262     @VisibleForTesting
getAppStandbyBucketReason(String packageName, int userId, long elapsedRealtime)1263     int getAppStandbyBucketReason(String packageName, int userId, long elapsedRealtime) {
1264         synchronized (mAppIdleLock) {
1265             return mAppIdleHistory.getAppStandbyReason(packageName, userId, elapsedRealtime);
1266         }
1267     }
1268 
1269     @Override
getAppStandbyBuckets(int userId)1270     public List<AppStandbyInfo> getAppStandbyBuckets(int userId) {
1271         synchronized (mAppIdleLock) {
1272             return mAppIdleHistory.getAppStandbyBuckets(userId, mAppIdleEnabled);
1273         }
1274     }
1275 
1276     @Override
restrictApp(@onNull String packageName, int userId, @SystemForcedReasons int restrictReason)1277     public void restrictApp(@NonNull String packageName, int userId,
1278             @SystemForcedReasons int restrictReason) {
1279         // If the package is not installed, don't allow the bucket to be set.
1280         if (!mInjector.isPackageInstalled(packageName, 0, userId)) {
1281             Slog.e(TAG, "Tried to restrict uninstalled app: " + packageName);
1282             return;
1283         }
1284 
1285         final int reason = REASON_MAIN_FORCED_BY_SYSTEM | (REASON_SUB_MASK & restrictReason);
1286         final long nowElapsed = mInjector.elapsedRealtime();
1287         final int bucket = mAllowRestrictedBucket ? STANDBY_BUCKET_RESTRICTED : STANDBY_BUCKET_RARE;
1288         setAppStandbyBucket(packageName, userId, bucket, reason, nowElapsed, false);
1289     }
1290 
1291     @Override
setAppStandbyBucket(@onNull String packageName, int bucket, int userId, int callingUid, int callingPid)1292     public void setAppStandbyBucket(@NonNull String packageName, int bucket, int userId,
1293             int callingUid, int callingPid) {
1294         setAppStandbyBuckets(
1295                 Collections.singletonList(new AppStandbyInfo(packageName, bucket)),
1296                 userId, callingUid, callingPid);
1297     }
1298 
1299     @Override
setAppStandbyBuckets(@onNull List<AppStandbyInfo> appBuckets, int userId, int callingUid, int callingPid)1300     public void setAppStandbyBuckets(@NonNull List<AppStandbyInfo> appBuckets, int userId,
1301             int callingUid, int callingPid) {
1302         userId = ActivityManager.handleIncomingUser(
1303                 callingPid, callingUid, userId, false, true, "setAppStandbyBucket", null);
1304         final boolean shellCaller = callingUid == Process.ROOT_UID
1305                 || callingUid == Process.SHELL_UID;
1306         final int reason;
1307         // The Settings app runs in the system UID but in a separate process. Assume
1308         // things coming from other processes are due to the user.
1309         if ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && callingPid != Process.myPid())
1310                 || shellCaller) {
1311             reason = REASON_MAIN_FORCED_BY_USER;
1312         } else if (UserHandle.isCore(callingUid)) {
1313             reason = REASON_MAIN_FORCED_BY_SYSTEM;
1314         } else {
1315             reason = REASON_MAIN_PREDICTED;
1316         }
1317         final int packageFlags = PackageManager.MATCH_ANY_USER
1318                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
1319                 | PackageManager.MATCH_DIRECT_BOOT_AWARE;
1320         final int numApps = appBuckets.size();
1321         final long elapsedRealtime = mInjector.elapsedRealtime();
1322         for (int i = 0; i < numApps; ++i) {
1323             final AppStandbyInfo bucketInfo = appBuckets.get(i);
1324             final String packageName = bucketInfo.mPackageName;
1325             final int bucket = bucketInfo.mStandbyBucket;
1326             if (bucket < STANDBY_BUCKET_ACTIVE || bucket > STANDBY_BUCKET_NEVER) {
1327                 throw new IllegalArgumentException("Cannot set the standby bucket to " + bucket);
1328             }
1329             final int packageUid = mInjector.getPackageManagerInternal()
1330                     .getPackageUid(packageName, packageFlags, userId);
1331             // Caller cannot set their own standby state
1332             if (packageUid == callingUid) {
1333                 throw new IllegalArgumentException("Cannot set your own standby bucket");
1334             }
1335             if (packageUid < 0) {
1336                 throw new IllegalArgumentException(
1337                         "Cannot set standby bucket for non existent package (" + packageName + ")");
1338             }
1339             setAppStandbyBucket(packageName, userId, bucket, reason, elapsedRealtime, shellCaller);
1340         }
1341     }
1342 
1343     @VisibleForTesting
setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason)1344     void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
1345             int reason) {
1346         setAppStandbyBucket(
1347                 packageName, userId, newBucket, reason, mInjector.elapsedRealtime(), false);
1348     }
1349 
setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime, boolean resetTimeout)1350     private void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
1351             int reason, long elapsedRealtime, boolean resetTimeout) {
1352         if (!mAppIdleEnabled) return;
1353 
1354         synchronized (mAppIdleLock) {
1355             // If the package is not installed, don't allow the bucket to be set.
1356             if (!mInjector.isPackageInstalled(packageName, 0, userId)) {
1357                 Slog.e(TAG, "Tried to set bucket of uninstalled app: " + packageName);
1358                 return;
1359             }
1360             if (newBucket == STANDBY_BUCKET_RESTRICTED && !mAllowRestrictedBucket) {
1361                 newBucket = STANDBY_BUCKET_RARE;
1362             }
1363             AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName,
1364                     userId, elapsedRealtime);
1365             boolean predicted = (reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED;
1366 
1367             // Don't allow changing bucket if higher than ACTIVE
1368             if (app.currentBucket < STANDBY_BUCKET_ACTIVE) return;
1369 
1370             // Don't allow prediction to change from/to NEVER.
1371             if ((app.currentBucket == STANDBY_BUCKET_NEVER || newBucket == STANDBY_BUCKET_NEVER)
1372                     && predicted) {
1373                 return;
1374             }
1375 
1376             final boolean wasForcedBySystem =
1377                     (app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM;
1378 
1379             // If the bucket was forced, don't allow prediction to override
1380             if (predicted
1381                     && ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER
1382                     || wasForcedBySystem)) {
1383                 return;
1384             }
1385 
1386             final boolean isForcedBySystem =
1387                     (reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_SYSTEM;
1388 
1389             if (app.currentBucket == newBucket && wasForcedBySystem && isForcedBySystem) {
1390                 mAppIdleHistory
1391                         .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason);
1392                 // Keep track of all restricting reasons
1393                 reason = REASON_MAIN_FORCED_BY_SYSTEM
1394                         | (app.bucketingReason & REASON_SUB_MASK)
1395                         | (reason & REASON_SUB_MASK);
1396                 mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime,
1397                         newBucket, reason, resetTimeout);
1398                 return;
1399             }
1400 
1401             final boolean isForcedByUser =
1402                     (reason & REASON_MAIN_MASK) == REASON_MAIN_FORCED_BY_USER;
1403 
1404             if (app.currentBucket == STANDBY_BUCKET_RESTRICTED) {
1405                 if ((app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_TIMEOUT) {
1406                     if (predicted && newBucket >= STANDBY_BUCKET_RARE) {
1407                         // Predicting into RARE or below means we don't expect the user to use the
1408                         // app anytime soon, so don't elevate it from RESTRICTED.
1409                         return;
1410                     }
1411                 } else if (!isUserUsage(reason) && !isForcedByUser) {
1412                     // If the current bucket is RESTRICTED, only user force or usage should bring
1413                     // it out, unless the app was put into the bucket due to timing out.
1414                     return;
1415                 }
1416             }
1417 
1418             if (newBucket == STANDBY_BUCKET_RESTRICTED) {
1419                 mAppIdleHistory
1420                         .noteRestrictionAttempt(packageName, userId, elapsedRealtime, reason);
1421 
1422                 if (isForcedByUser) {
1423                     // Only user force can bypass the delay restriction. If the user forced the
1424                     // app into the RESTRICTED bucket, then a toast confirming the action
1425                     // shouldn't be surprising.
1426                     if (Build.IS_DEBUGGABLE) {
1427                         Toast.makeText(mContext,
1428                                 // Since AppStandbyController sits low in the lock hierarchy,
1429                                 // make sure not to call out with the lock held.
1430                                 mHandler.getLooper(),
1431                                 mContext.getResources().getString(
1432                                         R.string.as_app_forced_to_restricted_bucket, packageName),
1433                                 Toast.LENGTH_SHORT)
1434                                 .show();
1435                     } else {
1436                         Slog.i(TAG, packageName + " restricted by user");
1437                     }
1438                 } else {
1439                     final long timeUntilRestrictPossibleMs = app.lastUsedByUserElapsedTime
1440                             + mInjector.getAutoRestrictedBucketDelayMs() - elapsedRealtime;
1441                     if (timeUntilRestrictPossibleMs > 0) {
1442                         Slog.w(TAG, "Tried to restrict recently used app: " + packageName
1443                                 + " due to " + reason);
1444                         mHandler.sendMessageDelayed(
1445                                 mHandler.obtainMessage(
1446                                         MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, packageName),
1447                                 timeUntilRestrictPossibleMs);
1448                         return;
1449                     }
1450                 }
1451             }
1452 
1453             // If the bucket is required to stay in a higher state for a specified duration, don't
1454             // override unless the duration has passed
1455             if (predicted) {
1456                 // Check if the app is within one of the timeouts for forced bucket elevation
1457                 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
1458                 // In case of not using the prediction, just keep track of it for applying after
1459                 // ACTIVE or WORKING_SET timeout.
1460                 mAppIdleHistory.updateLastPrediction(app, elapsedTimeAdjusted, newBucket);
1461 
1462                 if (newBucket > STANDBY_BUCKET_ACTIVE
1463                         && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
1464                     newBucket = STANDBY_BUCKET_ACTIVE;
1465                     reason = app.bucketingReason;
1466                     if (DEBUG) {
1467                         Slog.d(TAG, "    Keeping at ACTIVE due to min timeout");
1468                     }
1469                 } else if (newBucket > STANDBY_BUCKET_WORKING_SET
1470                         && app.bucketWorkingSetTimeoutTime > elapsedTimeAdjusted) {
1471                     newBucket = STANDBY_BUCKET_WORKING_SET;
1472                     if (app.currentBucket != newBucket) {
1473                         reason = REASON_MAIN_USAGE | REASON_SUB_USAGE_ACTIVE_TIMEOUT;
1474                     } else {
1475                         reason = app.bucketingReason;
1476                     }
1477                     if (DEBUG) {
1478                         Slog.d(TAG, "    Keeping at WORKING_SET due to min timeout");
1479                     }
1480                 } else if (newBucket == STANDBY_BUCKET_RARE
1481                         && mAllowRestrictedBucket
1482                         && getBucketForLocked(packageName, userId, elapsedRealtime)
1483                         == STANDBY_BUCKET_RESTRICTED) {
1484                     // Prediction doesn't think the app will be used anytime soon and
1485                     // it's been long enough that it could just time out into restricted,
1486                     // so time it out there instead. Using TIMEOUT will allow prediction
1487                     // to raise the bucket when it needs to.
1488                     newBucket = STANDBY_BUCKET_RESTRICTED;
1489                     reason = REASON_MAIN_TIMEOUT;
1490                     if (DEBUG) {
1491                         Slog.d(TAG,
1492                                 "Prediction to RARE overridden by timeout into RESTRICTED");
1493                     }
1494                 }
1495             }
1496 
1497             // Make sure we don't put the app in a lower bucket than it's supposed to be in.
1498             newBucket = Math.min(newBucket, getAppMinBucket(packageName, userId));
1499             mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
1500                     reason, resetTimeout);
1501         }
1502         maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, reason, false);
1503     }
1504 
1505     @VisibleForTesting
isActiveDeviceAdmin(String packageName, int userId)1506     boolean isActiveDeviceAdmin(String packageName, int userId) {
1507         synchronized (mActiveAdminApps) {
1508             final Set<String> adminPkgs = mActiveAdminApps.get(userId);
1509             return adminPkgs != null && adminPkgs.contains(packageName);
1510         }
1511     }
1512 
1513     @Override
addActiveDeviceAdmin(String adminPkg, int userId)1514     public void addActiveDeviceAdmin(String adminPkg, int userId) {
1515         synchronized (mActiveAdminApps) {
1516             Set<String> adminPkgs = mActiveAdminApps.get(userId);
1517             if (adminPkgs == null) {
1518                 adminPkgs = new ArraySet<>();
1519                 mActiveAdminApps.put(userId, adminPkgs);
1520             }
1521             adminPkgs.add(adminPkg);
1522         }
1523     }
1524 
1525     @Override
setActiveAdminApps(Set<String> adminPkgs, int userId)1526     public void setActiveAdminApps(Set<String> adminPkgs, int userId) {
1527         synchronized (mActiveAdminApps) {
1528             if (adminPkgs == null) {
1529                 mActiveAdminApps.remove(userId);
1530             } else {
1531                 mActiveAdminApps.put(userId, adminPkgs);
1532             }
1533         }
1534     }
1535 
1536     @Override
onAdminDataAvailable()1537     public void onAdminDataAvailable() {
1538         mAdminDataAvailableLatch.countDown();
1539     }
1540 
1541     /**
1542      * This will only ever be called once - during device boot.
1543      */
waitForAdminData()1544     private void waitForAdminData() {
1545         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
1546             ConcurrentUtils.waitForCountDownNoInterrupt(mAdminDataAvailableLatch,
1547                     WAIT_FOR_ADMIN_DATA_TIMEOUT_MS, "Wait for admin data");
1548         }
1549     }
1550 
1551     @VisibleForTesting
getActiveAdminAppsForTest(int userId)1552     Set<String> getActiveAdminAppsForTest(int userId) {
1553         synchronized (mActiveAdminApps) {
1554             return mActiveAdminApps.get(userId);
1555         }
1556     }
1557 
1558     /**
1559      * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
1560      * returns {@code false}.
1561      */
isDeviceProvisioningPackage(String packageName)1562     private boolean isDeviceProvisioningPackage(String packageName) {
1563         String deviceProvisioningPackage = mContext.getResources().getString(
1564                 com.android.internal.R.string.config_deviceProvisioningPackage);
1565         return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
1566     }
1567 
isCarrierApp(String packageName)1568     private boolean isCarrierApp(String packageName) {
1569         synchronized (mAppIdleLock) {
1570             if (!mHaveCarrierPrivilegedApps) {
1571                 fetchCarrierPrivilegedAppsLocked();
1572             }
1573             if (mCarrierPrivilegedApps != null) {
1574                 return mCarrierPrivilegedApps.contains(packageName);
1575             }
1576             return false;
1577         }
1578     }
1579 
1580     @Override
clearCarrierPrivilegedApps()1581     public void clearCarrierPrivilegedApps() {
1582         if (DEBUG) {
1583             Slog.i(TAG, "Clearing carrier privileged apps list");
1584         }
1585         synchronized (mAppIdleLock) {
1586             mHaveCarrierPrivilegedApps = false;
1587             mCarrierPrivilegedApps = null; // Need to be refetched.
1588         }
1589     }
1590 
1591     @GuardedBy("mAppIdleLock")
fetchCarrierPrivilegedAppsLocked()1592     private void fetchCarrierPrivilegedAppsLocked() {
1593         TelephonyManager telephonyManager =
1594                 mContext.getSystemService(TelephonyManager.class);
1595         mCarrierPrivilegedApps =
1596                 telephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions();
1597         mHaveCarrierPrivilegedApps = true;
1598         if (DEBUG) {
1599             Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps);
1600         }
1601     }
1602 
isActiveNetworkScorer(String packageName)1603     private boolean isActiveNetworkScorer(String packageName) {
1604         // Validity of network scorer cache is limited to a few seconds. Fetch it again
1605         // if longer since query.
1606         // This is a temporary optimization until there's a callback mechanism for changes to network scorer.
1607         final long now = SystemClock.elapsedRealtime();
1608         if (mCachedNetworkScorer == null
1609                 || mCachedNetworkScorerAtMillis < now - NETWORK_SCORER_CACHE_DURATION_MILLIS) {
1610             mCachedNetworkScorer = mInjector.getActiveNetworkScorer();
1611             mCachedNetworkScorerAtMillis = now;
1612         }
1613         return packageName != null && packageName.equals(mCachedNetworkScorer);
1614     }
1615 
informListeners(String packageName, int userId, int bucket, int reason, boolean userInteraction)1616     private void informListeners(String packageName, int userId, int bucket, int reason,
1617             boolean userInteraction) {
1618         final boolean idle = bucket >= STANDBY_BUCKET_RARE;
1619         synchronized (mPackageAccessListeners) {
1620             for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
1621                 listener.onAppIdleStateChanged(packageName, userId, idle, bucket, reason);
1622                 if (userInteraction) {
1623                     listener.onUserInteractionStarted(packageName, userId);
1624                 }
1625             }
1626         }
1627     }
1628 
informParoleStateChanged()1629     private void informParoleStateChanged() {
1630         final boolean paroled = isInParole();
1631         synchronized (mPackageAccessListeners) {
1632             for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
1633                 listener.onParoleStateChanged(paroled);
1634             }
1635         }
1636     }
1637 
1638 
1639     @Override
flushToDisk()1640     public void flushToDisk() {
1641         synchronized (mAppIdleLock) {
1642             mAppIdleHistory.writeAppIdleTimes();
1643             mAppIdleHistory.writeAppIdleDurations();
1644         }
1645     }
1646 
isDisplayOn()1647     private boolean isDisplayOn() {
1648         return mInjector.isDefaultDisplayOn();
1649     }
1650 
1651     @VisibleForTesting
clearAppIdleForPackage(String packageName, int userId)1652     void clearAppIdleForPackage(String packageName, int userId) {
1653         synchronized (mAppIdleLock) {
1654             mAppIdleHistory.clearUsage(packageName, userId);
1655         }
1656     }
1657 
1658     /**
1659      * Remove an app from the {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED}
1660      * bucket if it was forced into the bucket by the system because it was buggy.
1661      */
1662     @VisibleForTesting
maybeUnrestrictBuggyApp(String packageName, int userId)1663     void maybeUnrestrictBuggyApp(String packageName, int userId) {
1664         synchronized (mAppIdleLock) {
1665             final long elapsedRealtime = mInjector.elapsedRealtime();
1666             final AppIdleHistory.AppUsageHistory app =
1667                     mAppIdleHistory.getAppUsageHistory(packageName, userId, elapsedRealtime);
1668             if (app.currentBucket != STANDBY_BUCKET_RESTRICTED
1669                     || (app.bucketingReason & REASON_MAIN_MASK) != REASON_MAIN_FORCED_BY_SYSTEM) {
1670                 return;
1671             }
1672 
1673             final int newBucket;
1674             final int newReason;
1675             if ((app.bucketingReason & REASON_SUB_MASK) == REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY) {
1676                 // If bugginess was the only reason the app should be restricted, then lift it out.
1677                 newBucket = STANDBY_BUCKET_RARE;
1678                 newReason = REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_APP_UPDATE;
1679             } else {
1680                 // There's another reason the app was restricted. Remove the buggy bit and call
1681                 // it a day.
1682                 newBucket = STANDBY_BUCKET_RESTRICTED;
1683                 newReason = app.bucketingReason & ~REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY;
1684             }
1685             mAppIdleHistory.setAppStandbyBucket(
1686                     packageName, userId, elapsedRealtime, newBucket, newReason);
1687         }
1688     }
1689 
updatePowerWhitelistCache()1690     private void updatePowerWhitelistCache() {
1691         if (mInjector.getBootPhase() < PHASE_SYSTEM_SERVICES_READY) {
1692             return;
1693         }
1694         mInjector.updatePowerWhitelistCache();
1695         postCheckIdleStates(UserHandle.USER_ALL);
1696     }
1697 
1698     private class PackageReceiver extends BroadcastReceiver {
1699         @Override
onReceive(Context context, Intent intent)1700         public void onReceive(Context context, Intent intent) {
1701             final String action = intent.getAction();
1702             final String pkgName = intent.getData().getSchemeSpecificPart();
1703             final int userId = getSendingUserId();
1704             if (Intent.ACTION_PACKAGE_ADDED.equals(action)
1705                     || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
1706                 clearCarrierPrivilegedApps();
1707                 // ACTION_PACKAGE_ADDED is called even for system app downgrades.
1708                 evaluateSystemAppException(pkgName, userId);
1709                 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE, userId, -1, pkgName)
1710                     .sendToTarget();
1711             }
1712             if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
1713                     Intent.ACTION_PACKAGE_ADDED.equals(action))) {
1714                 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1715                     maybeUnrestrictBuggyApp(pkgName, userId);
1716                 } else {
1717                     clearAppIdleForPackage(pkgName, userId);
1718                 }
1719             }
1720         }
1721     }
1722 
evaluateSystemAppException(String packageName, int userId)1723     private void evaluateSystemAppException(String packageName, int userId) {
1724         if (!mSystemServicesReady) {
1725             // The app will be evaluated in when services are ready.
1726             return;
1727         }
1728         try {
1729             PackageInfo pi = mPackageManager.getPackageInfoAsUser(
1730                     packageName, HEADLESS_APP_CHECK_FLAGS, userId);
1731             evaluateSystemAppException(pi);
1732         } catch (PackageManager.NameNotFoundException e) {
1733             synchronized (mHeadlessSystemApps) {
1734                 mHeadlessSystemApps.remove(packageName);
1735             }
1736         }
1737     }
1738 
1739     /** Returns true if the exception status changed. */
evaluateSystemAppException(@ullable PackageInfo pkgInfo)1740     private boolean evaluateSystemAppException(@Nullable PackageInfo pkgInfo) {
1741         if (pkgInfo == null || pkgInfo.applicationInfo == null
1742                 || (!pkgInfo.applicationInfo.isSystemApp()
1743                         && !pkgInfo.applicationInfo.isUpdatedSystemApp())) {
1744             return false;
1745         }
1746         synchronized (mHeadlessSystemApps) {
1747             if (pkgInfo.activities == null || pkgInfo.activities.length == 0) {
1748                 // Headless system app.
1749                 return mHeadlessSystemApps.add(pkgInfo.packageName);
1750             } else {
1751                 return mHeadlessSystemApps.remove(pkgInfo.packageName);
1752             }
1753         }
1754     }
1755 
1756     /** Call on a system version update to temporarily reset system app buckets. */
1757     @Override
initializeDefaultsForSystemApps(int userId)1758     public void initializeDefaultsForSystemApps(int userId) {
1759         if (!mSystemServicesReady) {
1760             // Do it later, since SettingsProvider wasn't queried yet for app_standby_enabled
1761             mPendingInitializeDefaults = true;
1762             return;
1763         }
1764         Slog.d(TAG, "Initializing defaults for system apps on user " + userId + ", "
1765                 + "appIdleEnabled=" + mAppIdleEnabled);
1766         final long elapsedRealtime = mInjector.elapsedRealtime();
1767         List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
1768                 PackageManager.MATCH_DISABLED_COMPONENTS,
1769                 userId);
1770         final int packageCount = packages.size();
1771         synchronized (mAppIdleLock) {
1772             for (int i = 0; i < packageCount; i++) {
1773                 final PackageInfo pi = packages.get(i);
1774                 String packageName = pi.packageName;
1775                 if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
1776                     // Mark app as used for 2 hours. After that it can timeout to whatever the
1777                     // past usage pattern was.
1778                     mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE,
1779                             REASON_SUB_USAGE_SYSTEM_UPDATE, 0,
1780                             elapsedRealtime + mSystemUpdateUsageTimeoutMillis);
1781                 }
1782             }
1783             // Immediately persist defaults to disk
1784             mAppIdleHistory.writeAppIdleTimes(userId);
1785         }
1786     }
1787 
1788     /** Call on system boot to get the initial set of headless system apps. */
loadHeadlessSystemAppCache()1789     private void loadHeadlessSystemAppCache() {
1790         Slog.d(TAG, "Loading headless system app cache. appIdleEnabled=" + mAppIdleEnabled);
1791         final List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
1792                 HEADLESS_APP_CHECK_FLAGS, UserHandle.USER_SYSTEM);
1793         final int packageCount = packages.size();
1794         for (int i = 0; i < packageCount; i++) {
1795             PackageInfo pkgInfo = packages.get(i);
1796             if (pkgInfo != null && evaluateSystemAppException(pkgInfo)) {
1797                 mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE,
1798                         UserHandle.USER_SYSTEM, -1, pkgInfo.packageName)
1799                     .sendToTarget();
1800             }
1801         }
1802     }
1803 
1804     @Override
postReportContentProviderUsage(String name, String packageName, int userId)1805     public void postReportContentProviderUsage(String name, String packageName, int userId) {
1806         SomeArgs args = SomeArgs.obtain();
1807         args.arg1 = name;
1808         args.arg2 = packageName;
1809         args.arg3 = userId;
1810         mHandler.obtainMessage(MSG_REPORT_CONTENT_PROVIDER_USAGE, args)
1811                 .sendToTarget();
1812     }
1813 
1814     @Override
postReportSyncScheduled(String packageName, int userId, boolean exempted)1815     public void postReportSyncScheduled(String packageName, int userId, boolean exempted) {
1816         mHandler.obtainMessage(MSG_REPORT_SYNC_SCHEDULED, userId, exempted ? 1 : 0, packageName)
1817                 .sendToTarget();
1818     }
1819 
1820     @Override
postReportExemptedSyncStart(String packageName, int userId)1821     public void postReportExemptedSyncStart(String packageName, int userId) {
1822         mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName)
1823                 .sendToTarget();
1824     }
1825 
1826     @Override
dumpUsers(IndentingPrintWriter idpw, int[] userIds, List<String> pkgs)1827     public void dumpUsers(IndentingPrintWriter idpw, int[] userIds, List<String> pkgs) {
1828         synchronized (mAppIdleLock) {
1829             mAppIdleHistory.dumpUsers(idpw, userIds, pkgs);
1830         }
1831     }
1832 
1833     @Override
dumpState(String[] args, PrintWriter pw)1834     public void dumpState(String[] args, PrintWriter pw) {
1835         synchronized (mAppIdleLock) {
1836             pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
1837                     + "): " + mCarrierPrivilegedApps);
1838         }
1839 
1840         pw.println();
1841         pw.println("Settings:");
1842 
1843         pw.print("  mCheckIdleIntervalMillis=");
1844         TimeUtils.formatDuration(mCheckIdleIntervalMillis, pw);
1845         pw.println();
1846 
1847         pw.print("  mStrongUsageTimeoutMillis=");
1848         TimeUtils.formatDuration(mStrongUsageTimeoutMillis, pw);
1849         pw.println();
1850         pw.print("  mNotificationSeenTimeoutMillis=");
1851         TimeUtils.formatDuration(mNotificationSeenTimeoutMillis, pw);
1852         pw.println();
1853         pw.print("  mSyncAdapterTimeoutMillis=");
1854         TimeUtils.formatDuration(mSyncAdapterTimeoutMillis, pw);
1855         pw.println();
1856         pw.print("  mSystemInteractionTimeoutMillis=");
1857         TimeUtils.formatDuration(mSystemInteractionTimeoutMillis, pw);
1858         pw.println();
1859         pw.print("  mInitialForegroundServiceStartTimeoutMillis=");
1860         TimeUtils.formatDuration(mInitialForegroundServiceStartTimeoutMillis, pw);
1861         pw.println();
1862 
1863         pw.print("  mPredictionTimeoutMillis=");
1864         TimeUtils.formatDuration(mPredictionTimeoutMillis, pw);
1865         pw.println();
1866 
1867         pw.print("  mExemptedSyncScheduledNonDozeTimeoutMillis=");
1868         TimeUtils.formatDuration(mExemptedSyncScheduledNonDozeTimeoutMillis, pw);
1869         pw.println();
1870         pw.print("  mExemptedSyncScheduledDozeTimeoutMillis=");
1871         TimeUtils.formatDuration(mExemptedSyncScheduledDozeTimeoutMillis, pw);
1872         pw.println();
1873         pw.print("  mExemptedSyncStartTimeoutMillis=");
1874         TimeUtils.formatDuration(mExemptedSyncStartTimeoutMillis, pw);
1875         pw.println();
1876         pw.print("  mUnexemptedSyncScheduledTimeoutMillis=");
1877         TimeUtils.formatDuration(mUnexemptedSyncScheduledTimeoutMillis, pw);
1878         pw.println();
1879 
1880         pw.print("  mSystemUpdateUsageTimeoutMillis=");
1881         TimeUtils.formatDuration(mSystemUpdateUsageTimeoutMillis, pw);
1882         pw.println();
1883 
1884         pw.println();
1885         pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
1886         pw.print(" mAllowRestrictedBucket=");
1887         pw.print(mAllowRestrictedBucket);
1888         pw.print(" mIsCharging=");
1889         pw.print(mIsCharging);
1890         pw.println();
1891         pw.print("mScreenThresholds="); pw.println(Arrays.toString(mAppStandbyScreenThresholds));
1892         pw.print("mElapsedThresholds="); pw.println(Arrays.toString(mAppStandbyElapsedThresholds));
1893         pw.println();
1894 
1895         pw.println("mHeadlessSystemApps=[");
1896         synchronized (mHeadlessSystemApps) {
1897             for (int i = mHeadlessSystemApps.size() - 1; i >= 0; --i) {
1898                 pw.print("  ");
1899                 pw.print(mHeadlessSystemApps.valueAt(i));
1900                 pw.println(",");
1901             }
1902         }
1903         pw.println("]");
1904         pw.println();
1905 
1906         mInjector.dump(pw);
1907     }
1908 
1909     /**
1910      * Injector for interaction with external code. Override methods to provide a mock
1911      * implementation for tests.
1912      * onBootPhase() must be called with at least the PHASE_SYSTEM_SERVICES_READY
1913      */
1914     static class Injector {
1915 
1916         private final Context mContext;
1917         private final Looper mLooper;
1918         private IBatteryStats mBatteryStats;
1919         private BatteryManager mBatteryManager;
1920         private PackageManagerInternal mPackageManagerInternal;
1921         private DisplayManager mDisplayManager;
1922         private PowerManager mPowerManager;
1923         private IDeviceIdleController mDeviceIdleController;
1924         private CrossProfileAppsInternal mCrossProfileAppsInternal;
1925         int mBootPhase;
1926         /**
1927          * The minimum amount of time required since the last user interaction before an app can be
1928          * automatically placed in the RESTRICTED bucket.
1929          */
1930         long mAutoRestrictedBucketDelayMs = ONE_DAY;
1931         /**
1932          * Cached set of apps that are power whitelisted, including those not whitelisted from idle.
1933          */
1934         @GuardedBy("mPowerWhitelistedApps")
1935         private final ArraySet<String> mPowerWhitelistedApps = new ArraySet<>();
1936         private String mWellbeingApp = null;
1937 
Injector(Context context, Looper looper)1938         Injector(Context context, Looper looper) {
1939             mContext = context;
1940             mLooper = looper;
1941         }
1942 
getContext()1943         Context getContext() {
1944             return mContext;
1945         }
1946 
getLooper()1947         Looper getLooper() {
1948             return mLooper;
1949         }
1950 
onBootPhase(int phase)1951         void onBootPhase(int phase) {
1952             if (phase == PHASE_SYSTEM_SERVICES_READY) {
1953                 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1954                         ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
1955                 mBatteryStats = IBatteryStats.Stub.asInterface(
1956                         ServiceManager.getService(BatteryStats.SERVICE_NAME));
1957                 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
1958                 mDisplayManager = (DisplayManager) mContext.getSystemService(
1959                         Context.DISPLAY_SERVICE);
1960                 mPowerManager = mContext.getSystemService(PowerManager.class);
1961                 mBatteryManager = mContext.getSystemService(BatteryManager.class);
1962                 mCrossProfileAppsInternal = LocalServices.getService(
1963                         CrossProfileAppsInternal.class);
1964 
1965                 final ActivityManager activityManager =
1966                         (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
1967                 if (activityManager.isLowRamDevice() || ActivityManager.isSmallBatteryDevice()) {
1968                     mAutoRestrictedBucketDelayMs = 12 * ONE_HOUR;
1969                 }
1970 
1971                 final PackageManager packageManager = mContext.getPackageManager();
1972                 mWellbeingApp = packageManager.getWellbeingPackageName();
1973             }
1974             mBootPhase = phase;
1975         }
1976 
getBootPhase()1977         int getBootPhase() {
1978             return mBootPhase;
1979         }
1980 
1981         /**
1982          * Returns the elapsed realtime since the device started. Override this
1983          * to control the clock.
1984          * @return elapsed realtime
1985          */
elapsedRealtime()1986         long elapsedRealtime() {
1987             return SystemClock.elapsedRealtime();
1988         }
1989 
currentTimeMillis()1990         long currentTimeMillis() {
1991             return System.currentTimeMillis();
1992         }
1993 
isAppIdleEnabled()1994         boolean isAppIdleEnabled() {
1995             final boolean buildFlag = mContext.getResources().getBoolean(
1996                     com.android.internal.R.bool.config_enableAutoPowerModes);
1997             final boolean runtimeFlag = Global.getInt(mContext.getContentResolver(),
1998                     Global.APP_STANDBY_ENABLED, 1) == 1
1999                     && Global.getInt(mContext.getContentResolver(),
2000                     Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 1) == 1;
2001             return buildFlag && runtimeFlag;
2002         }
2003 
isCharging()2004         boolean isCharging() {
2005             return mBatteryManager.isCharging();
2006         }
2007 
isNonIdleWhitelisted(String packageName)2008         boolean isNonIdleWhitelisted(String packageName) {
2009             if (mBootPhase < PHASE_SYSTEM_SERVICES_READY) {
2010                 return false;
2011             }
2012             synchronized (mPowerWhitelistedApps) {
2013                 return mPowerWhitelistedApps.contains(packageName);
2014             }
2015         }
2016 
2017         /**
2018          * Returns {@code true} if the supplied package is the wellbeing app. Otherwise,
2019          * returns {@code false}.
2020          */
isWellbeingPackage(String packageName)2021         boolean isWellbeingPackage(String packageName) {
2022             return mWellbeingApp != null && mWellbeingApp.equals(packageName);
2023         }
2024 
updatePowerWhitelistCache()2025         void updatePowerWhitelistCache() {
2026             try {
2027                 // Don't call out to DeviceIdleController with the lock held.
2028                 final String[] whitelistedPkgs =
2029                         mDeviceIdleController.getFullPowerWhitelistExceptIdle();
2030                 synchronized (mPowerWhitelistedApps) {
2031                     mPowerWhitelistedApps.clear();
2032                     final int len = whitelistedPkgs.length;
2033                     for (int i = 0; i < len; ++i) {
2034                         mPowerWhitelistedApps.add(whitelistedPkgs[i]);
2035                     }
2036                 }
2037             } catch (RemoteException e) {
2038                 // Should not happen.
2039                 Slog.wtf(TAG, "Failed to get power whitelist", e);
2040             }
2041         }
2042 
isRestrictedBucketEnabled()2043         boolean isRestrictedBucketEnabled() {
2044             return Global.getInt(mContext.getContentResolver(),
2045                     Global.ENABLE_RESTRICTED_BUCKET,
2046                     Global.DEFAULT_ENABLE_RESTRICTED_BUCKET) == 1;
2047         }
2048 
getDataSystemDirectory()2049         File getDataSystemDirectory() {
2050             return Environment.getDataSystemDirectory();
2051         }
2052 
2053         /**
2054          * Return the minimum amount of time that must have passed since the last user usage before
2055          * an app can be automatically put into the
2056          * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket.
2057          */
getAutoRestrictedBucketDelayMs()2058         long getAutoRestrictedBucketDelayMs() {
2059             return mAutoRestrictedBucketDelayMs;
2060         }
2061 
noteEvent(int event, String packageName, int uid)2062         void noteEvent(int event, String packageName, int uid) throws RemoteException {
2063             mBatteryStats.noteEvent(event, packageName, uid);
2064         }
2065 
getPackageManagerInternal()2066         PackageManagerInternal getPackageManagerInternal() {
2067             return mPackageManagerInternal;
2068         }
2069 
isPackageEphemeral(int userId, String packageName)2070         boolean isPackageEphemeral(int userId, String packageName) {
2071             return mPackageManagerInternal.isPackageEphemeral(userId, packageName);
2072         }
2073 
isPackageInstalled(String packageName, int flags, int userId)2074         boolean isPackageInstalled(String packageName, int flags, int userId) {
2075             return mPackageManagerInternal.getPackageUid(packageName, flags, userId) >= 0;
2076         }
2077 
getRunningUserIds()2078         int[] getRunningUserIds() throws RemoteException {
2079             return ActivityManager.getService().getRunningUserIds();
2080         }
2081 
isDefaultDisplayOn()2082         boolean isDefaultDisplayOn() {
2083             return mDisplayManager
2084                     .getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_ON;
2085         }
2086 
registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler)2087         void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) {
2088             mDisplayManager.registerDisplayListener(listener, handler);
2089         }
2090 
getActiveNetworkScorer()2091         String getActiveNetworkScorer() {
2092             NetworkScoreManager nsm = (NetworkScoreManager) mContext.getSystemService(
2093                     Context.NETWORK_SCORE_SERVICE);
2094             return nsm.getActiveScorerPackage();
2095         }
2096 
isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName, int userId)2097         public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName,
2098                 int userId) {
2099             return appWidgetManager.isBoundWidgetPackage(packageName, userId);
2100         }
2101 
getAppIdleSettings()2102         String getAppIdleSettings() {
2103             return Global.getString(mContext.getContentResolver(),
2104                     Global.APP_IDLE_CONSTANTS);
2105         }
2106 
2107         /** Whether the device is in doze or not. */
isDeviceIdleMode()2108         public boolean isDeviceIdleMode() {
2109             return mPowerManager.isDeviceIdleMode();
2110         }
2111 
getValidCrossProfileTargets(String pkg, int userId)2112         public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) {
2113             final int uid = mPackageManagerInternal.getPackageUidInternal(pkg, 0, userId);
2114             final AndroidPackage aPkg = mPackageManagerInternal.getPackage(uid);
2115             if (uid < 0
2116                     || aPkg == null
2117                     || !aPkg.isCrossProfile()
2118                     || !mCrossProfileAppsInternal
2119                             .verifyUidHasInteractAcrossProfilePermission(pkg, uid)) {
2120                 if (uid >= 0 && aPkg == null) {
2121                     Slog.wtf(TAG, "Null package retrieved for UID " + uid);
2122                 }
2123                 return Collections.emptyList();
2124             }
2125             return mCrossProfileAppsInternal.getTargetUserProfiles(pkg, userId);
2126         }
2127 
dump(PrintWriter pw)2128         void dump(PrintWriter pw) {
2129             pw.println("mPowerWhitelistedApps=[");
2130             synchronized (mPowerWhitelistedApps) {
2131                 for (int i = mPowerWhitelistedApps.size() - 1; i >= 0; --i) {
2132                     pw.print("  ");
2133                     pw.print(mPowerWhitelistedApps.valueAt(i));
2134                     pw.println(",");
2135                 }
2136             }
2137             pw.println("]");
2138             pw.println();
2139         }
2140     }
2141 
2142     class AppStandbyHandler extends Handler {
2143 
AppStandbyHandler(Looper looper)2144         AppStandbyHandler(Looper looper) {
2145             super(looper);
2146         }
2147 
2148         @Override
handleMessage(Message msg)2149         public void handleMessage(Message msg) {
2150             switch (msg.what) {
2151                 case MSG_INFORM_LISTENERS:
2152                     StandbyUpdateRecord r = (StandbyUpdateRecord) msg.obj;
2153                     informListeners(r.packageName, r.userId, r.bucket, r.reason,
2154                             r.isUserInteraction);
2155                     r.recycle();
2156                     break;
2157 
2158                 case MSG_FORCE_IDLE_STATE:
2159                     forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1);
2160                     break;
2161 
2162                 case MSG_CHECK_IDLE_STATES:
2163                     if (checkIdleStates(msg.arg1) && mAppIdleEnabled) {
2164                         mHandler.sendMessageDelayed(mHandler.obtainMessage(
2165                                 MSG_CHECK_IDLE_STATES, msg.arg1, 0),
2166                                 mCheckIdleIntervalMillis);
2167                     }
2168                     break;
2169 
2170                 case MSG_ONE_TIME_CHECK_IDLE_STATES:
2171                     mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
2172                     waitForAdminData();
2173                     checkIdleStates(UserHandle.USER_ALL);
2174                     break;
2175 
2176                 case MSG_REPORT_CONTENT_PROVIDER_USAGE:
2177                     SomeArgs args = (SomeArgs) msg.obj;
2178                     reportContentProviderUsage((String) args.arg1, // authority name
2179                             (String) args.arg2, // package name
2180                             (int) args.arg3); // userId
2181                     args.recycle();
2182                     break;
2183 
2184                 case MSG_PAROLE_STATE_CHANGED:
2185                     if (DEBUG) Slog.d(TAG, "Parole state: " + isInParole());
2186                     informParoleStateChanged();
2187                     break;
2188 
2189                 case MSG_CHECK_PACKAGE_IDLE_STATE:
2190                     checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
2191                             mInjector.elapsedRealtime());
2192                     break;
2193 
2194                 case MSG_REPORT_SYNC_SCHEDULED:
2195                     final boolean exempted = msg.arg2 > 0 ? true : false;
2196                     if (exempted) {
2197                         reportExemptedSyncScheduled((String) msg.obj, msg.arg1);
2198                     } else {
2199                         reportUnexemptedSyncScheduled((String) msg.obj, msg.arg1);
2200                     }
2201                     break;
2202 
2203                 case MSG_REPORT_EXEMPTED_SYNC_START:
2204                     reportExemptedSyncStart((String) msg.obj, msg.arg1);
2205                     break;
2206 
2207                 default:
2208                     super.handleMessage(msg);
2209                     break;
2210 
2211             }
2212         }
2213     };
2214 
2215     private class DeviceStateReceiver extends BroadcastReceiver {
2216         @Override
onReceive(Context context, Intent intent)2217         public void onReceive(Context context, Intent intent) {
2218             switch (intent.getAction()) {
2219                 case BatteryManager.ACTION_CHARGING:
2220                     setChargingState(true);
2221                     break;
2222                 case BatteryManager.ACTION_DISCHARGING:
2223                     setChargingState(false);
2224                     break;
2225                 case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED:
2226                     if (mSystemServicesReady) {
2227                         mHandler.post(AppStandbyController.this::updatePowerWhitelistCache);
2228                     }
2229                     break;
2230             }
2231         }
2232     }
2233 
2234     private final DisplayManager.DisplayListener mDisplayListener
2235             = new DisplayManager.DisplayListener() {
2236 
2237         @Override public void onDisplayAdded(int displayId) {
2238         }
2239 
2240         @Override public void onDisplayRemoved(int displayId) {
2241         }
2242 
2243         @Override public void onDisplayChanged(int displayId) {
2244             if (displayId == Display.DEFAULT_DISPLAY) {
2245                 final boolean displayOn = isDisplayOn();
2246                 synchronized (mAppIdleLock) {
2247                     mAppIdleHistory.updateDisplay(displayOn, mInjector.elapsedRealtime());
2248                 }
2249             }
2250         }
2251     };
2252 
2253     /**
2254      * Observe settings changes for {@link Global#APP_IDLE_CONSTANTS}.
2255      */
2256     private class SettingsObserver extends ContentObserver {
2257         private static final String KEY_SCREEN_TIME_THRESHOLDS = "screen_thresholds";
2258         private static final String KEY_ELAPSED_TIME_THRESHOLDS = "elapsed_thresholds";
2259         private static final String KEY_STRONG_USAGE_HOLD_DURATION = "strong_usage_duration";
2260         private static final String KEY_NOTIFICATION_SEEN_HOLD_DURATION =
2261                 "notification_seen_duration";
2262         private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION =
2263                 "system_update_usage_duration";
2264         private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout";
2265         private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration";
2266         private static final String KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION =
2267                 "exempted_sync_scheduled_nd_duration";
2268         private static final String KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION =
2269                 "exempted_sync_scheduled_d_duration";
2270         private static final String KEY_EXEMPTED_SYNC_START_HOLD_DURATION =
2271                 "exempted_sync_start_duration";
2272         private static final String KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION =
2273                 "unexempted_sync_scheduled_duration";
2274         private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION =
2275                 "system_interaction_duration";
2276         private static final String KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION =
2277                 "initial_foreground_service_start_duration";
2278         private static final String KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS =
2279                 "auto_restricted_bucket_delay_ms";
2280         private static final String KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS =
2281                 "cross_profile_apps_share_standby_buckets";
2282         public static final long DEFAULT_STRONG_USAGE_TIMEOUT = 1 * ONE_HOUR;
2283         public static final long DEFAULT_NOTIFICATION_TIMEOUT = 12 * ONE_HOUR;
2284         public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
2285         public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE;
2286         public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE;
2287         public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT = 10 * ONE_MINUTE;
2288         public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = 4 * ONE_HOUR;
2289         public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 10 * ONE_MINUTE;
2290         public static final long DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT = 10 * ONE_MINUTE;
2291         public static final long DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT = 30 * ONE_MINUTE;
2292         public static final long DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS = ONE_DAY;
2293         public static final boolean DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = true;
2294 
2295         private final KeyValueListParser mParser = new KeyValueListParser(',');
2296 
SettingsObserver(Handler handler)2297         SettingsObserver(Handler handler) {
2298             super(handler);
2299         }
2300 
registerObserver()2301         void registerObserver() {
2302             final ContentResolver cr = mContext.getContentResolver();
2303             cr.registerContentObserver(Global.getUriFor(Global.APP_IDLE_CONSTANTS), false, this);
2304             cr.registerContentObserver(Global.getUriFor(Global.APP_STANDBY_ENABLED), false, this);
2305             cr.registerContentObserver(Global.getUriFor(Global.ENABLE_RESTRICTED_BUCKET),
2306                     false, this);
2307             cr.registerContentObserver(Global.getUriFor(Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED),
2308                     false, this);
2309         }
2310 
2311         @Override
onChange(boolean selfChange)2312         public void onChange(boolean selfChange) {
2313             updateSettings();
2314             postOneTimeCheckIdleStates();
2315         }
2316 
updateSettings()2317         void updateSettings() {
2318             if (DEBUG) {
2319                 Slog.d(TAG,
2320                         "appidle=" + Global.getString(mContext.getContentResolver(),
2321                                 Global.APP_STANDBY_ENABLED));
2322                 Slog.d(TAG,
2323                         "adaptivebat=" + Global.getString(mContext.getContentResolver(),
2324                                 Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED));
2325                 Slog.d(TAG, "appidleconstants=" + Global.getString(
2326                         mContext.getContentResolver(),
2327                         Global.APP_IDLE_CONSTANTS));
2328             }
2329 
2330             // Look at global settings for this.
2331             // TODO: Maybe apply different thresholds for different users.
2332             try {
2333                 mParser.setString(mInjector.getAppIdleSettings());
2334             } catch (IllegalArgumentException e) {
2335                 Slog.e(TAG, "Bad value for app idle settings: " + e.getMessage());
2336                 // fallthrough, mParser is empty and all defaults will be returned.
2337             }
2338 
2339             synchronized (mAppIdleLock) {
2340 
2341                 String screenThresholdsValue = mParser.getString(KEY_SCREEN_TIME_THRESHOLDS, null);
2342                 mAppStandbyScreenThresholds = parseLongArray(screenThresholdsValue,
2343                         SCREEN_TIME_THRESHOLDS, MINIMUM_SCREEN_TIME_THRESHOLDS);
2344 
2345                 String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS,
2346                         null);
2347                 mAppStandbyElapsedThresholds = parseLongArray(elapsedThresholdsValue,
2348                         ELAPSED_TIME_THRESHOLDS, MINIMUM_ELAPSED_TIME_THRESHOLDS);
2349                 mCheckIdleIntervalMillis = Math.min(mAppStandbyElapsedThresholds[1] / 4,
2350                         COMPRESS_TIME ? ONE_MINUTE : 4 * 60 * ONE_MINUTE); // 4 hours
2351                 mStrongUsageTimeoutMillis = mParser.getDurationMillis(
2352                         KEY_STRONG_USAGE_HOLD_DURATION,
2353                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STRONG_USAGE_TIMEOUT);
2354                 mNotificationSeenTimeoutMillis = mParser.getDurationMillis(
2355                         KEY_NOTIFICATION_SEEN_HOLD_DURATION,
2356                                 COMPRESS_TIME ? 12 * ONE_MINUTE : DEFAULT_NOTIFICATION_TIMEOUT);
2357                 mSystemUpdateUsageTimeoutMillis = mParser.getDurationMillis(
2358                         KEY_SYSTEM_UPDATE_HOLD_DURATION,
2359                                 COMPRESS_TIME ? 2 * ONE_MINUTE : DEFAULT_SYSTEM_UPDATE_TIMEOUT);
2360                 mPredictionTimeoutMillis = mParser.getDurationMillis(
2361                         KEY_PREDICTION_TIMEOUT,
2362                                 COMPRESS_TIME ? 10 * ONE_MINUTE : DEFAULT_PREDICTION_TIMEOUT);
2363                 mSyncAdapterTimeoutMillis = mParser.getDurationMillis(
2364                         KEY_SYNC_ADAPTER_HOLD_DURATION,
2365                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT);
2366 
2367                 mExemptedSyncScheduledNonDozeTimeoutMillis = mParser.getDurationMillis(
2368                         KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION,
2369                                 COMPRESS_TIME ? (ONE_MINUTE / 2)
2370                                         : DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT);
2371 
2372                 mExemptedSyncScheduledDozeTimeoutMillis = mParser.getDurationMillis(
2373                         KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION,
2374                                 COMPRESS_TIME ? ONE_MINUTE
2375                                         : DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT);
2376 
2377                 mExemptedSyncStartTimeoutMillis = mParser.getDurationMillis(
2378                         KEY_EXEMPTED_SYNC_START_HOLD_DURATION,
2379                                 COMPRESS_TIME ? ONE_MINUTE
2380                                         : DEFAULT_EXEMPTED_SYNC_START_TIMEOUT);
2381 
2382                 mUnexemptedSyncScheduledTimeoutMillis = mParser.getDurationMillis(
2383                         KEY_UNEXEMPTED_SYNC_SCHEDULED_HOLD_DURATION,
2384                                 COMPRESS_TIME
2385                                         ? ONE_MINUTE : DEFAULT_UNEXEMPTED_SYNC_SCHEDULED_TIMEOUT);
2386 
2387                 mSystemInteractionTimeoutMillis = mParser.getDurationMillis(
2388                         KEY_SYSTEM_INTERACTION_HOLD_DURATION,
2389                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT);
2390 
2391                 mInitialForegroundServiceStartTimeoutMillis = mParser.getDurationMillis(
2392                         KEY_INITIAL_FOREGROUND_SERVICE_START_HOLD_DURATION,
2393                         COMPRESS_TIME ? ONE_MINUTE :
2394                                 DEFAULT_INITIAL_FOREGROUND_SERVICE_START_TIMEOUT);
2395 
2396                 mInjector.mAutoRestrictedBucketDelayMs = Math.max(
2397                         COMPRESS_TIME ? ONE_MINUTE : 2 * ONE_HOUR,
2398                         mParser.getDurationMillis(KEY_AUTO_RESTRICTED_BUCKET_DELAY_MS,
2399                                 COMPRESS_TIME
2400                                         ? ONE_MINUTE : DEFAULT_AUTO_RESTRICTED_BUCKET_DELAY_MS));
2401 
2402                 mLinkCrossProfileApps = mParser.getBoolean(
2403                         KEY_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS,
2404                         DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS);
2405 
2406                 mAllowRestrictedBucket = mInjector.isRestrictedBucketEnabled();
2407             }
2408 
2409             // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
2410             // in case we need to change something based on the new values.
2411             setAppIdleEnabled(mInjector.isAppIdleEnabled());
2412         }
2413 
parseLongArray(String values, long[] defaults, long[] minValues)2414         long[] parseLongArray(String values, long[] defaults, long[] minValues) {
2415             if (values == null) return defaults;
2416             if (values.isEmpty()) {
2417                 // Reset to defaults
2418                 return defaults;
2419             } else {
2420                 String[] thresholds = values.split("/");
2421                 if (thresholds.length == THRESHOLD_BUCKETS.length) {
2422                     if (minValues.length != THRESHOLD_BUCKETS.length) {
2423                         Slog.wtf(TAG, "minValues array is the wrong size");
2424                         // Use zeroes as the minimums.
2425                         minValues = new long[THRESHOLD_BUCKETS.length];
2426                     }
2427                     long[] array = new long[THRESHOLD_BUCKETS.length];
2428                     for (int i = 0; i < THRESHOLD_BUCKETS.length; i++) {
2429                         try {
2430                             if (thresholds[i].startsWith("P") || thresholds[i].startsWith("p")) {
2431                                 array[i] = Math.max(minValues[i],
2432                                         Duration.parse(thresholds[i]).toMillis());
2433                             } else {
2434                                 array[i] = Math.max(minValues[i], Long.parseLong(thresholds[i]));
2435                             }
2436                         } catch (NumberFormatException|DateTimeParseException e) {
2437                             return defaults;
2438                         }
2439                     }
2440                     return array;
2441                 } else {
2442                     return defaults;
2443                 }
2444             }
2445         }
2446     }
2447 }
2448