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