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