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