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 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
448             switch (intent.getAction()) {
449                 case Intent.ACTION_USER_REMOVED:
450                     if (userId > 0) {
451                         mHandler.doUserRemoved(userId);
452                     }
453                     break;
454                 case Intent.ACTION_BATTERY_CHANGED:
455                     synchronized (mLock) {
456                         mIsPluggedIn = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
457                     }
458                     updateForceAllAppStandbyState();
459                     break;
460                 case Intent.ACTION_PACKAGE_REMOVED:
461                     if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
462                         final String pkgName = intent.getData().getSchemeSpecificPart();
463                         final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
464                         // No need to notify for state change as all the alarms and jobs should be
465                         // removed too.
466                         synchronized (mLock) {
467                             mExemptedBucketPackages.remove(userId, pkgName);
468                             mRunAnyRestrictedPackages.remove(Pair.create(uid, pkgName));
469                             updateBackgroundRestrictedUidPackagesLocked();
470                             mActiveUids.delete(uid);
471                         }
472                     }
473                     break;
474             }
475         }
476     };
477 
478     /**
479      * Call it when the system is ready.
480      */
onSystemServicesReady()481     public void onSystemServicesReady() {
482         synchronized (mLock) {
483             if (mStarted) {
484                 return;
485             }
486             mStarted = true;
487 
488             mIActivityManager = Objects.requireNonNull(injectIActivityManager());
489             mActivityManagerInternal = Objects.requireNonNull(injectActivityManagerInternal());
490             mAppOpsManager = Objects.requireNonNull(injectAppOpsManager());
491             mAppOpsService = Objects.requireNonNull(injectIAppOpsService());
492             mPowerManagerInternal = Objects.requireNonNull(injectPowerManagerInternal());
493             mAppStandbyInternal = Objects.requireNonNull(injectAppStandbyInternal());
494 
495             mFlagsObserver = new FeatureFlagsObserver();
496             mFlagsObserver.register();
497             mForceAllAppStandbyForSmallBattery =
498                     mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled();
499             mStandbyTracker = new StandbyTracker();
500             mAppStandbyInternal.addListener(mStandbyTracker);
501             mActivityManagerInternal.addAppBackgroundRestrictionListener(
502                     mAppBackgroundRestrictionListener);
503 
504             try {
505                 mIActivityManager.registerUidObserver(new UidObserver(),
506                         ActivityManager.UID_OBSERVER_GONE
507                                 | ActivityManager.UID_OBSERVER_IDLE
508                                 | ActivityManager.UID_OBSERVER_ACTIVE
509                                 | ActivityManager.UID_OBSERVER_CACHED,
510                         ActivityManager.PROCESS_STATE_UNKNOWN, null);
511                 mAppOpsService.startWatchingMode(TARGET_OP, null,
512                         new AppOpsWatcher());
513             } catch (RemoteException e) {
514                 // shouldn't happen.
515             }
516 
517             IntentFilter filter = new IntentFilter();
518             filter.addAction(Intent.ACTION_USER_REMOVED);
519             filter.addAction(Intent.ACTION_BATTERY_CHANGED);
520             mContext.registerReceiver(mReceiver, filter);
521 
522             filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
523             filter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
524             mContext.registerReceiver(mReceiver, filter);
525 
526             refreshForcedAppStandbyUidPackagesLocked();
527 
528             mPowerManagerInternal.registerLowPowerModeObserver(
529                     ServiceType.FORCE_ALL_APPS_STANDBY,
530                     (state) -> {
531                         synchronized (mLock) {
532                             mBatterySaverEnabled = state.batterySaverEnabled;
533                             updateForceAllAppStandbyState();
534                         }
535                     });
536 
537             mBatterySaverEnabled = mPowerManagerInternal.getLowPowerState(
538                     ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled;
539 
540             updateForceAllAppStandbyState();
541         }
542     }
543 
544     @VisibleForTesting
injectAppOpsManager()545     AppOpsManager injectAppOpsManager() {
546         return mContext.getSystemService(AppOpsManager.class);
547     }
548 
549     @VisibleForTesting
injectIAppOpsService()550     IAppOpsService injectIAppOpsService() {
551         return IAppOpsService.Stub.asInterface(
552                 ServiceManager.getService(Context.APP_OPS_SERVICE));
553     }
554 
555     @VisibleForTesting
injectIActivityManager()556     IActivityManager injectIActivityManager() {
557         return ActivityManager.getService();
558     }
559 
560     @VisibleForTesting
injectActivityManagerInternal()561     ActivityManagerInternal injectActivityManagerInternal() {
562         return LocalServices.getService(ActivityManagerInternal.class);
563     }
564 
565     @VisibleForTesting
injectPowerManagerInternal()566     PowerManagerInternal injectPowerManagerInternal() {
567         return LocalServices.getService(PowerManagerInternal.class);
568     }
569 
570     @VisibleForTesting
injectAppStandbyInternal()571     AppStandbyInternal injectAppStandbyInternal() {
572         return LocalServices.getService(AppStandbyInternal.class);
573     }
574 
575     @VisibleForTesting
isSmallBatteryDevice()576     boolean isSmallBatteryDevice() {
577         return ActivityManager.isSmallBatteryDevice();
578     }
579 
580     @VisibleForTesting
injectGetGlobalSettingInt(String key, int def)581     int injectGetGlobalSettingInt(String key, int def) {
582         return Settings.Global.getInt(mContext.getContentResolver(), key, def);
583     }
584 
585     /**
586      * Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
587      */
588     @GuardedBy("mLock")
refreshForcedAppStandbyUidPackagesLocked()589     private void refreshForcedAppStandbyUidPackagesLocked() {
590         mRunAnyRestrictedPackages.clear();
591         final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(
592                 new int[] {TARGET_OP});
593 
594         if (ops == null) {
595             return;
596         }
597         final int size = ops.size();
598         for (int i = 0; i < size; i++) {
599             final AppOpsManager.PackageOps pkg = ops.get(i);
600             final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
601 
602             for (int j = 0; j < entries.size(); j++) {
603                 AppOpsManager.OpEntry ent = entries.get(j);
604                 if (ent.getOp() != TARGET_OP) {
605                     continue;
606                 }
607                 if (ent.getMode() != AppOpsManager.MODE_ALLOWED) {
608                     mRunAnyRestrictedPackages.add(Pair.create(
609                             pkg.getUid(), pkg.getPackageName()));
610                 }
611             }
612         }
613         updateBackgroundRestrictedUidPackagesLocked();
614     }
615 
616     /**
617      * Update the {@link #mBackgroundRestrictedUidPackages} upon mutations on
618      * {@link #mRunAnyRestrictedPackages}.
619      */
620     @GuardedBy("mLock")
updateBackgroundRestrictedUidPackagesLocked()621     private void updateBackgroundRestrictedUidPackagesLocked() {
622         Set<Pair<Integer, String>> fasUidPkgs = new ArraySet<>();
623         for (int i = 0, size = mRunAnyRestrictedPackages.size(); i < size; i++) {
624             fasUidPkgs.add(mRunAnyRestrictedPackages.valueAt(i));
625         }
626         mBackgroundRestrictedUidPackages = Collections.unmodifiableSet(fasUidPkgs);
627     }
628 
updateForceAllAppStandbyState()629     private void updateForceAllAppStandbyState() {
630         synchronized (mLock) {
631             if (mForceAllAppStandbyForSmallBattery && isSmallBatteryDevice()) {
632                 toggleForceAllAppsStandbyLocked(!mIsPluggedIn);
633             } else {
634                 toggleForceAllAppsStandbyLocked(mBatterySaverEnabled);
635             }
636         }
637     }
638 
639     /**
640      * Update {@link #mForceAllAppsStandby} and notifies the listeners.
641      */
642     @GuardedBy("mLock")
toggleForceAllAppsStandbyLocked(boolean enable)643     private void toggleForceAllAppsStandbyLocked(boolean enable) {
644         if (enable == mForceAllAppsStandby) {
645             return;
646         }
647         mForceAllAppsStandby = enable;
648 
649         mHandler.notifyForceAllAppsStandbyChanged();
650     }
651 
652     @GuardedBy("mLock")
findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName)653     private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
654         final int size = mRunAnyRestrictedPackages.size();
655         if (size > 8) {
656             return mRunAnyRestrictedPackages.indexOf(Pair.create(uid, packageName));
657         }
658         for (int i = 0; i < size; i++) {
659             final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
660 
661             if ((pair.first == uid) && packageName.equals(pair.second)) {
662                 return i;
663             }
664         }
665         return -1;
666     }
667 
668     /**
669      * @return whether a uid package-name pair is in mRunAnyRestrictedPackages.
670      */
671     @GuardedBy("mLock")
isRunAnyRestrictedLocked(int uid, @NonNull String packageName)672     boolean isRunAnyRestrictedLocked(int uid, @NonNull String packageName) {
673         return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0;
674     }
675 
676     /**
677      * Add to / remove from {@link #mRunAnyRestrictedPackages}.
678      */
679     @GuardedBy("mLock")
updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName, boolean restricted)680     boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName,
681             boolean restricted) {
682         final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
683         final boolean wasRestricted = index >= 0;
684         if (wasRestricted == restricted) {
685             return false;
686         }
687         if (restricted) {
688             mRunAnyRestrictedPackages.add(Pair.create(uid, packageName));
689         } else {
690             mRunAnyRestrictedPackages.removeAt(index);
691         }
692         updateBackgroundRestrictedUidPackagesLocked();
693         return true;
694     }
695 
addUidToArray(SparseBooleanArray array, int uid)696     private static boolean addUidToArray(SparseBooleanArray array, int uid) {
697         if (UserHandle.isCore(uid)) {
698             return false;
699         }
700         if (array.get(uid)) {
701             return false;
702         }
703         array.put(uid, true);
704         return true;
705     }
706 
removeUidFromArray(SparseBooleanArray array, int uid, boolean remove)707     private static boolean removeUidFromArray(SparseBooleanArray array, int uid, boolean remove) {
708         if (UserHandle.isCore(uid)) {
709             return false;
710         }
711         if (!array.get(uid)) {
712             return false;
713         }
714         if (remove) {
715             array.delete(uid);
716         } else {
717             array.put(uid, false);
718         }
719         return true;
720     }
721 
722     private final class UidObserver extends android.app.UidObserver {
723         @Override
onUidActive(int uid)724         public void onUidActive(int uid) {
725             mHandler.onUidActive(uid);
726         }
727 
728         @Override
onUidGone(int uid, boolean disabled)729         public void onUidGone(int uid, boolean disabled) {
730             mHandler.onUidGone(uid, disabled);
731         }
732 
733         @Override
onUidIdle(int uid, boolean disabled)734         public void onUidIdle(int uid, boolean disabled) {
735             mHandler.onUidIdle(uid, disabled);
736         }
737 
738         @Override
onUidCachedChanged(int uid, boolean cached)739         public void onUidCachedChanged(int uid, boolean cached) {
740             mHandler.onUidCachedChanged(uid, cached);
741         }
742     }
743 
744     private final class AppOpsWatcher extends IAppOpsCallback.Stub {
745         @Override
opChanged(int op, int uid, String packageName)746         public void opChanged(int op, int uid, String packageName) throws RemoteException {
747             boolean restricted = false;
748             try {
749                 restricted = mAppOpsService.checkOperation(TARGET_OP,
750                         uid, packageName) != AppOpsManager.MODE_ALLOWED;
751             } catch (RemoteException e) {
752                 // Shouldn't happen
753             }
754             if (restricted) {
755                 Counter.logIncrementWithUid(APP_RESTRICTION_COUNTER_METRIC_ID, uid);
756             }
757             synchronized (mLock) {
758                 if (updateForcedAppStandbyUidPackageLocked(uid, packageName, restricted)) {
759                     mHandler.notifyRunAnyAppOpsChanged(uid, packageName);
760                 }
761             }
762         }
763     }
764 
765     final class StandbyTracker extends AppIdleStateChangeListener {
766         @Override
onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason)767         public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
768                 int bucket, int reason) {
769             if (DEBUG) {
770                 Slog.d(TAG, "onAppIdleStateChanged: " + packageName + " u" + userId
771                         + (idle ? " idle" : " active") + " " + bucket);
772             }
773             synchronized (mLock) {
774                 final boolean changed;
775                 if (bucket == UsageStatsManager.STANDBY_BUCKET_EXEMPTED) {
776                     changed = mExemptedBucketPackages.add(userId, packageName);
777                 } else {
778                     changed = mExemptedBucketPackages.remove(userId, packageName);
779                 }
780                 if (changed) {
781                     mHandler.notifyExemptedBucketChanged();
782                 }
783             }
784         }
785     }
786 
cloneListeners()787     private Listener[] cloneListeners() {
788         synchronized (mLock) {
789             return mListeners.toArray(new Listener[mListeners.size()]);
790         }
791     }
792 
793     private class MyHandler extends Handler {
794         private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0;
795         // Unused ids 1, 2.
796         private static final int MSG_RUN_ANY_CHANGED = 3;
797         private static final int MSG_ALL_UNEXEMPTED = 4;
798         private static final int MSG_ALL_EXEMPTION_LIST_CHANGED = 5;
799         private static final int MSG_TEMP_EXEMPTION_LIST_CHANGED = 6;
800         private static final int MSG_FORCE_ALL_CHANGED = 7;
801         private static final int MSG_USER_REMOVED = 8;
802         // Unused id 9.
803         private static final int MSG_EXEMPTED_BUCKET_CHANGED = 10;
804         private static final int MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED = 11;
805 
806         private static final int MSG_ON_UID_ACTIVE = 12;
807         private static final int MSG_ON_UID_GONE = 13;
808         private static final int MSG_ON_UID_IDLE = 14;
809         private static final int MSG_ON_UID_CACHED = 15;
810 
MyHandler(Looper looper)811         MyHandler(Looper looper) {
812             super(looper);
813         }
814 
notifyUidActiveStateChanged(int uid)815         public void notifyUidActiveStateChanged(int uid) {
816             obtainMessage(MSG_UID_ACTIVE_STATE_CHANGED, uid, 0).sendToTarget();
817         }
818 
notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName)819         public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
820             obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
821         }
822 
notifyAllUnexempted()823         public void notifyAllUnexempted() {
824             removeMessages(MSG_ALL_UNEXEMPTED);
825             obtainMessage(MSG_ALL_UNEXEMPTED).sendToTarget();
826         }
827 
notifyAllExemptionListChanged()828         public void notifyAllExemptionListChanged() {
829             removeMessages(MSG_ALL_EXEMPTION_LIST_CHANGED);
830             obtainMessage(MSG_ALL_EXEMPTION_LIST_CHANGED).sendToTarget();
831         }
832 
notifyTempExemptionListChanged()833         public void notifyTempExemptionListChanged() {
834             removeMessages(MSG_TEMP_EXEMPTION_LIST_CHANGED);
835             obtainMessage(MSG_TEMP_EXEMPTION_LIST_CHANGED).sendToTarget();
836         }
837 
notifyForceAllAppsStandbyChanged()838         public void notifyForceAllAppsStandbyChanged() {
839             removeMessages(MSG_FORCE_ALL_CHANGED);
840             obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
841         }
842 
notifyExemptedBucketChanged()843         public void notifyExemptedBucketChanged() {
844             removeMessages(MSG_EXEMPTED_BUCKET_CHANGED);
845             obtainMessage(MSG_EXEMPTED_BUCKET_CHANGED).sendToTarget();
846         }
847 
notifyAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket)848         public void notifyAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket) {
849             removeMessages(MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED);
850             obtainMessage(MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED,
851                     autoRestrictedBucket ? 1 : 0, 0).sendToTarget();
852         }
853 
doUserRemoved(int userId)854         public void doUserRemoved(int userId) {
855             obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
856         }
857 
onUidActive(int uid)858         public void onUidActive(int uid) {
859             obtainMessage(MSG_ON_UID_ACTIVE, uid, 0).sendToTarget();
860         }
861 
onUidGone(int uid, boolean disabled)862         public void onUidGone(int uid, boolean disabled) {
863             obtainMessage(MSG_ON_UID_GONE, uid, disabled ? 1 : 0).sendToTarget();
864         }
865 
onUidIdle(int uid, boolean disabled)866         public void onUidIdle(int uid, boolean disabled) {
867             obtainMessage(MSG_ON_UID_IDLE, uid, disabled ? 1 : 0).sendToTarget();
868         }
869 
onUidCachedChanged(int uid, boolean cached)870         public void onUidCachedChanged(int uid, boolean cached) {
871             obtainMessage(MSG_ON_UID_CACHED, uid, cached ? 1 : 0).sendToTarget();
872         }
873 
874         @Override
handleMessage(Message msg)875         public void handleMessage(Message msg) {
876             switch (msg.what) {
877                 case MSG_USER_REMOVED:
878                     handleUserRemoved(msg.arg1);
879                     return;
880             }
881 
882             // Only notify the listeners when started.
883             synchronized (mLock) {
884                 if (!mStarted) {
885                     return;
886                 }
887             }
888             final AppStateTrackerImpl sender = AppStateTrackerImpl.this;
889 
890             long start = mStatLogger.getTime();
891             switch (msg.what) {
892                 case MSG_UID_ACTIVE_STATE_CHANGED:
893                     for (Listener l : cloneListeners()) {
894                         l.onUidActiveStateChanged(sender, msg.arg1);
895                     }
896                     mStatLogger.logDurationStat(Stats.UID_ACTIVE_STATE_CHANGED, start);
897                     return;
898 
899                 case MSG_RUN_ANY_CHANGED:
900                     for (Listener l : cloneListeners()) {
901                         l.onRunAnyAppOpsChanged(sender, msg.arg1, (String) msg.obj);
902                     }
903                     mStatLogger.logDurationStat(Stats.RUN_ANY_CHANGED, start);
904                     return;
905 
906                 case MSG_ALL_UNEXEMPTED:
907                     for (Listener l : cloneListeners()) {
908                         l.onPowerSaveUnexempted(sender);
909                     }
910                     mStatLogger.logDurationStat(Stats.ALL_UNEXEMPTED, start);
911                     return;
912 
913                 case MSG_ALL_EXEMPTION_LIST_CHANGED:
914                     for (Listener l : cloneListeners()) {
915                         l.onPowerSaveExemptionListChanged(sender);
916                     }
917                     mStatLogger.logDurationStat(Stats.ALL_EXEMPTION_LIST_CHANGED, start);
918                     return;
919 
920                 case MSG_TEMP_EXEMPTION_LIST_CHANGED:
921                     for (Listener l : cloneListeners()) {
922                         l.onTempPowerSaveExemptionListChanged(sender);
923                     }
924                     mStatLogger.logDurationStat(Stats.TEMP_EXEMPTION_LIST_CHANGED, start);
925                     return;
926 
927                 case MSG_EXEMPTED_BUCKET_CHANGED:
928                     for (Listener l : cloneListeners()) {
929                         l.onExemptedBucketChanged(sender);
930                     }
931                     mStatLogger.logDurationStat(Stats.EXEMPTED_BUCKET_CHANGED, start);
932                     return;
933 
934                 case MSG_FORCE_ALL_CHANGED:
935                     for (Listener l : cloneListeners()) {
936                         l.onForceAllAppsStandbyChanged(sender);
937                     }
938                     mStatLogger.logDurationStat(Stats.FORCE_ALL_CHANGED, start);
939                     return;
940 
941                 case MSG_USER_REMOVED:
942                     handleUserRemoved(msg.arg1);
943                     return;
944 
945                 case MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED:
946                     final boolean autoRestrictedBucket = msg.arg1 == 1;
947                     for (Listener l : cloneListeners()) {
948                         l.onAutoRestrictedBucketFeatureFlagChanged(sender, autoRestrictedBucket);
949                     }
950                     return;
951 
952                 case MSG_ON_UID_ACTIVE:
953                     handleUidActive(msg.arg1);
954                     return;
955                 case MSG_ON_UID_GONE:
956                     handleUidGone(msg.arg1);
957                     if (msg.arg2 != 0) {
958                         handleUidDisabled(msg.arg1);
959                     }
960                     return;
961                 case MSG_ON_UID_IDLE:
962                     handleUidIdle(msg.arg1);
963                     if (msg.arg2 != 0) {
964                         handleUidDisabled(msg.arg1);
965                     }
966                     return;
967                 case MSG_ON_UID_CACHED:
968                     handleUidCached(msg.arg1, (msg.arg2 != 0));
969                     return;
970             }
971         }
972 
handleUidCached(int uid, boolean cached)973         private void handleUidCached(int uid, boolean cached) {
974             for (Listener l : cloneListeners()) {
975                 l.handleUidCachedChanged(uid, cached);
976             }
977         }
978 
handleUidDisabled(int uid)979         private void handleUidDisabled(int uid) {
980             for (Listener l : cloneListeners()) {
981                 l.removeAlarmsForUid(uid);
982             }
983         }
984 
handleUidActive(int uid)985         public void handleUidActive(int uid) {
986             synchronized (mLock) {
987                 if (addUidToArray(mActiveUids, uid)) {
988                     mHandler.notifyUidActiveStateChanged(uid);
989                 }
990             }
991         }
992 
handleUidGone(int uid)993         public void handleUidGone(int uid) {
994             removeUid(uid, true);
995         }
996 
handleUidIdle(int uid)997         public void handleUidIdle(int uid) {
998             // Just to avoid excessive memcpy, don't remove from the array in this case.
999             removeUid(uid, false);
1000         }
1001 
removeUid(int uid, boolean remove)1002         private void removeUid(int uid, boolean remove) {
1003             synchronized (mLock) {
1004                 if (removeUidFromArray(mActiveUids, uid, remove)) {
1005                     mHandler.notifyUidActiveStateChanged(uid);
1006                 }
1007             }
1008         }
1009     }
1010 
handleUserRemoved(int removedUserId)1011     void handleUserRemoved(int removedUserId) {
1012         synchronized (mLock) {
1013             for (int i = mRunAnyRestrictedPackages.size() - 1; i >= 0; i--) {
1014                 final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
1015                 final int uid = pair.first;
1016                 final int userId = UserHandle.getUserId(uid);
1017 
1018                 if (userId == removedUserId) {
1019                     mRunAnyRestrictedPackages.removeAt(i);
1020                 }
1021             }
1022             updateBackgroundRestrictedUidPackagesLocked();
1023             cleanUpArrayForUser(mActiveUids, removedUserId);
1024             mExemptedBucketPackages.remove(removedUserId);
1025         }
1026     }
1027 
cleanUpArrayForUser(SparseBooleanArray array, int removedUserId)1028     private void cleanUpArrayForUser(SparseBooleanArray array, int removedUserId) {
1029         for (int i = array.size() - 1; i >= 0; i--) {
1030             final int uid = array.keyAt(i);
1031             final int userId = UserHandle.getUserId(uid);
1032 
1033             if (userId == removedUserId) {
1034                 array.removeAt(i);
1035             }
1036         }
1037     }
1038 
1039     /**
1040      * Called by device idle controller to update the power save exemption lists.
1041      */
setPowerSaveExemptionListAppIds( int[] powerSaveExemptionListExceptIdleAppIdArray, int[] powerSaveExemptionListUserAppIdArray, int[] tempExemptionListAppIdArray)1042     public void setPowerSaveExemptionListAppIds(
1043             int[] powerSaveExemptionListExceptIdleAppIdArray,
1044             int[] powerSaveExemptionListUserAppIdArray,
1045             int[] tempExemptionListAppIdArray) {
1046         synchronized (mLock) {
1047             final int[] previousExemptionList = mPowerExemptAllAppIds;
1048             final int[] previousTempExemptionList = mTempExemptAppIds;
1049 
1050             mPowerExemptAllAppIds = powerSaveExemptionListExceptIdleAppIdArray;
1051             mTempExemptAppIds = tempExemptionListAppIdArray;
1052             mPowerExemptUserAppIds = powerSaveExemptionListUserAppIdArray;
1053 
1054             if (isAnyAppIdUnexempt(previousExemptionList, mPowerExemptAllAppIds)) {
1055                 mHandler.notifyAllUnexempted();
1056             } else if (!Arrays.equals(previousExemptionList, mPowerExemptAllAppIds)) {
1057                 mHandler.notifyAllExemptionListChanged();
1058             }
1059 
1060             if (!Arrays.equals(previousTempExemptionList, mTempExemptAppIds)) {
1061                 mHandler.notifyTempExemptionListChanged();
1062             }
1063 
1064         }
1065     }
1066 
1067     /**
1068      * @return true if a sorted app-id array {@code prevArray} has at least one element
1069      * that's not in a sorted app-id array {@code newArray}.
1070      */
1071     @VisibleForTesting
isAnyAppIdUnexempt(int[] prevArray, int[] newArray)1072     static boolean isAnyAppIdUnexempt(int[] prevArray, int[] newArray) {
1073         int i1 = 0;
1074         int i2 = 0;
1075         boolean prevFinished;
1076         boolean newFinished;
1077 
1078         for (;;) {
1079             prevFinished = i1 >= prevArray.length;
1080             newFinished = i2 >= newArray.length;
1081             if (prevFinished || newFinished) {
1082                 break;
1083             }
1084             int a1 = prevArray[i1];
1085             int a2 = newArray[i2];
1086 
1087             if (a1 == a2) {
1088                 i1++;
1089                 i2++;
1090                 continue;
1091             }
1092             if (a1 < a2) {
1093                 // prevArray has an element that's not in a2.
1094                 return true;
1095             }
1096             i2++;
1097         }
1098         if (prevFinished) {
1099             return false;
1100         }
1101         return newFinished;
1102     }
1103 
1104     // Public interface.
1105 
1106     /**
1107      * Register a listener to get callbacks when any state changes.
1108      */
addListener(@onNull Listener listener)1109     public void addListener(@NonNull Listener listener) {
1110         synchronized (mLock) {
1111             mListeners.add(listener);
1112         }
1113     }
1114 
1115     /**
1116      * @return whether alarms should be restricted for a UID package-name, due to explicit
1117      * user-forced app standby. Use {{@link #areAlarmsRestrictedByBatterySaver} to check for
1118      * restrictions induced by battery saver.
1119      */
areAlarmsRestricted(int uid, @NonNull String packageName)1120     public boolean areAlarmsRestricted(int uid, @NonNull String packageName) {
1121         if (isUidActive(uid)) {
1122             return false;
1123         }
1124         synchronized (mLock) {
1125             final int appId = UserHandle.getAppId(uid);
1126             if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) {
1127                 return false;
1128             }
1129             // If apps will be put into restricted standby bucket automatically on user-forced
1130             // app standby, instead of blocking alarms completely, let the restricted standby bucket
1131             // policy take care of it.
1132             return (!mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
1133                     && isRunAnyRestrictedLocked(uid, packageName));
1134         }
1135     }
1136 
1137     /**
1138      * @return whether alarms should be restricted when due to battery saver.
1139      */
areAlarmsRestrictedByBatterySaver(int uid, @NonNull String packageName)1140     public boolean areAlarmsRestrictedByBatterySaver(int uid, @NonNull String packageName) {
1141         if (isUidActive(uid)) {
1142             return false;
1143         }
1144         synchronized (mLock) {
1145             final int appId = UserHandle.getAppId(uid);
1146             if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) {
1147                 return false;
1148             }
1149             final int userId = UserHandle.getUserId(uid);
1150             if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole()
1151                     && mExemptedBucketPackages.contains(userId, packageName)) {
1152                 return false;
1153             }
1154             return mForceAllAppsStandby;
1155         }
1156     }
1157 
1158 
1159     /**
1160      * @return whether jobs should be restricted for a UID package-name. This could be due to
1161      * battery saver or user-forced app standby
1162      */
areJobsRestricted(int uid, @NonNull String packageName, boolean hasForegroundExemption)1163     public boolean areJobsRestricted(int uid, @NonNull String packageName,
1164             boolean hasForegroundExemption) {
1165         if (isUidActive(uid)) {
1166             return false;
1167         }
1168         synchronized (mLock) {
1169             final int appId = UserHandle.getAppId(uid);
1170             if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)
1171                     || ArrayUtils.contains(mTempExemptAppIds, appId)) {
1172                 return false;
1173             }
1174             // If apps will be put into restricted standby bucket automatically on user-forced
1175             // app standby, instead of blocking jobs completely, let the restricted standby bucket
1176             // policy take care of it.
1177             if (!mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
1178                     && isRunAnyRestrictedLocked(uid, packageName)) {
1179                 return true;
1180             }
1181             if (hasForegroundExemption) {
1182                 return false;
1183             }
1184             final int userId = UserHandle.getUserId(uid);
1185             if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole()
1186                     && mExemptedBucketPackages.contains(userId, packageName)) {
1187                 return false;
1188             }
1189             return mForceAllAppsStandby;
1190         }
1191     }
1192 
1193     /**
1194      * @return whether a UID is in active or not *based on cached information.*
1195      *
1196      * Note this information is based on the UID proc state callback, meaning it's updated
1197      * asynchronously and may subtly be stale. If the fresh data is needed, use
1198      * {@link #isUidActiveSynced} instead.
1199      */
isUidActive(int uid)1200     public boolean isUidActive(int uid) {
1201         if (UserHandle.isCore(uid)) {
1202             return true;
1203         }
1204         synchronized (mLock) {
1205             return mActiveUids.get(uid);
1206         }
1207     }
1208 
1209     /**
1210      * @return whether a UID is in active or not *right now.*
1211      *
1212      * This gives the fresh information, but may access the activity manager so is slower.
1213      */
isUidActiveSynced(int uid)1214     public boolean isUidActiveSynced(int uid) {
1215         if (isUidActive(uid)) { // Use the cached one first.
1216             return true;
1217         }
1218         final long start = mStatLogger.getTime();
1219 
1220         final boolean ret = mActivityManagerInternal.isUidActive(uid);
1221         mStatLogger.logDurationStat(Stats.IS_UID_ACTIVE_RAW, start);
1222 
1223         return ret;
1224     }
1225 
1226     /**
1227      * @return whether force all apps standby is enabled or not.
1228      */
isForceAllAppsStandbyEnabled()1229     public boolean isForceAllAppsStandbyEnabled() {
1230         synchronized (mLock) {
1231             return mForceAllAppsStandby;
1232         }
1233     }
1234 
1235     /**
1236      * @return whether a UID/package has {@code OP_RUN_ANY_IN_BACKGROUND} allowed or not.
1237      *
1238      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1239      */
isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName)1240     public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
1241         synchronized (mLock) {
1242             return !isRunAnyRestrictedLocked(uid, packageName);
1243         }
1244     }
1245 
1246     /**
1247      * @return whether a UID is in the user / system defined power-save exemption list or not.
1248      *
1249      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1250      */
isUidPowerSaveExempt(int uid)1251     public boolean isUidPowerSaveExempt(int uid) {
1252         synchronized (mLock) {
1253             return ArrayUtils.contains(mPowerExemptAllAppIds, UserHandle.getAppId(uid));
1254         }
1255     }
1256 
1257     /**
1258      * @param uid the uid to check for
1259      * @return whether a UID is in the user defined power-save exemption list or not.
1260      */
isUidPowerSaveUserExempt(int uid)1261     public boolean isUidPowerSaveUserExempt(int uid) {
1262         synchronized (mLock) {
1263             return ArrayUtils.contains(mPowerExemptUserAppIds, UserHandle.getAppId(uid));
1264         }
1265     }
1266 
1267     /**
1268      * @return whether a UID is in the temp power-save exemption list or not.
1269      *
1270      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1271      */
isUidTempPowerSaveExempt(int uid)1272     public boolean isUidTempPowerSaveExempt(int uid) {
1273         synchronized (mLock) {
1274             return ArrayUtils.contains(mTempExemptAppIds, UserHandle.getAppId(uid));
1275         }
1276     }
1277 
1278     /**
1279      * Dump the internal state to the given PrintWriter. Can be included in the dump
1280      * of a binder service to be output on the shell command "dumpsys".
1281      */
dump(IndentingPrintWriter pw)1282     public void dump(IndentingPrintWriter pw) {
1283         synchronized (mLock) {
1284             pw.println("Current AppStateTracker State:");
1285 
1286             pw.increaseIndent();
1287             pw.print("Force all apps standby: ");
1288             pw.println(isForceAllAppsStandbyEnabled());
1289 
1290             pw.print("Small Battery Device: ");
1291             pw.println(isSmallBatteryDevice());
1292 
1293             pw.print("Force all apps standby for small battery device: ");
1294             pw.println(mForceAllAppStandbyForSmallBattery);
1295 
1296             pw.print("Plugged In: ");
1297             pw.println(mIsPluggedIn);
1298 
1299             pw.print("Active uids: ");
1300             dumpUids(pw, mActiveUids);
1301 
1302             pw.print("Except-idle + user exemption list appids: ");
1303             pw.println(Arrays.toString(mPowerExemptAllAppIds));
1304 
1305             pw.print("User exemption list appids: ");
1306             pw.println(Arrays.toString(mPowerExemptUserAppIds));
1307 
1308             pw.print("Temp exemption list appids: ");
1309             pw.println(Arrays.toString(mTempExemptAppIds));
1310 
1311             pw.println("Exempted bucket packages:");
1312             pw.increaseIndent();
1313             for (int i = 0; i < mExemptedBucketPackages.size(); i++) {
1314                 pw.print("User ");
1315                 pw.print(mExemptedBucketPackages.keyAt(i));
1316                 pw.println();
1317 
1318                 pw.increaseIndent();
1319                 for (int j = 0; j < mExemptedBucketPackages.sizeAt(i); j++) {
1320                     pw.print(mExemptedBucketPackages.valueAt(i, j));
1321                     pw.println();
1322                 }
1323                 pw.decreaseIndent();
1324             }
1325             pw.decreaseIndent();
1326             pw.println();
1327 
1328             pw.println("Restricted packages:");
1329             pw.increaseIndent();
1330             for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
1331                 pw.print(UserHandle.formatUid(uidAndPackage.first));
1332                 pw.print(" ");
1333                 pw.print(uidAndPackage.second);
1334                 pw.println();
1335             }
1336             pw.decreaseIndent();
1337 
1338             mStatLogger.dump(pw);
1339             pw.decreaseIndent();
1340         }
1341     }
1342 
dumpUids(PrintWriter pw, SparseBooleanArray array)1343     private void dumpUids(PrintWriter pw, SparseBooleanArray array) {
1344         pw.print("[");
1345 
1346         String sep = "";
1347         for (int i = 0; i < array.size(); i++) {
1348             if (array.valueAt(i)) {
1349                 pw.print(sep);
1350                 pw.print(UserHandle.formatUid(array.keyAt(i)));
1351                 sep = " ";
1352             }
1353         }
1354         pw.println("]");
1355     }
1356 
1357     /**
1358      * Proto version of {@link #dump(IndentingPrintWriter)}
1359      */
dumpProto(ProtoOutputStream proto, long fieldId)1360     public void dumpProto(ProtoOutputStream proto, long fieldId) {
1361         synchronized (mLock) {
1362             final long token = proto.start(fieldId);
1363 
1364             proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY,
1365                     isForceAllAppsStandbyEnabled());
1366             proto.write(AppStateTrackerProto.IS_SMALL_BATTERY_DEVICE, isSmallBatteryDevice());
1367             proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
1368                     mForceAllAppStandbyForSmallBattery);
1369             proto.write(AppStateTrackerProto.IS_PLUGGED_IN, mIsPluggedIn);
1370 
1371             for (int i = 0; i < mActiveUids.size(); i++) {
1372                 if (mActiveUids.valueAt(i)) {
1373                     proto.write(AppStateTrackerProto.ACTIVE_UIDS, mActiveUids.keyAt(i));
1374                 }
1375             }
1376 
1377             for (int appId : mPowerExemptAllAppIds) {
1378                 proto.write(AppStateTrackerProto.POWER_SAVE_EXEMPT_APP_IDS, appId);
1379             }
1380 
1381             for (int appId : mPowerExemptUserAppIds) {
1382                 proto.write(AppStateTrackerProto.POWER_SAVE_USER_EXEMPT_APP_IDS, appId);
1383             }
1384 
1385             for (int appId : mTempExemptAppIds) {
1386                 proto.write(AppStateTrackerProto.TEMP_POWER_SAVE_EXEMPT_APP_IDS, appId);
1387             }
1388 
1389             for (int i = 0; i < mExemptedBucketPackages.size(); i++) {
1390                 for (int j = 0; j < mExemptedBucketPackages.sizeAt(i); j++) {
1391                     final long token2 = proto.start(AppStateTrackerProto.EXEMPTED_BUCKET_PACKAGES);
1392 
1393                     proto.write(ExemptedPackage.USER_ID, mExemptedBucketPackages.keyAt(i));
1394                     proto.write(ExemptedPackage.PACKAGE_NAME,
1395                             mExemptedBucketPackages.valueAt(i, j));
1396 
1397                     proto.end(token2);
1398                 }
1399             }
1400 
1401             for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
1402                 final long token2 = proto.start(
1403                         AppStateTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
1404                 proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
1405                 proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME,
1406                         uidAndPackage.second);
1407                 proto.end(token2);
1408             }
1409 
1410             mStatLogger.dumpProto(proto, AppStateTrackerProto.STATS);
1411 
1412             proto.end(token);
1413         }
1414     }
1415 }
1416