• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server;
17 
18 import android.annotation.NonNull;
19 import android.app.ActivityManager;
20 import android.app.ActivityManagerInternal;
21 import android.app.ActivityManagerInternal.AppBackgroundRestrictionListener;
22 import android.app.AppOpsManager;
23 import android.app.AppOpsManager.PackageOps;
24 import android.app.IActivityManager;
25 import android.app.usage.UsageStatsManager;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.database.ContentObserver;
31 import android.net.Uri;
32 import android.os.BatteryManager;
33 import android.os.Handler;
34 import android.os.Looper;
35 import android.os.Message;
36 import android.os.PowerManager.ServiceType;
37 import android.os.PowerManagerInternal;
38 import android.os.RemoteException;
39 import android.os.ServiceManager;
40 import android.os.UserHandle;
41 import android.provider.Settings;
42 import android.util.ArraySet;
43 import android.util.IndentingPrintWriter;
44 import android.util.Pair;
45 import android.util.Slog;
46 import android.util.SparseBooleanArray;
47 import android.util.SparseSetArray;
48 import android.util.proto.ProtoOutputStream;
49 
50 import com.android.internal.annotations.GuardedBy;
51 import com.android.internal.annotations.VisibleForTesting;
52 import com.android.internal.app.IAppOpsCallback;
53 import com.android.internal.app.IAppOpsService;
54 import com.android.internal.util.ArrayUtils;
55 import com.android.internal.util.StatLogger;
56 import com.android.modules.expresslog.Counter;
57 import com.android.server.AppStateTrackerProto.ExemptedPackage;
58 import com.android.server.AppStateTrackerProto.RunAnyInBackgroundRestrictedPackages;
59 import com.android.server.usage.AppStandbyInternal;
60 import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
61 
62 import java.io.PrintWriter;
63 import java.util.Arrays;
64 import java.util.Collections;
65 import java.util.List;
66 import java.util.Objects;
67 import java.util.Set;
68 
69 /**
70  * Class to keep track of the information related to "force app standby", which includes:
71  * - OP_RUN_ANY_IN_BACKGROUND for each package
72  * - UID foreground/active state
73  * - User+system power save exemption list
74  * - Temporary power save exemption list
75  * - Global "force all apps standby" mode enforced by battery saver.
76  *
77  * Test: atest com.android.server.AppStateTrackerTest
78  */
79 public class AppStateTrackerImpl implements AppStateTracker {
80     private static final boolean DEBUG = false;
81 
82     private static final String APP_RESTRICTION_COUNTER_METRIC_ID =
83             "battery.value_app_background_restricted";
84 
85     private final Object mLock = new Object();
86     private final Context mContext;
87 
88     @VisibleForTesting
89     static final int TARGET_OP = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
90 
91     IActivityManager mIActivityManager;
92     ActivityManagerInternal mActivityManagerInternal;
93     AppOpsManager mAppOpsManager;
94     IAppOpsService mAppOpsService;
95     PowerManagerInternal mPowerManagerInternal;
96     StandbyTracker mStandbyTracker;
97     AppStandbyInternal mAppStandbyInternal;
98 
99     private final MyHandler mHandler;
100 
101     @VisibleForTesting
102     FeatureFlagsObserver mFlagsObserver;
103 
104     /**
105      * Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
106      */
107     @GuardedBy("mLock")
108     final ArraySet<Pair<Integer, String>> mRunAnyRestrictedPackages = new ArraySet<>();
109 
110     /** UIDs that are active. */
111     @GuardedBy("mLock")
112     final SparseBooleanArray mActiveUids = new SparseBooleanArray();
113 
114     /**
115      * System except-idle + user exemption list in the device idle controller.
116      */
117     @GuardedBy("mLock")
118     private int[] mPowerExemptAllAppIds = new int[0];
119 
120     /**
121      * User exempted apps in the device idle controller.
122      */
123     @GuardedBy("mLock")
124     private int[] mPowerExemptUserAppIds = new int[0];
125 
126     @GuardedBy("mLock")
127     private int[] mTempExemptAppIds = mPowerExemptAllAppIds;
128 
129     /**
130      * Per-user packages that are in the EXEMPTED bucket.
131      */
132     @GuardedBy("mLock")
133     @VisibleForTesting
134     final SparseSetArray<String> mExemptedBucketPackages = new SparseSetArray<>();
135 
136     @GuardedBy("mLock")
137     final ArraySet<Listener> mListeners = new ArraySet<>();
138 
139     @GuardedBy("mLock")
140     boolean mStarted;
141 
142     /**
143      * Only used for small battery use-case.
144      */
145     @GuardedBy("mLock")
146     boolean mIsPluggedIn;
147 
148     @GuardedBy("mLock")
149     boolean mBatterySaverEnabled;
150 
151     /**
152      * True if the forced app standby is currently enabled
153      */
154     @GuardedBy("mLock")
155     boolean mForceAllAppsStandby;
156 
157     /**
158      * True if the forced app standby for small battery devices feature is enabled in settings
159      */
160     @GuardedBy("mLock")
161     boolean mForceAllAppStandbyForSmallBattery;
162 
163     /**
164      * A lock-free set of (uid, packageName) pairs in background restricted mode.
165      *
166      * <p>
167      * It's basically shadowing the {@link #mRunAnyRestrictedPackages}, any mutations on it would
168      * result in copy-on-write.
169      * </p>
170      */
171     volatile Set<Pair<Integer, String>> mBackgroundRestrictedUidPackages = Collections.emptySet();
172 
173     @Override
addBackgroundRestrictedAppListener( @onNull BackgroundRestrictedAppListener listener)174     public void addBackgroundRestrictedAppListener(
175             @NonNull BackgroundRestrictedAppListener listener) {
176         addListener(new Listener() {
177             @Override
178             public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
179                     boolean restricted) {
180                 listener.updateBackgroundRestrictedForUidPackage(uid, packageName, restricted);
181             }
182         });
183     }
184 
185     @Override
isAppBackgroundRestricted(int uid, @NonNull String packageName)186     public boolean isAppBackgroundRestricted(int uid, @NonNull String packageName) {
187         final Set<Pair<Integer, String>> bgRestrictedUidPkgs = mBackgroundRestrictedUidPackages;
188         return bgRestrictedUidPkgs.contains(Pair.create(uid, packageName));
189     }
190 
191     interface Stats {
192         int UID_FG_STATE_CHANGED = 0;
193         int UID_ACTIVE_STATE_CHANGED = 1;
194         int RUN_ANY_CHANGED = 2;
195         int ALL_UNEXEMPTED = 3;
196         int ALL_EXEMPTION_LIST_CHANGED = 4;
197         int TEMP_EXEMPTION_LIST_CHANGED = 5;
198         int EXEMPTED_BUCKET_CHANGED = 6;
199         int FORCE_ALL_CHANGED = 7;
200 
201         int IS_UID_ACTIVE_CACHED = 8;
202         int IS_UID_ACTIVE_RAW = 9;
203     }
204 
205     private final StatLogger mStatLogger = new StatLogger(new String[] {
206             "UID_FG_STATE_CHANGED",
207             "UID_ACTIVE_STATE_CHANGED",
208             "RUN_ANY_CHANGED",
209             "ALL_UNEXEMPTED",
210             "ALL_EXEMPTION_LIST_CHANGED",
211             "TEMP_EXEMPTION_LIST_CHANGED",
212             "EXEMPTED_BUCKET_CHANGED",
213             "FORCE_ALL_CHANGED",
214 
215             "IS_UID_ACTIVE_CACHED",
216             "IS_UID_ACTIVE_RAW",
217     });
218 
219     @VisibleForTesting
220     class FeatureFlagsObserver extends ContentObserver {
FeatureFlagsObserver()221         FeatureFlagsObserver() {
222             super(null);
223         }
224 
register()225         void register() {
226             mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
227                     Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED), false, this);
228         }
229 
isForcedAppStandbyForSmallBatteryEnabled()230         boolean isForcedAppStandbyForSmallBatteryEnabled() {
231             return injectGetGlobalSettingInt(
232                     Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 0) == 1;
233         }
234 
235         @Override
onChange(boolean selfChange, Uri uri)236         public void onChange(boolean selfChange, Uri uri) {
237             if (Settings.Global.getUriFor(
238                     Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED).equals(uri)) {
239                 final boolean enabled = isForcedAppStandbyForSmallBatteryEnabled();
240                 synchronized (mLock) {
241                     if (mForceAllAppStandbyForSmallBattery == enabled) {
242                         return;
243                     }
244                     mForceAllAppStandbyForSmallBattery = enabled;
245                     if (DEBUG) {
246                         Slog.d(TAG, "Forced app standby for small battery feature flag changed: "
247                                 + mForceAllAppStandbyForSmallBattery);
248                     }
249                     updateForceAllAppStandbyState();
250                 }
251             } else {
252                 Slog.w(TAG, "Unexpected feature flag uri encountered: " + uri);
253             }
254         }
255     }
256 
257     private final AppBackgroundRestrictionListener mAppBackgroundRestrictionListener =
258             new AppBackgroundRestrictionListener() {
259         @Override
260         public void onAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket) {
261             mHandler.notifyAutoRestrictedBucketFeatureFlagChanged(autoRestrictedBucket);
262         }
263     };
264 
265     /**
266      * Listener for any state changes that affect any app's eligibility to run.
267      */
268     public abstract static class Listener {
269         /**
270          * This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package.
271          */
onRunAnyAppOpsChanged(AppStateTrackerImpl sender, int uid, @NonNull String packageName)272         private void onRunAnyAppOpsChanged(AppStateTrackerImpl sender,
273                 int uid, @NonNull String packageName) {
274             updateJobsForUidPackage(uid, packageName, sender.isUidActive(uid));
275 
276             if (!sender.areAlarmsRestricted(uid, packageName)) {
277                 unblockAlarmsForUidPackage(uid, packageName);
278             }
279 
280             if (!sender.isRunAnyInBackgroundAppOpsAllowed(uid, packageName)) {
281                 Slog.v(TAG, "Package " + packageName + "/" + uid
282                         + " toggled into fg service restriction");
283                 updateBackgroundRestrictedForUidPackage(uid, packageName, true);
284             } else {
285                 Slog.v(TAG, "Package " + packageName + "/" + uid
286                         + " toggled out of fg service restriction");
287                 updateBackgroundRestrictedForUidPackage(uid, packageName, false);
288             }
289         }
290 
291         /**
292          * This is called when the active/idle state changed for a UID.
293          */
onUidActiveStateChanged(AppStateTrackerImpl sender, int uid)294         private void onUidActiveStateChanged(AppStateTrackerImpl sender, int uid) {
295             final boolean isActive = sender.isUidActive(uid);
296 
297             updateJobsForUid(uid, isActive);
298             updateAlarmsForUid(uid);
299 
300             if (isActive) {
301                 unblockAlarmsForUid(uid);
302             }
303         }
304 
305         /**
306          * This is called when an app-id(s) is removed from the power save allow-list.
307          */
onPowerSaveUnexempted(AppStateTrackerImpl sender)308         private void onPowerSaveUnexempted(AppStateTrackerImpl sender) {
309             updateAllJobs();
310             updateAllAlarms();
311         }
312 
313         /**
314          * This is called when the power save exemption list changes, excluding the
315          * {@link #onPowerSaveUnexempted} case.
316          */
onPowerSaveExemptionListChanged(AppStateTrackerImpl sender)317         private void onPowerSaveExemptionListChanged(AppStateTrackerImpl sender) {
318             updateAllJobs();
319             updateAllAlarms();
320             unblockAllUnrestrictedAlarms();
321         }
322 
323         /**
324          * This is called when the temp exemption list changes.
325          */
onTempPowerSaveExemptionListChanged(AppStateTrackerImpl sender)326         private void onTempPowerSaveExemptionListChanged(AppStateTrackerImpl sender) {
327 
328             // TODO This case happens rather frequently; consider optimizing and update jobs
329             // only for affected app-ids.
330 
331             updateAllJobs();
332 
333             // Note when an app is just put in the temp exemption list, we do *not* drain pending
334             // alarms.
335         }
336 
337         /**
338          * This is called when the EXEMPTED bucket is updated.
339          */
onExemptedBucketChanged(AppStateTrackerImpl sender)340         private void onExemptedBucketChanged(AppStateTrackerImpl sender) {
341             // This doesn't happen very often, so just re-evaluate all jobs / alarms.
342             updateAllJobs();
343             updateAllAlarms();
344         }
345 
346         /**
347          * This is called when the global "force all apps standby" flag changes.
348          */
onForceAllAppsStandbyChanged(AppStateTrackerImpl sender)349         private void onForceAllAppsStandbyChanged(AppStateTrackerImpl sender) {
350             updateAllJobs();
351             updateAllAlarms();
352         }
353 
354         /**
355          * Called when toggling the feature flag of moving to restricted standby bucket
356          * automatically on background-restricted.
357          */
onAutoRestrictedBucketFeatureFlagChanged(AppStateTrackerImpl sender, boolean autoRestrictedBucket)358         private void onAutoRestrictedBucketFeatureFlagChanged(AppStateTrackerImpl sender,
359                 boolean autoRestrictedBucket) {
360             updateAllJobs();
361             if (autoRestrictedBucket) {
362                 unblockAllUnrestrictedAlarms();
363             }
364         }
365 
366         /**
367          * Called when the job restrictions for multiple UIDs might have changed, so the job
368          * scheduler should re-evaluate all restrictions for all jobs.
369          */
updateAllJobs()370         public void updateAllJobs() {
371         }
372 
373         /**
374          * Called when the job restrictions for a UID might have changed, so the job
375          * scheduler should re-evaluate all restrictions for all jobs.
376          */
updateJobsForUid(int uid, boolean isNowActive)377         public void updateJobsForUid(int uid, boolean isNowActive) {
378         }
379 
380         /**
381          * Called when the job restrictions for a UID - package might have changed, so the job
382          * scheduler should re-evaluate all restrictions for all jobs.
383          */
updateJobsForUidPackage(int uid, String packageName, boolean isNowActive)384         public void updateJobsForUidPackage(int uid, String packageName, boolean isNowActive) {
385         }
386 
387         /**
388          * Called when an app goes in/out of background restricted mode.
389          */
updateBackgroundRestrictedForUidPackage(int uid, String packageName, boolean restricted)390         public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
391                 boolean restricted) {
392         }
393 
394         /**
395          * Called when all alarms need to be re-evaluated for eligibility based on
396          * {@link #areAlarmsRestrictedByBatterySaver}.
397          */
updateAllAlarms()398         public void updateAllAlarms() {
399         }
400 
401         /**
402          * Called when the given uid state changes to active / idle.
403          */
updateAlarmsForUid(int uid)404         public void updateAlarmsForUid(int uid) {
405         }
406 
407         /**
408          * Called when the job restrictions for multiple UIDs might have changed, so the alarm
409          * manager should re-evaluate all restrictions for all blocked jobs.
410          */
unblockAllUnrestrictedAlarms()411         public void unblockAllUnrestrictedAlarms() {
412         }
413 
414         /**
415          * Called when all jobs for a specific UID are unblocked.
416          */
unblockAlarmsForUid(int uid)417         public void unblockAlarmsForUid(int uid) {
418         }
419 
420         /**
421          * Called when all alarms for a specific UID - package are unblocked.
422          */
unblockAlarmsForUidPackage(int uid, String packageName)423         public void unblockAlarmsForUidPackage(int uid, String packageName) {
424         }
425 
426         /**
427          * Called when an ephemeral uid goes to the background, so its alarms need to be removed.
428          */
removeAlarmsForUid(int uid)429         public void removeAlarmsForUid(int uid) {
430         }
431 
432         /**
433          * Called when a uid goes into cached, so its alarms using a listener should be removed.
434          */
handleUidCachedChanged(int uid, boolean cached)435         public void handleUidCachedChanged(int uid, boolean cached) {
436         }
437     }
438 
AppStateTrackerImpl(Context context, Looper looper)439     public AppStateTrackerImpl(Context context, Looper looper) {
440         mContext = context;
441         mHandler = new MyHandler(looper);
442     }
443 
444     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
445         @Override
446         public void onReceive(Context context, Intent intent) {
447             final String action = intent.getAction();
448             if (action == null) {
449                 return;
450             }
451 
452             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
453             switch (action) {
454                 case Intent.ACTION_USER_REMOVED:
455                     if (userId > 0) {
456                         mHandler.doUserRemoved(userId);
457                     }
458                     break;
459                 case Intent.ACTION_BATTERY_CHANGED:
460                     synchronized (mLock) {
461                         mIsPluggedIn = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
462                     }
463                     updateForceAllAppStandbyState();
464                     break;
465                 case Intent.ACTION_PACKAGE_REMOVED:
466                     if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
467                         final String pkgName = intent.getData().getSchemeSpecificPart();
468                         final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
469                         // No need to notify for state change as all the alarms and jobs should be
470                         // removed too.
471                         synchronized (mLock) {
472                             mExemptedBucketPackages.remove(userId, pkgName);
473                             mRunAnyRestrictedPackages.remove(Pair.create(uid, pkgName));
474                             updateBackgroundRestrictedUidPackagesLocked();
475                             mActiveUids.delete(uid);
476                         }
477                     }
478                     break;
479             }
480         }
481     };
482 
483     /**
484      * Call it when the system is ready.
485      */
onSystemServicesReady()486     public void onSystemServicesReady() {
487         synchronized (mLock) {
488             if (mStarted) {
489                 return;
490             }
491             mStarted = true;
492 
493             mIActivityManager = Objects.requireNonNull(injectIActivityManager());
494             mActivityManagerInternal = Objects.requireNonNull(injectActivityManagerInternal());
495             mAppOpsManager = Objects.requireNonNull(injectAppOpsManager());
496             mAppOpsService = Objects.requireNonNull(injectIAppOpsService());
497             mPowerManagerInternal = Objects.requireNonNull(injectPowerManagerInternal());
498             mAppStandbyInternal = Objects.requireNonNull(injectAppStandbyInternal());
499 
500             mFlagsObserver = new FeatureFlagsObserver();
501             mFlagsObserver.register();
502             mForceAllAppStandbyForSmallBattery =
503                     mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled();
504             mStandbyTracker = new StandbyTracker();
505             mAppStandbyInternal.addListener(mStandbyTracker);
506             mActivityManagerInternal.addAppBackgroundRestrictionListener(
507                     mAppBackgroundRestrictionListener);
508 
509             try {
510                 mIActivityManager.registerUidObserver(new UidObserver(),
511                         ActivityManager.UID_OBSERVER_GONE
512                                 | ActivityManager.UID_OBSERVER_IDLE
513                                 | ActivityManager.UID_OBSERVER_ACTIVE
514                                 | ActivityManager.UID_OBSERVER_CACHED,
515                         ActivityManager.PROCESS_STATE_UNKNOWN, null);
516                 mAppOpsService.startWatchingMode(TARGET_OP, null,
517                         new AppOpsWatcher());
518             } catch (RemoteException e) {
519                 // shouldn't happen.
520             }
521 
522             IntentFilter filter = new IntentFilter();
523             filter.addAction(Intent.ACTION_USER_REMOVED);
524             filter.addAction(Intent.ACTION_BATTERY_CHANGED);
525             mContext.registerReceiver(mReceiver, filter);
526 
527             filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
528             filter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
529             mContext.registerReceiver(mReceiver, filter);
530 
531             refreshForcedAppStandbyUidPackagesLocked();
532 
533             mPowerManagerInternal.registerLowPowerModeObserver(
534                     ServiceType.FORCE_ALL_APPS_STANDBY,
535                     (state) -> {
536                         synchronized (mLock) {
537                             mBatterySaverEnabled = state.batterySaverEnabled;
538                             updateForceAllAppStandbyState();
539                         }
540                     });
541 
542             mBatterySaverEnabled = mPowerManagerInternal.getLowPowerState(
543                     ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled;
544 
545             updateForceAllAppStandbyState();
546         }
547     }
548 
549     @VisibleForTesting
injectAppOpsManager()550     AppOpsManager injectAppOpsManager() {
551         return mContext.getSystemService(AppOpsManager.class);
552     }
553 
554     @VisibleForTesting
injectIAppOpsService()555     IAppOpsService injectIAppOpsService() {
556         return IAppOpsService.Stub.asInterface(
557                 ServiceManager.getService(Context.APP_OPS_SERVICE));
558     }
559 
560     @VisibleForTesting
injectIActivityManager()561     IActivityManager injectIActivityManager() {
562         return ActivityManager.getService();
563     }
564 
565     @VisibleForTesting
injectActivityManagerInternal()566     ActivityManagerInternal injectActivityManagerInternal() {
567         return LocalServices.getService(ActivityManagerInternal.class);
568     }
569 
570     @VisibleForTesting
injectPowerManagerInternal()571     PowerManagerInternal injectPowerManagerInternal() {
572         return LocalServices.getService(PowerManagerInternal.class);
573     }
574 
575     @VisibleForTesting
injectAppStandbyInternal()576     AppStandbyInternal injectAppStandbyInternal() {
577         return LocalServices.getService(AppStandbyInternal.class);
578     }
579 
580     @VisibleForTesting
isSmallBatteryDevice()581     boolean isSmallBatteryDevice() {
582         return ActivityManager.isSmallBatteryDevice();
583     }
584 
585     @VisibleForTesting
injectGetGlobalSettingInt(String key, int def)586     int injectGetGlobalSettingInt(String key, int def) {
587         return Settings.Global.getInt(mContext.getContentResolver(), key, def);
588     }
589 
590     /**
591      * Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
592      */
593     @GuardedBy("mLock")
refreshForcedAppStandbyUidPackagesLocked()594     private void refreshForcedAppStandbyUidPackagesLocked() {
595         mRunAnyRestrictedPackages.clear();
596         final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(
597                 new int[] {TARGET_OP});
598 
599         if (ops == null) {
600             return;
601         }
602         final int size = ops.size();
603         for (int i = 0; i < size; i++) {
604             final AppOpsManager.PackageOps pkg = ops.get(i);
605             final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
606 
607             for (int j = 0; j < entries.size(); j++) {
608                 AppOpsManager.OpEntry ent = entries.get(j);
609                 if (ent.getOp() != TARGET_OP) {
610                     continue;
611                 }
612                 if (ent.getMode() != AppOpsManager.MODE_ALLOWED) {
613                     mRunAnyRestrictedPackages.add(Pair.create(
614                             pkg.getUid(), pkg.getPackageName()));
615                 }
616             }
617         }
618         updateBackgroundRestrictedUidPackagesLocked();
619     }
620 
621     /**
622      * Update the {@link #mBackgroundRestrictedUidPackages} upon mutations on
623      * {@link #mRunAnyRestrictedPackages}.
624      */
625     @GuardedBy("mLock")
updateBackgroundRestrictedUidPackagesLocked()626     private void updateBackgroundRestrictedUidPackagesLocked() {
627         Set<Pair<Integer, String>> fasUidPkgs = new ArraySet<>();
628         for (int i = 0, size = mRunAnyRestrictedPackages.size(); i < size; i++) {
629             fasUidPkgs.add(mRunAnyRestrictedPackages.valueAt(i));
630         }
631         mBackgroundRestrictedUidPackages = Collections.unmodifiableSet(fasUidPkgs);
632     }
633 
updateForceAllAppStandbyState()634     private void updateForceAllAppStandbyState() {
635         synchronized (mLock) {
636             if (mForceAllAppStandbyForSmallBattery && isSmallBatteryDevice()) {
637                 toggleForceAllAppsStandbyLocked(!mIsPluggedIn);
638             } else {
639                 toggleForceAllAppsStandbyLocked(mBatterySaverEnabled);
640             }
641         }
642     }
643 
644     /**
645      * Update {@link #mForceAllAppsStandby} and notifies the listeners.
646      */
647     @GuardedBy("mLock")
toggleForceAllAppsStandbyLocked(boolean enable)648     private void toggleForceAllAppsStandbyLocked(boolean enable) {
649         if (enable == mForceAllAppsStandby) {
650             return;
651         }
652         mForceAllAppsStandby = enable;
653 
654         mHandler.notifyForceAllAppsStandbyChanged();
655     }
656 
657     @GuardedBy("mLock")
findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName)658     private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
659         final int size = mRunAnyRestrictedPackages.size();
660         if (size > 8) {
661             return mRunAnyRestrictedPackages.indexOf(Pair.create(uid, packageName));
662         }
663         for (int i = 0; i < size; i++) {
664             final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
665 
666             if ((pair.first == uid) && packageName.equals(pair.second)) {
667                 return i;
668             }
669         }
670         return -1;
671     }
672 
673     /**
674      * @return whether a uid package-name pair is in mRunAnyRestrictedPackages.
675      */
676     @GuardedBy("mLock")
isRunAnyRestrictedLocked(int uid, @NonNull String packageName)677     boolean isRunAnyRestrictedLocked(int uid, @NonNull String packageName) {
678         return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0;
679     }
680 
681     /**
682      * Add to / remove from {@link #mRunAnyRestrictedPackages}.
683      */
684     @GuardedBy("mLock")
updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName, boolean restricted)685     boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName,
686             boolean restricted) {
687         final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
688         final boolean wasRestricted = index >= 0;
689         if (wasRestricted == restricted) {
690             return false;
691         }
692         if (restricted) {
693             mRunAnyRestrictedPackages.add(Pair.create(uid, packageName));
694         } else {
695             mRunAnyRestrictedPackages.removeAt(index);
696         }
697         updateBackgroundRestrictedUidPackagesLocked();
698         return true;
699     }
700 
addUidToArray(SparseBooleanArray array, int uid)701     private static boolean addUidToArray(SparseBooleanArray array, int uid) {
702         if (UserHandle.isCore(uid)) {
703             return false;
704         }
705         if (array.get(uid)) {
706             return false;
707         }
708         array.put(uid, true);
709         return true;
710     }
711 
removeUidFromArray(SparseBooleanArray array, int uid, boolean remove)712     private static boolean removeUidFromArray(SparseBooleanArray array, int uid, boolean remove) {
713         if (UserHandle.isCore(uid)) {
714             return false;
715         }
716         if (!array.get(uid)) {
717             return false;
718         }
719         if (remove) {
720             array.delete(uid);
721         } else {
722             array.put(uid, false);
723         }
724         return true;
725     }
726 
727     private final class UidObserver extends android.app.UidObserver {
728         @Override
onUidActive(int uid)729         public void onUidActive(int uid) {
730             mHandler.onUidActive(uid);
731         }
732 
733         @Override
onUidGone(int uid, boolean disabled)734         public void onUidGone(int uid, boolean disabled) {
735             mHandler.onUidGone(uid, disabled);
736         }
737 
738         @Override
onUidIdle(int uid, boolean disabled)739         public void onUidIdle(int uid, boolean disabled) {
740             mHandler.onUidIdle(uid, disabled);
741         }
742 
743         @Override
onUidCachedChanged(int uid, boolean cached)744         public void onUidCachedChanged(int uid, boolean cached) {
745             mHandler.onUidCachedChanged(uid, cached);
746         }
747     }
748 
749     private final class AppOpsWatcher extends IAppOpsCallback.Stub {
750         @Override
opChanged(int op, int uid, String packageName, String persistentDeviceId)751         public void opChanged(int op, int uid, String packageName,
752                 String persistentDeviceId) throws RemoteException {
753             boolean restricted = false;
754             try {
755                 restricted = mAppOpsService.checkOperation(TARGET_OP,
756                         uid, packageName) != AppOpsManager.MODE_ALLOWED;
757             } catch (RemoteException e) {
758                 // Shouldn't happen
759             }
760             if (restricted) {
761                 Counter.logIncrementWithUid(APP_RESTRICTION_COUNTER_METRIC_ID, uid);
762             }
763             synchronized (mLock) {
764                 if (updateForcedAppStandbyUidPackageLocked(uid, packageName, restricted)) {
765                     mHandler.notifyRunAnyAppOpsChanged(uid, packageName);
766                 }
767             }
768         }
769     }
770 
771     final class StandbyTracker extends AppIdleStateChangeListener {
772         @Override
onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason)773         public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
774                 int bucket, int reason) {
775             if (DEBUG) {
776                 Slog.d(TAG, "onAppIdleStateChanged: " + packageName + " u" + userId
777                         + (idle ? " idle" : " active") + " " + bucket);
778             }
779             synchronized (mLock) {
780                 final boolean changed;
781                 if (bucket == UsageStatsManager.STANDBY_BUCKET_EXEMPTED) {
782                     changed = mExemptedBucketPackages.add(userId, packageName);
783                 } else {
784                     changed = mExemptedBucketPackages.remove(userId, packageName);
785                 }
786                 if (changed) {
787                     mHandler.notifyExemptedBucketChanged();
788                 }
789             }
790         }
791     }
792 
cloneListeners()793     private Listener[] cloneListeners() {
794         synchronized (mLock) {
795             return mListeners.toArray(new Listener[mListeners.size()]);
796         }
797     }
798 
799     private class MyHandler extends Handler {
800         private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0;
801         // Unused ids 1, 2.
802         private static final int MSG_RUN_ANY_CHANGED = 3;
803         private static final int MSG_ALL_UNEXEMPTED = 4;
804         private static final int MSG_ALL_EXEMPTION_LIST_CHANGED = 5;
805         private static final int MSG_TEMP_EXEMPTION_LIST_CHANGED = 6;
806         private static final int MSG_FORCE_ALL_CHANGED = 7;
807         private static final int MSG_USER_REMOVED = 8;
808         // Unused id 9.
809         private static final int MSG_EXEMPTED_BUCKET_CHANGED = 10;
810         private static final int MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED = 11;
811 
812         private static final int MSG_ON_UID_ACTIVE = 12;
813         private static final int MSG_ON_UID_GONE = 13;
814         private static final int MSG_ON_UID_IDLE = 14;
815         private static final int MSG_ON_UID_CACHED = 15;
816 
MyHandler(Looper looper)817         MyHandler(Looper looper) {
818             super(looper);
819         }
820 
notifyUidActiveStateChanged(int uid)821         public void notifyUidActiveStateChanged(int uid) {
822             obtainMessage(MSG_UID_ACTIVE_STATE_CHANGED, uid, 0).sendToTarget();
823         }
824 
notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName)825         public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
826             obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
827         }
828 
notifyAllUnexempted()829         public void notifyAllUnexempted() {
830             removeMessages(MSG_ALL_UNEXEMPTED);
831             obtainMessage(MSG_ALL_UNEXEMPTED).sendToTarget();
832         }
833 
notifyAllExemptionListChanged()834         public void notifyAllExemptionListChanged() {
835             removeMessages(MSG_ALL_EXEMPTION_LIST_CHANGED);
836             obtainMessage(MSG_ALL_EXEMPTION_LIST_CHANGED).sendToTarget();
837         }
838 
notifyTempExemptionListChanged()839         public void notifyTempExemptionListChanged() {
840             removeMessages(MSG_TEMP_EXEMPTION_LIST_CHANGED);
841             obtainMessage(MSG_TEMP_EXEMPTION_LIST_CHANGED).sendToTarget();
842         }
843 
notifyForceAllAppsStandbyChanged()844         public void notifyForceAllAppsStandbyChanged() {
845             removeMessages(MSG_FORCE_ALL_CHANGED);
846             obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
847         }
848 
notifyExemptedBucketChanged()849         public void notifyExemptedBucketChanged() {
850             removeMessages(MSG_EXEMPTED_BUCKET_CHANGED);
851             obtainMessage(MSG_EXEMPTED_BUCKET_CHANGED).sendToTarget();
852         }
853 
notifyAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket)854         public void notifyAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket) {
855             removeMessages(MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED);
856             obtainMessage(MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED,
857                     autoRestrictedBucket ? 1 : 0, 0).sendToTarget();
858         }
859 
doUserRemoved(int userId)860         public void doUserRemoved(int userId) {
861             obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
862         }
863 
onUidActive(int uid)864         public void onUidActive(int uid) {
865             obtainMessage(MSG_ON_UID_ACTIVE, uid, 0).sendToTarget();
866         }
867 
onUidGone(int uid, boolean disabled)868         public void onUidGone(int uid, boolean disabled) {
869             obtainMessage(MSG_ON_UID_GONE, uid, disabled ? 1 : 0).sendToTarget();
870         }
871 
onUidIdle(int uid, boolean disabled)872         public void onUidIdle(int uid, boolean disabled) {
873             obtainMessage(MSG_ON_UID_IDLE, uid, disabled ? 1 : 0).sendToTarget();
874         }
875 
onUidCachedChanged(int uid, boolean cached)876         public void onUidCachedChanged(int uid, boolean cached) {
877             obtainMessage(MSG_ON_UID_CACHED, uid, cached ? 1 : 0).sendToTarget();
878         }
879 
880         @Override
handleMessage(Message msg)881         public void handleMessage(Message msg) {
882             switch (msg.what) {
883                 case MSG_USER_REMOVED:
884                     handleUserRemoved(msg.arg1);
885                     return;
886             }
887 
888             // Only notify the listeners when started.
889             synchronized (mLock) {
890                 if (!mStarted) {
891                     return;
892                 }
893             }
894             final AppStateTrackerImpl sender = AppStateTrackerImpl.this;
895 
896             long start = mStatLogger.getTime();
897             switch (msg.what) {
898                 case MSG_UID_ACTIVE_STATE_CHANGED:
899                     for (Listener l : cloneListeners()) {
900                         l.onUidActiveStateChanged(sender, msg.arg1);
901                     }
902                     mStatLogger.logDurationStat(Stats.UID_ACTIVE_STATE_CHANGED, start);
903                     return;
904 
905                 case MSG_RUN_ANY_CHANGED:
906                     for (Listener l : cloneListeners()) {
907                         l.onRunAnyAppOpsChanged(sender, msg.arg1, (String) msg.obj);
908                     }
909                     mStatLogger.logDurationStat(Stats.RUN_ANY_CHANGED, start);
910                     return;
911 
912                 case MSG_ALL_UNEXEMPTED:
913                     for (Listener l : cloneListeners()) {
914                         l.onPowerSaveUnexempted(sender);
915                     }
916                     mStatLogger.logDurationStat(Stats.ALL_UNEXEMPTED, start);
917                     return;
918 
919                 case MSG_ALL_EXEMPTION_LIST_CHANGED:
920                     for (Listener l : cloneListeners()) {
921                         l.onPowerSaveExemptionListChanged(sender);
922                     }
923                     mStatLogger.logDurationStat(Stats.ALL_EXEMPTION_LIST_CHANGED, start);
924                     return;
925 
926                 case MSG_TEMP_EXEMPTION_LIST_CHANGED:
927                     for (Listener l : cloneListeners()) {
928                         l.onTempPowerSaveExemptionListChanged(sender);
929                     }
930                     mStatLogger.logDurationStat(Stats.TEMP_EXEMPTION_LIST_CHANGED, start);
931                     return;
932 
933                 case MSG_EXEMPTED_BUCKET_CHANGED:
934                     for (Listener l : cloneListeners()) {
935                         l.onExemptedBucketChanged(sender);
936                     }
937                     mStatLogger.logDurationStat(Stats.EXEMPTED_BUCKET_CHANGED, start);
938                     return;
939 
940                 case MSG_FORCE_ALL_CHANGED:
941                     for (Listener l : cloneListeners()) {
942                         l.onForceAllAppsStandbyChanged(sender);
943                     }
944                     mStatLogger.logDurationStat(Stats.FORCE_ALL_CHANGED, start);
945                     return;
946 
947                 case MSG_USER_REMOVED:
948                     handleUserRemoved(msg.arg1);
949                     return;
950 
951                 case MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED:
952                     final boolean autoRestrictedBucket = msg.arg1 == 1;
953                     for (Listener l : cloneListeners()) {
954                         l.onAutoRestrictedBucketFeatureFlagChanged(sender, autoRestrictedBucket);
955                     }
956                     return;
957 
958                 case MSG_ON_UID_ACTIVE:
959                     handleUidActive(msg.arg1);
960                     return;
961                 case MSG_ON_UID_GONE:
962                     handleUidGone(msg.arg1);
963                     if (msg.arg2 != 0) {
964                         handleUidDisabled(msg.arg1);
965                     }
966                     return;
967                 case MSG_ON_UID_IDLE:
968                     handleUidIdle(msg.arg1);
969                     if (msg.arg2 != 0) {
970                         handleUidDisabled(msg.arg1);
971                     }
972                     return;
973                 case MSG_ON_UID_CACHED:
974                     handleUidCached(msg.arg1, (msg.arg2 != 0));
975                     return;
976             }
977         }
978 
handleUidCached(int uid, boolean cached)979         private void handleUidCached(int uid, boolean cached) {
980             for (Listener l : cloneListeners()) {
981                 l.handleUidCachedChanged(uid, cached);
982             }
983         }
984 
handleUidDisabled(int uid)985         private void handleUidDisabled(int uid) {
986             for (Listener l : cloneListeners()) {
987                 l.removeAlarmsForUid(uid);
988             }
989         }
990 
handleUidActive(int uid)991         public void handleUidActive(int uid) {
992             synchronized (mLock) {
993                 if (addUidToArray(mActiveUids, uid)) {
994                     mHandler.notifyUidActiveStateChanged(uid);
995                 }
996             }
997         }
998 
handleUidGone(int uid)999         public void handleUidGone(int uid) {
1000             removeUid(uid, true);
1001         }
1002 
handleUidIdle(int uid)1003         public void handleUidIdle(int uid) {
1004             // Just to avoid excessive memcpy, don't remove from the array in this case.
1005             removeUid(uid, false);
1006         }
1007 
removeUid(int uid, boolean remove)1008         private void removeUid(int uid, boolean remove) {
1009             synchronized (mLock) {
1010                 if (removeUidFromArray(mActiveUids, uid, remove)) {
1011                     mHandler.notifyUidActiveStateChanged(uid);
1012                 }
1013             }
1014         }
1015     }
1016 
handleUserRemoved(int removedUserId)1017     void handleUserRemoved(int removedUserId) {
1018         synchronized (mLock) {
1019             for (int i = mRunAnyRestrictedPackages.size() - 1; i >= 0; i--) {
1020                 final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
1021                 final int uid = pair.first;
1022                 final int userId = UserHandle.getUserId(uid);
1023 
1024                 if (userId == removedUserId) {
1025                     mRunAnyRestrictedPackages.removeAt(i);
1026                 }
1027             }
1028             updateBackgroundRestrictedUidPackagesLocked();
1029             cleanUpArrayForUser(mActiveUids, removedUserId);
1030             mExemptedBucketPackages.remove(removedUserId);
1031         }
1032     }
1033 
cleanUpArrayForUser(SparseBooleanArray array, int removedUserId)1034     private void cleanUpArrayForUser(SparseBooleanArray array, int removedUserId) {
1035         for (int i = array.size() - 1; i >= 0; i--) {
1036             final int uid = array.keyAt(i);
1037             final int userId = UserHandle.getUserId(uid);
1038 
1039             if (userId == removedUserId) {
1040                 array.removeAt(i);
1041             }
1042         }
1043     }
1044 
1045     /**
1046      * Called by device idle controller to update the power save exemption lists.
1047      */
setPowerSaveExemptionListAppIds( int[] powerSaveExemptionListExceptIdleAppIdArray, int[] powerSaveExemptionListUserAppIdArray, int[] tempExemptionListAppIdArray)1048     public void setPowerSaveExemptionListAppIds(
1049             int[] powerSaveExemptionListExceptIdleAppIdArray,
1050             int[] powerSaveExemptionListUserAppIdArray,
1051             int[] tempExemptionListAppIdArray) {
1052         synchronized (mLock) {
1053             final int[] previousExemptionList = mPowerExemptAllAppIds;
1054             final int[] previousTempExemptionList = mTempExemptAppIds;
1055 
1056             mPowerExemptAllAppIds = powerSaveExemptionListExceptIdleAppIdArray;
1057             mTempExemptAppIds = tempExemptionListAppIdArray;
1058             mPowerExemptUserAppIds = powerSaveExemptionListUserAppIdArray;
1059 
1060             if (isAnyAppIdUnexempt(previousExemptionList, mPowerExemptAllAppIds)) {
1061                 mHandler.notifyAllUnexempted();
1062             } else if (!Arrays.equals(previousExemptionList, mPowerExemptAllAppIds)) {
1063                 mHandler.notifyAllExemptionListChanged();
1064             }
1065 
1066             if (!Arrays.equals(previousTempExemptionList, mTempExemptAppIds)) {
1067                 mHandler.notifyTempExemptionListChanged();
1068             }
1069 
1070         }
1071     }
1072 
1073     /**
1074      * @return true if a sorted app-id array {@code prevArray} has at least one element
1075      * that's not in a sorted app-id array {@code newArray}.
1076      */
1077     @VisibleForTesting
isAnyAppIdUnexempt(int[] prevArray, int[] newArray)1078     static boolean isAnyAppIdUnexempt(int[] prevArray, int[] newArray) {
1079         int i1 = 0;
1080         int i2 = 0;
1081         boolean prevFinished;
1082         boolean newFinished;
1083 
1084         for (;;) {
1085             prevFinished = i1 >= prevArray.length;
1086             newFinished = i2 >= newArray.length;
1087             if (prevFinished || newFinished) {
1088                 break;
1089             }
1090             int a1 = prevArray[i1];
1091             int a2 = newArray[i2];
1092 
1093             if (a1 == a2) {
1094                 i1++;
1095                 i2++;
1096                 continue;
1097             }
1098             if (a1 < a2) {
1099                 // prevArray has an element that's not in a2.
1100                 return true;
1101             }
1102             i2++;
1103         }
1104         if (prevFinished) {
1105             return false;
1106         }
1107         return newFinished;
1108     }
1109 
1110     // Public interface.
1111 
1112     /**
1113      * Register a listener to get callbacks when any state changes.
1114      */
addListener(@onNull Listener listener)1115     public void addListener(@NonNull Listener listener) {
1116         synchronized (mLock) {
1117             mListeners.add(listener);
1118         }
1119     }
1120 
1121     /**
1122      * @return whether alarms should be restricted for a UID package-name, due to explicit
1123      * user-forced app standby. Use {{@link #areAlarmsRestrictedByBatterySaver} to check for
1124      * restrictions induced by battery saver.
1125      */
areAlarmsRestricted(int uid, @NonNull String packageName)1126     public boolean areAlarmsRestricted(int uid, @NonNull String packageName) {
1127         if (isUidActive(uid)) {
1128             return false;
1129         }
1130         synchronized (mLock) {
1131             final int appId = UserHandle.getAppId(uid);
1132             if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) {
1133                 return false;
1134             }
1135             // If apps will be put into restricted standby bucket automatically on user-forced
1136             // app standby, instead of blocking alarms completely, let the restricted standby bucket
1137             // policy take care of it.
1138             return (!mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
1139                     && isRunAnyRestrictedLocked(uid, packageName));
1140         }
1141     }
1142 
1143     /**
1144      * @return whether alarms should be restricted when due to battery saver.
1145      */
areAlarmsRestrictedByBatterySaver(int uid, @NonNull String packageName)1146     public boolean areAlarmsRestrictedByBatterySaver(int uid, @NonNull String packageName) {
1147         if (isUidActive(uid)) {
1148             return false;
1149         }
1150         synchronized (mLock) {
1151             final int appId = UserHandle.getAppId(uid);
1152             if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) {
1153                 return false;
1154             }
1155             final int userId = UserHandle.getUserId(uid);
1156             if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole()
1157                     && mExemptedBucketPackages.contains(userId, packageName)) {
1158                 return false;
1159             }
1160             return mForceAllAppsStandby;
1161         }
1162     }
1163 
1164 
1165     /**
1166      * @return whether jobs should be restricted for a UID package-name. This could be due to
1167      * battery saver or user-forced app standby
1168      */
areJobsRestricted(int uid, @NonNull String packageName, boolean hasForegroundExemption)1169     public boolean areJobsRestricted(int uid, @NonNull String packageName,
1170             boolean hasForegroundExemption) {
1171         if (isUidActive(uid)) {
1172             return false;
1173         }
1174         synchronized (mLock) {
1175             final int appId = UserHandle.getAppId(uid);
1176             if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)
1177                     || ArrayUtils.contains(mTempExemptAppIds, appId)) {
1178                 return false;
1179             }
1180             // If apps will be put into restricted standby bucket automatically on user-forced
1181             // app standby, instead of blocking jobs completely, let the restricted standby bucket
1182             // policy take care of it.
1183             if (!mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
1184                     && isRunAnyRestrictedLocked(uid, packageName)) {
1185                 return true;
1186             }
1187             if (hasForegroundExemption) {
1188                 return false;
1189             }
1190             final int userId = UserHandle.getUserId(uid);
1191             if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole()
1192                     && mExemptedBucketPackages.contains(userId, packageName)) {
1193                 return false;
1194             }
1195             return mForceAllAppsStandby;
1196         }
1197     }
1198 
1199     /**
1200      * @return whether a UID is in active or not *based on cached information.*
1201      *
1202      * Note this information is based on the UID proc state callback, meaning it's updated
1203      * asynchronously and may subtly be stale. If the fresh data is needed, use
1204      * {@link #isUidActiveSynced} instead.
1205      */
isUidActive(int uid)1206     public boolean isUidActive(int uid) {
1207         if (UserHandle.isCore(uid)) {
1208             return true;
1209         }
1210         synchronized (mLock) {
1211             return mActiveUids.get(uid);
1212         }
1213     }
1214 
1215     /**
1216      * @return whether a UID is in active or not *right now.*
1217      *
1218      * This gives the fresh information, but may access the activity manager so is slower.
1219      */
isUidActiveSynced(int uid)1220     public boolean isUidActiveSynced(int uid) {
1221         if (isUidActive(uid)) { // Use the cached one first.
1222             return true;
1223         }
1224         final long start = mStatLogger.getTime();
1225 
1226         final boolean ret = mActivityManagerInternal.isUidActive(uid);
1227         mStatLogger.logDurationStat(Stats.IS_UID_ACTIVE_RAW, start);
1228 
1229         return ret;
1230     }
1231 
1232     /**
1233      * @return whether force all apps standby is enabled or not.
1234      */
isForceAllAppsStandbyEnabled()1235     public boolean isForceAllAppsStandbyEnabled() {
1236         synchronized (mLock) {
1237             return mForceAllAppsStandby;
1238         }
1239     }
1240 
1241     /**
1242      * @return whether a UID/package has {@code OP_RUN_ANY_IN_BACKGROUND} allowed or not.
1243      *
1244      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1245      */
isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName)1246     public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
1247         synchronized (mLock) {
1248             return !isRunAnyRestrictedLocked(uid, packageName);
1249         }
1250     }
1251 
1252     /**
1253      * @return whether a UID is in the user / system defined power-save exemption list or not.
1254      *
1255      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1256      */
isUidPowerSaveExempt(int uid)1257     public boolean isUidPowerSaveExempt(int uid) {
1258         synchronized (mLock) {
1259             return ArrayUtils.contains(mPowerExemptAllAppIds, UserHandle.getAppId(uid));
1260         }
1261     }
1262 
1263     /**
1264      * @param uid the uid to check for
1265      * @return whether a UID is in the user defined power-save exemption list or not.
1266      */
isUidPowerSaveUserExempt(int uid)1267     public boolean isUidPowerSaveUserExempt(int uid) {
1268         synchronized (mLock) {
1269             return ArrayUtils.contains(mPowerExemptUserAppIds, UserHandle.getAppId(uid));
1270         }
1271     }
1272 
1273     /**
1274      * @return whether a UID is in the temp power-save exemption list or not.
1275      *
1276      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1277      */
isUidTempPowerSaveExempt(int uid)1278     public boolean isUidTempPowerSaveExempt(int uid) {
1279         synchronized (mLock) {
1280             return ArrayUtils.contains(mTempExemptAppIds, UserHandle.getAppId(uid));
1281         }
1282     }
1283 
1284     /**
1285      * Dump the internal state to the given PrintWriter. Can be included in the dump
1286      * of a binder service to be output on the shell command "dumpsys".
1287      */
dump(IndentingPrintWriter pw)1288     public void dump(IndentingPrintWriter pw) {
1289         synchronized (mLock) {
1290             pw.println("Current AppStateTracker State:");
1291 
1292             pw.increaseIndent();
1293             pw.print("Force all apps standby: ");
1294             pw.println(isForceAllAppsStandbyEnabled());
1295 
1296             pw.print("Small Battery Device: ");
1297             pw.println(isSmallBatteryDevice());
1298 
1299             pw.print("Force all apps standby for small battery device: ");
1300             pw.println(mForceAllAppStandbyForSmallBattery);
1301 
1302             pw.print("Plugged In: ");
1303             pw.println(mIsPluggedIn);
1304 
1305             pw.print("Active uids: ");
1306             dumpUids(pw, mActiveUids);
1307 
1308             pw.print("Except-idle + user exemption list appids: ");
1309             pw.println(Arrays.toString(mPowerExemptAllAppIds));
1310 
1311             pw.print("User exemption list appids: ");
1312             pw.println(Arrays.toString(mPowerExemptUserAppIds));
1313 
1314             pw.print("Temp exemption list appids: ");
1315             pw.println(Arrays.toString(mTempExemptAppIds));
1316 
1317             pw.println("Exempted bucket packages:");
1318             pw.increaseIndent();
1319             for (int i = 0; i < mExemptedBucketPackages.size(); i++) {
1320                 pw.print("User ");
1321                 pw.print(mExemptedBucketPackages.keyAt(i));
1322                 pw.println();
1323 
1324                 pw.increaseIndent();
1325                 for (int j = 0; j < mExemptedBucketPackages.sizeAt(i); j++) {
1326                     pw.print(mExemptedBucketPackages.valueAt(i, j));
1327                     pw.println();
1328                 }
1329                 pw.decreaseIndent();
1330             }
1331             pw.decreaseIndent();
1332             pw.println();
1333 
1334             pw.println("Restricted packages:");
1335             pw.increaseIndent();
1336             for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
1337                 pw.print(UserHandle.formatUid(uidAndPackage.first));
1338                 pw.print(" ");
1339                 pw.print(uidAndPackage.second);
1340                 pw.println();
1341             }
1342             pw.decreaseIndent();
1343 
1344             mStatLogger.dump(pw);
1345             pw.decreaseIndent();
1346         }
1347     }
1348 
dumpUids(PrintWriter pw, SparseBooleanArray array)1349     private void dumpUids(PrintWriter pw, SparseBooleanArray array) {
1350         pw.print("[");
1351 
1352         String sep = "";
1353         for (int i = 0; i < array.size(); i++) {
1354             if (array.valueAt(i)) {
1355                 pw.print(sep);
1356                 pw.print(UserHandle.formatUid(array.keyAt(i)));
1357                 sep = " ";
1358             }
1359         }
1360         pw.println("]");
1361     }
1362 
1363     /**
1364      * Proto version of {@link #dump(IndentingPrintWriter)}
1365      */
dumpProto(ProtoOutputStream proto, long fieldId)1366     public void dumpProto(ProtoOutputStream proto, long fieldId) {
1367         synchronized (mLock) {
1368             final long token = proto.start(fieldId);
1369 
1370             proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY,
1371                     isForceAllAppsStandbyEnabled());
1372             proto.write(AppStateTrackerProto.IS_SMALL_BATTERY_DEVICE, isSmallBatteryDevice());
1373             proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
1374                     mForceAllAppStandbyForSmallBattery);
1375             proto.write(AppStateTrackerProto.IS_PLUGGED_IN, mIsPluggedIn);
1376 
1377             for (int i = 0; i < mActiveUids.size(); i++) {
1378                 if (mActiveUids.valueAt(i)) {
1379                     proto.write(AppStateTrackerProto.ACTIVE_UIDS, mActiveUids.keyAt(i));
1380                 }
1381             }
1382 
1383             for (int appId : mPowerExemptAllAppIds) {
1384                 proto.write(AppStateTrackerProto.POWER_SAVE_EXEMPT_APP_IDS, appId);
1385             }
1386 
1387             for (int appId : mPowerExemptUserAppIds) {
1388                 proto.write(AppStateTrackerProto.POWER_SAVE_USER_EXEMPT_APP_IDS, appId);
1389             }
1390 
1391             for (int appId : mTempExemptAppIds) {
1392                 proto.write(AppStateTrackerProto.TEMP_POWER_SAVE_EXEMPT_APP_IDS, appId);
1393             }
1394 
1395             for (int i = 0; i < mExemptedBucketPackages.size(); i++) {
1396                 for (int j = 0; j < mExemptedBucketPackages.sizeAt(i); j++) {
1397                     final long token2 = proto.start(AppStateTrackerProto.EXEMPTED_BUCKET_PACKAGES);
1398 
1399                     proto.write(ExemptedPackage.USER_ID, mExemptedBucketPackages.keyAt(i));
1400                     proto.write(ExemptedPackage.PACKAGE_NAME,
1401                             mExemptedBucketPackages.valueAt(i, j));
1402 
1403                     proto.end(token2);
1404                 }
1405             }
1406 
1407             for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
1408                 final long token2 = proto.start(
1409                         AppStateTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
1410                 proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
1411                 proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME,
1412                         uidAndPackage.second);
1413                 proto.end(token2);
1414             }
1415 
1416             mStatLogger.dumpProto(proto, AppStateTrackerProto.STATS);
1417 
1418             proto.end(token);
1419         }
1420     }
1421 }
1422