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