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, String persistentDeviceId)746         public void opChanged(int op, int uid, String packageName,
747                 String persistentDeviceId) throws RemoteException {
748             boolean restricted = false;
749             try {
750                 restricted = mAppOpsService.checkOperation(TARGET_OP,
751                         uid, packageName) != AppOpsManager.MODE_ALLOWED;
752             } catch (RemoteException e) {
753                 // Shouldn't happen
754             }
755             if (restricted) {
756                 Counter.logIncrementWithUid(APP_RESTRICTION_COUNTER_METRIC_ID, uid);
757             }
758             synchronized (mLock) {
759                 if (updateForcedAppStandbyUidPackageLocked(uid, packageName, restricted)) {
760                     mHandler.notifyRunAnyAppOpsChanged(uid, packageName);
761                 }
762             }
763         }
764     }
765 
766     final class StandbyTracker extends AppIdleStateChangeListener {
767         @Override
onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason)768         public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
769                 int bucket, int reason) {
770             if (DEBUG) {
771                 Slog.d(TAG, "onAppIdleStateChanged: " + packageName + " u" + userId
772                         + (idle ? " idle" : " active") + " " + bucket);
773             }
774             synchronized (mLock) {
775                 final boolean changed;
776                 if (bucket == UsageStatsManager.STANDBY_BUCKET_EXEMPTED) {
777                     changed = mExemptedBucketPackages.add(userId, packageName);
778                 } else {
779                     changed = mExemptedBucketPackages.remove(userId, packageName);
780                 }
781                 if (changed) {
782                     mHandler.notifyExemptedBucketChanged();
783                 }
784             }
785         }
786     }
787 
cloneListeners()788     private Listener[] cloneListeners() {
789         synchronized (mLock) {
790             return mListeners.toArray(new Listener[mListeners.size()]);
791         }
792     }
793 
794     private class MyHandler extends Handler {
795         private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0;
796         // Unused ids 1, 2.
797         private static final int MSG_RUN_ANY_CHANGED = 3;
798         private static final int MSG_ALL_UNEXEMPTED = 4;
799         private static final int MSG_ALL_EXEMPTION_LIST_CHANGED = 5;
800         private static final int MSG_TEMP_EXEMPTION_LIST_CHANGED = 6;
801         private static final int MSG_FORCE_ALL_CHANGED = 7;
802         private static final int MSG_USER_REMOVED = 8;
803         // Unused id 9.
804         private static final int MSG_EXEMPTED_BUCKET_CHANGED = 10;
805         private static final int MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED = 11;
806 
807         private static final int MSG_ON_UID_ACTIVE = 12;
808         private static final int MSG_ON_UID_GONE = 13;
809         private static final int MSG_ON_UID_IDLE = 14;
810         private static final int MSG_ON_UID_CACHED = 15;
811 
MyHandler(Looper looper)812         MyHandler(Looper looper) {
813             super(looper);
814         }
815 
notifyUidActiveStateChanged(int uid)816         public void notifyUidActiveStateChanged(int uid) {
817             obtainMessage(MSG_UID_ACTIVE_STATE_CHANGED, uid, 0).sendToTarget();
818         }
819 
notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName)820         public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
821             obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
822         }
823 
notifyAllUnexempted()824         public void notifyAllUnexempted() {
825             removeMessages(MSG_ALL_UNEXEMPTED);
826             obtainMessage(MSG_ALL_UNEXEMPTED).sendToTarget();
827         }
828 
notifyAllExemptionListChanged()829         public void notifyAllExemptionListChanged() {
830             removeMessages(MSG_ALL_EXEMPTION_LIST_CHANGED);
831             obtainMessage(MSG_ALL_EXEMPTION_LIST_CHANGED).sendToTarget();
832         }
833 
notifyTempExemptionListChanged()834         public void notifyTempExemptionListChanged() {
835             removeMessages(MSG_TEMP_EXEMPTION_LIST_CHANGED);
836             obtainMessage(MSG_TEMP_EXEMPTION_LIST_CHANGED).sendToTarget();
837         }
838 
notifyForceAllAppsStandbyChanged()839         public void notifyForceAllAppsStandbyChanged() {
840             removeMessages(MSG_FORCE_ALL_CHANGED);
841             obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
842         }
843 
notifyExemptedBucketChanged()844         public void notifyExemptedBucketChanged() {
845             removeMessages(MSG_EXEMPTED_BUCKET_CHANGED);
846             obtainMessage(MSG_EXEMPTED_BUCKET_CHANGED).sendToTarget();
847         }
848 
notifyAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket)849         public void notifyAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket) {
850             removeMessages(MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED);
851             obtainMessage(MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED,
852                     autoRestrictedBucket ? 1 : 0, 0).sendToTarget();
853         }
854 
doUserRemoved(int userId)855         public void doUserRemoved(int userId) {
856             obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
857         }
858 
onUidActive(int uid)859         public void onUidActive(int uid) {
860             obtainMessage(MSG_ON_UID_ACTIVE, uid, 0).sendToTarget();
861         }
862 
onUidGone(int uid, boolean disabled)863         public void onUidGone(int uid, boolean disabled) {
864             obtainMessage(MSG_ON_UID_GONE, uid, disabled ? 1 : 0).sendToTarget();
865         }
866 
onUidIdle(int uid, boolean disabled)867         public void onUidIdle(int uid, boolean disabled) {
868             obtainMessage(MSG_ON_UID_IDLE, uid, disabled ? 1 : 0).sendToTarget();
869         }
870 
onUidCachedChanged(int uid, boolean cached)871         public void onUidCachedChanged(int uid, boolean cached) {
872             obtainMessage(MSG_ON_UID_CACHED, uid, cached ? 1 : 0).sendToTarget();
873         }
874 
875         @Override
handleMessage(Message msg)876         public void handleMessage(Message msg) {
877             switch (msg.what) {
878                 case MSG_USER_REMOVED:
879                     handleUserRemoved(msg.arg1);
880                     return;
881             }
882 
883             // Only notify the listeners when started.
884             synchronized (mLock) {
885                 if (!mStarted) {
886                     return;
887                 }
888             }
889             final AppStateTrackerImpl sender = AppStateTrackerImpl.this;
890 
891             long start = mStatLogger.getTime();
892             switch (msg.what) {
893                 case MSG_UID_ACTIVE_STATE_CHANGED:
894                     for (Listener l : cloneListeners()) {
895                         l.onUidActiveStateChanged(sender, msg.arg1);
896                     }
897                     mStatLogger.logDurationStat(Stats.UID_ACTIVE_STATE_CHANGED, start);
898                     return;
899 
900                 case MSG_RUN_ANY_CHANGED:
901                     for (Listener l : cloneListeners()) {
902                         l.onRunAnyAppOpsChanged(sender, msg.arg1, (String) msg.obj);
903                     }
904                     mStatLogger.logDurationStat(Stats.RUN_ANY_CHANGED, start);
905                     return;
906 
907                 case MSG_ALL_UNEXEMPTED:
908                     for (Listener l : cloneListeners()) {
909                         l.onPowerSaveUnexempted(sender);
910                     }
911                     mStatLogger.logDurationStat(Stats.ALL_UNEXEMPTED, start);
912                     return;
913 
914                 case MSG_ALL_EXEMPTION_LIST_CHANGED:
915                     for (Listener l : cloneListeners()) {
916                         l.onPowerSaveExemptionListChanged(sender);
917                     }
918                     mStatLogger.logDurationStat(Stats.ALL_EXEMPTION_LIST_CHANGED, start);
919                     return;
920 
921                 case MSG_TEMP_EXEMPTION_LIST_CHANGED:
922                     for (Listener l : cloneListeners()) {
923                         l.onTempPowerSaveExemptionListChanged(sender);
924                     }
925                     mStatLogger.logDurationStat(Stats.TEMP_EXEMPTION_LIST_CHANGED, start);
926                     return;
927 
928                 case MSG_EXEMPTED_BUCKET_CHANGED:
929                     for (Listener l : cloneListeners()) {
930                         l.onExemptedBucketChanged(sender);
931                     }
932                     mStatLogger.logDurationStat(Stats.EXEMPTED_BUCKET_CHANGED, start);
933                     return;
934 
935                 case MSG_FORCE_ALL_CHANGED:
936                     for (Listener l : cloneListeners()) {
937                         l.onForceAllAppsStandbyChanged(sender);
938                     }
939                     mStatLogger.logDurationStat(Stats.FORCE_ALL_CHANGED, start);
940                     return;
941 
942                 case MSG_USER_REMOVED:
943                     handleUserRemoved(msg.arg1);
944                     return;
945 
946                 case MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED:
947                     final boolean autoRestrictedBucket = msg.arg1 == 1;
948                     for (Listener l : cloneListeners()) {
949                         l.onAutoRestrictedBucketFeatureFlagChanged(sender, autoRestrictedBucket);
950                     }
951                     return;
952 
953                 case MSG_ON_UID_ACTIVE:
954                     handleUidActive(msg.arg1);
955                     return;
956                 case MSG_ON_UID_GONE:
957                     handleUidGone(msg.arg1);
958                     if (msg.arg2 != 0) {
959                         handleUidDisabled(msg.arg1);
960                     }
961                     return;
962                 case MSG_ON_UID_IDLE:
963                     handleUidIdle(msg.arg1);
964                     if (msg.arg2 != 0) {
965                         handleUidDisabled(msg.arg1);
966                     }
967                     return;
968                 case MSG_ON_UID_CACHED:
969                     handleUidCached(msg.arg1, (msg.arg2 != 0));
970                     return;
971             }
972         }
973 
handleUidCached(int uid, boolean cached)974         private void handleUidCached(int uid, boolean cached) {
975             for (Listener l : cloneListeners()) {
976                 l.handleUidCachedChanged(uid, cached);
977             }
978         }
979 
handleUidDisabled(int uid)980         private void handleUidDisabled(int uid) {
981             for (Listener l : cloneListeners()) {
982                 l.removeAlarmsForUid(uid);
983             }
984         }
985 
handleUidActive(int uid)986         public void handleUidActive(int uid) {
987             synchronized (mLock) {
988                 if (addUidToArray(mActiveUids, uid)) {
989                     mHandler.notifyUidActiveStateChanged(uid);
990                 }
991             }
992         }
993 
handleUidGone(int uid)994         public void handleUidGone(int uid) {
995             removeUid(uid, true);
996         }
997 
handleUidIdle(int uid)998         public void handleUidIdle(int uid) {
999             // Just to avoid excessive memcpy, don't remove from the array in this case.
1000             removeUid(uid, false);
1001         }
1002 
removeUid(int uid, boolean remove)1003         private void removeUid(int uid, boolean remove) {
1004             synchronized (mLock) {
1005                 if (removeUidFromArray(mActiveUids, uid, remove)) {
1006                     mHandler.notifyUidActiveStateChanged(uid);
1007                 }
1008             }
1009         }
1010     }
1011 
handleUserRemoved(int removedUserId)1012     void handleUserRemoved(int removedUserId) {
1013         synchronized (mLock) {
1014             for (int i = mRunAnyRestrictedPackages.size() - 1; i >= 0; i--) {
1015                 final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
1016                 final int uid = pair.first;
1017                 final int userId = UserHandle.getUserId(uid);
1018 
1019                 if (userId == removedUserId) {
1020                     mRunAnyRestrictedPackages.removeAt(i);
1021                 }
1022             }
1023             updateBackgroundRestrictedUidPackagesLocked();
1024             cleanUpArrayForUser(mActiveUids, removedUserId);
1025             mExemptedBucketPackages.remove(removedUserId);
1026         }
1027     }
1028 
cleanUpArrayForUser(SparseBooleanArray array, int removedUserId)1029     private void cleanUpArrayForUser(SparseBooleanArray array, int removedUserId) {
1030         for (int i = array.size() - 1; i >= 0; i--) {
1031             final int uid = array.keyAt(i);
1032             final int userId = UserHandle.getUserId(uid);
1033 
1034             if (userId == removedUserId) {
1035                 array.removeAt(i);
1036             }
1037         }
1038     }
1039 
1040     /**
1041      * Called by device idle controller to update the power save exemption lists.
1042      */
setPowerSaveExemptionListAppIds( int[] powerSaveExemptionListExceptIdleAppIdArray, int[] powerSaveExemptionListUserAppIdArray, int[] tempExemptionListAppIdArray)1043     public void setPowerSaveExemptionListAppIds(
1044             int[] powerSaveExemptionListExceptIdleAppIdArray,
1045             int[] powerSaveExemptionListUserAppIdArray,
1046             int[] tempExemptionListAppIdArray) {
1047         synchronized (mLock) {
1048             final int[] previousExemptionList = mPowerExemptAllAppIds;
1049             final int[] previousTempExemptionList = mTempExemptAppIds;
1050 
1051             mPowerExemptAllAppIds = powerSaveExemptionListExceptIdleAppIdArray;
1052             mTempExemptAppIds = tempExemptionListAppIdArray;
1053             mPowerExemptUserAppIds = powerSaveExemptionListUserAppIdArray;
1054 
1055             if (isAnyAppIdUnexempt(previousExemptionList, mPowerExemptAllAppIds)) {
1056                 mHandler.notifyAllUnexempted();
1057             } else if (!Arrays.equals(previousExemptionList, mPowerExemptAllAppIds)) {
1058                 mHandler.notifyAllExemptionListChanged();
1059             }
1060 
1061             if (!Arrays.equals(previousTempExemptionList, mTempExemptAppIds)) {
1062                 mHandler.notifyTempExemptionListChanged();
1063             }
1064 
1065         }
1066     }
1067 
1068     /**
1069      * @return true if a sorted app-id array {@code prevArray} has at least one element
1070      * that's not in a sorted app-id array {@code newArray}.
1071      */
1072     @VisibleForTesting
isAnyAppIdUnexempt(int[] prevArray, int[] newArray)1073     static boolean isAnyAppIdUnexempt(int[] prevArray, int[] newArray) {
1074         int i1 = 0;
1075         int i2 = 0;
1076         boolean prevFinished;
1077         boolean newFinished;
1078 
1079         for (;;) {
1080             prevFinished = i1 >= prevArray.length;
1081             newFinished = i2 >= newArray.length;
1082             if (prevFinished || newFinished) {
1083                 break;
1084             }
1085             int a1 = prevArray[i1];
1086             int a2 = newArray[i2];
1087 
1088             if (a1 == a2) {
1089                 i1++;
1090                 i2++;
1091                 continue;
1092             }
1093             if (a1 < a2) {
1094                 // prevArray has an element that's not in a2.
1095                 return true;
1096             }
1097             i2++;
1098         }
1099         if (prevFinished) {
1100             return false;
1101         }
1102         return newFinished;
1103     }
1104 
1105     // Public interface.
1106 
1107     /**
1108      * Register a listener to get callbacks when any state changes.
1109      */
addListener(@onNull Listener listener)1110     public void addListener(@NonNull Listener listener) {
1111         synchronized (mLock) {
1112             mListeners.add(listener);
1113         }
1114     }
1115 
1116     /**
1117      * @return whether alarms should be restricted for a UID package-name, due to explicit
1118      * user-forced app standby. Use {{@link #areAlarmsRestrictedByBatterySaver} to check for
1119      * restrictions induced by battery saver.
1120      */
areAlarmsRestricted(int uid, @NonNull String packageName)1121     public boolean areAlarmsRestricted(int uid, @NonNull String packageName) {
1122         if (isUidActive(uid)) {
1123             return false;
1124         }
1125         synchronized (mLock) {
1126             final int appId = UserHandle.getAppId(uid);
1127             if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) {
1128                 return false;
1129             }
1130             // If apps will be put into restricted standby bucket automatically on user-forced
1131             // app standby, instead of blocking alarms completely, let the restricted standby bucket
1132             // policy take care of it.
1133             return (!mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
1134                     && isRunAnyRestrictedLocked(uid, packageName));
1135         }
1136     }
1137 
1138     /**
1139      * @return whether alarms should be restricted when due to battery saver.
1140      */
areAlarmsRestrictedByBatterySaver(int uid, @NonNull String packageName)1141     public boolean areAlarmsRestrictedByBatterySaver(int uid, @NonNull String packageName) {
1142         if (isUidActive(uid)) {
1143             return false;
1144         }
1145         synchronized (mLock) {
1146             final int appId = UserHandle.getAppId(uid);
1147             if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) {
1148                 return false;
1149             }
1150             final int userId = UserHandle.getUserId(uid);
1151             if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole()
1152                     && mExemptedBucketPackages.contains(userId, packageName)) {
1153                 return false;
1154             }
1155             return mForceAllAppsStandby;
1156         }
1157     }
1158 
1159 
1160     /**
1161      * @return whether jobs should be restricted for a UID package-name. This could be due to
1162      * battery saver or user-forced app standby
1163      */
areJobsRestricted(int uid, @NonNull String packageName, boolean hasForegroundExemption)1164     public boolean areJobsRestricted(int uid, @NonNull String packageName,
1165             boolean hasForegroundExemption) {
1166         if (isUidActive(uid)) {
1167             return false;
1168         }
1169         synchronized (mLock) {
1170             final int appId = UserHandle.getAppId(uid);
1171             if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)
1172                     || ArrayUtils.contains(mTempExemptAppIds, appId)) {
1173                 return false;
1174             }
1175             // If apps will be put into restricted standby bucket automatically on user-forced
1176             // app standby, instead of blocking jobs completely, let the restricted standby bucket
1177             // policy take care of it.
1178             if (!mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
1179                     && isRunAnyRestrictedLocked(uid, packageName)) {
1180                 return true;
1181             }
1182             if (hasForegroundExemption) {
1183                 return false;
1184             }
1185             final int userId = UserHandle.getUserId(uid);
1186             if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole()
1187                     && mExemptedBucketPackages.contains(userId, packageName)) {
1188                 return false;
1189             }
1190             return mForceAllAppsStandby;
1191         }
1192     }
1193 
1194     /**
1195      * @return whether a UID is in active or not *based on cached information.*
1196      *
1197      * Note this information is based on the UID proc state callback, meaning it's updated
1198      * asynchronously and may subtly be stale. If the fresh data is needed, use
1199      * {@link #isUidActiveSynced} instead.
1200      */
isUidActive(int uid)1201     public boolean isUidActive(int uid) {
1202         if (UserHandle.isCore(uid)) {
1203             return true;
1204         }
1205         synchronized (mLock) {
1206             return mActiveUids.get(uid);
1207         }
1208     }
1209 
1210     /**
1211      * @return whether a UID is in active or not *right now.*
1212      *
1213      * This gives the fresh information, but may access the activity manager so is slower.
1214      */
isUidActiveSynced(int uid)1215     public boolean isUidActiveSynced(int uid) {
1216         if (isUidActive(uid)) { // Use the cached one first.
1217             return true;
1218         }
1219         final long start = mStatLogger.getTime();
1220 
1221         final boolean ret = mActivityManagerInternal.isUidActive(uid);
1222         mStatLogger.logDurationStat(Stats.IS_UID_ACTIVE_RAW, start);
1223 
1224         return ret;
1225     }
1226 
1227     /**
1228      * @return whether force all apps standby is enabled or not.
1229      */
isForceAllAppsStandbyEnabled()1230     public boolean isForceAllAppsStandbyEnabled() {
1231         synchronized (mLock) {
1232             return mForceAllAppsStandby;
1233         }
1234     }
1235 
1236     /**
1237      * @return whether a UID/package has {@code OP_RUN_ANY_IN_BACKGROUND} allowed or not.
1238      *
1239      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1240      */
isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName)1241     public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
1242         synchronized (mLock) {
1243             return !isRunAnyRestrictedLocked(uid, packageName);
1244         }
1245     }
1246 
1247     /**
1248      * @return whether a UID is in the user / system defined power-save exemption list or not.
1249      *
1250      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1251      */
isUidPowerSaveExempt(int uid)1252     public boolean isUidPowerSaveExempt(int uid) {
1253         synchronized (mLock) {
1254             return ArrayUtils.contains(mPowerExemptAllAppIds, UserHandle.getAppId(uid));
1255         }
1256     }
1257 
1258     /**
1259      * @param uid the uid to check for
1260      * @return whether a UID is in the user defined power-save exemption list or not.
1261      */
isUidPowerSaveUserExempt(int uid)1262     public boolean isUidPowerSaveUserExempt(int uid) {
1263         synchronized (mLock) {
1264             return ArrayUtils.contains(mPowerExemptUserAppIds, UserHandle.getAppId(uid));
1265         }
1266     }
1267 
1268     /**
1269      * @return whether a UID is in the temp power-save exemption list or not.
1270      *
1271      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1272      */
isUidTempPowerSaveExempt(int uid)1273     public boolean isUidTempPowerSaveExempt(int uid) {
1274         synchronized (mLock) {
1275             return ArrayUtils.contains(mTempExemptAppIds, UserHandle.getAppId(uid));
1276         }
1277     }
1278 
1279     /**
1280      * Dump the internal state to the given PrintWriter. Can be included in the dump
1281      * of a binder service to be output on the shell command "dumpsys".
1282      */
dump(IndentingPrintWriter pw)1283     public void dump(IndentingPrintWriter pw) {
1284         synchronized (mLock) {
1285             pw.println("Current AppStateTracker State:");
1286 
1287             pw.increaseIndent();
1288             pw.print("Force all apps standby: ");
1289             pw.println(isForceAllAppsStandbyEnabled());
1290 
1291             pw.print("Small Battery Device: ");
1292             pw.println(isSmallBatteryDevice());
1293 
1294             pw.print("Force all apps standby for small battery device: ");
1295             pw.println(mForceAllAppStandbyForSmallBattery);
1296 
1297             pw.print("Plugged In: ");
1298             pw.println(mIsPluggedIn);
1299 
1300             pw.print("Active uids: ");
1301             dumpUids(pw, mActiveUids);
1302 
1303             pw.print("Except-idle + user exemption list appids: ");
1304             pw.println(Arrays.toString(mPowerExemptAllAppIds));
1305 
1306             pw.print("User exemption list appids: ");
1307             pw.println(Arrays.toString(mPowerExemptUserAppIds));
1308 
1309             pw.print("Temp exemption list appids: ");
1310             pw.println(Arrays.toString(mTempExemptAppIds));
1311 
1312             pw.println("Exempted bucket packages:");
1313             pw.increaseIndent();
1314             for (int i = 0; i < mExemptedBucketPackages.size(); i++) {
1315                 pw.print("User ");
1316                 pw.print(mExemptedBucketPackages.keyAt(i));
1317                 pw.println();
1318 
1319                 pw.increaseIndent();
1320                 for (int j = 0; j < mExemptedBucketPackages.sizeAt(i); j++) {
1321                     pw.print(mExemptedBucketPackages.valueAt(i, j));
1322                     pw.println();
1323                 }
1324                 pw.decreaseIndent();
1325             }
1326             pw.decreaseIndent();
1327             pw.println();
1328 
1329             pw.println("Restricted packages:");
1330             pw.increaseIndent();
1331             for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
1332                 pw.print(UserHandle.formatUid(uidAndPackage.first));
1333                 pw.print(" ");
1334                 pw.print(uidAndPackage.second);
1335                 pw.println();
1336             }
1337             pw.decreaseIndent();
1338 
1339             mStatLogger.dump(pw);
1340             pw.decreaseIndent();
1341         }
1342     }
1343 
dumpUids(PrintWriter pw, SparseBooleanArray array)1344     private void dumpUids(PrintWriter pw, SparseBooleanArray array) {
1345         pw.print("[");
1346 
1347         String sep = "";
1348         for (int i = 0; i < array.size(); i++) {
1349             if (array.valueAt(i)) {
1350                 pw.print(sep);
1351                 pw.print(UserHandle.formatUid(array.keyAt(i)));
1352                 sep = " ";
1353             }
1354         }
1355         pw.println("]");
1356     }
1357 
1358     /**
1359      * Proto version of {@link #dump(IndentingPrintWriter)}
1360      */
dumpProto(ProtoOutputStream proto, long fieldId)1361     public void dumpProto(ProtoOutputStream proto, long fieldId) {
1362         synchronized (mLock) {
1363             final long token = proto.start(fieldId);
1364 
1365             proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY,
1366                     isForceAllAppsStandbyEnabled());
1367             proto.write(AppStateTrackerProto.IS_SMALL_BATTERY_DEVICE, isSmallBatteryDevice());
1368             proto.write(AppStateTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
1369                     mForceAllAppStandbyForSmallBattery);
1370             proto.write(AppStateTrackerProto.IS_PLUGGED_IN, mIsPluggedIn);
1371 
1372             for (int i = 0; i < mActiveUids.size(); i++) {
1373                 if (mActiveUids.valueAt(i)) {
1374                     proto.write(AppStateTrackerProto.ACTIVE_UIDS, mActiveUids.keyAt(i));
1375                 }
1376             }
1377 
1378             for (int appId : mPowerExemptAllAppIds) {
1379                 proto.write(AppStateTrackerProto.POWER_SAVE_EXEMPT_APP_IDS, appId);
1380             }
1381 
1382             for (int appId : mPowerExemptUserAppIds) {
1383                 proto.write(AppStateTrackerProto.POWER_SAVE_USER_EXEMPT_APP_IDS, appId);
1384             }
1385 
1386             for (int appId : mTempExemptAppIds) {
1387                 proto.write(AppStateTrackerProto.TEMP_POWER_SAVE_EXEMPT_APP_IDS, appId);
1388             }
1389 
1390             for (int i = 0; i < mExemptedBucketPackages.size(); i++) {
1391                 for (int j = 0; j < mExemptedBucketPackages.sizeAt(i); j++) {
1392                     final long token2 = proto.start(AppStateTrackerProto.EXEMPTED_BUCKET_PACKAGES);
1393 
1394                     proto.write(ExemptedPackage.USER_ID, mExemptedBucketPackages.keyAt(i));
1395                     proto.write(ExemptedPackage.PACKAGE_NAME,
1396                             mExemptedBucketPackages.valueAt(i, j));
1397 
1398                     proto.end(token2);
1399                 }
1400             }
1401 
1402             for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
1403                 final long token2 = proto.start(
1404                         AppStateTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
1405                 proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
1406                 proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME,
1407                         uidAndPackage.second);
1408                 proto.end(token2);
1409             }
1410 
1411             mStatLogger.dumpProto(proto, AppStateTrackerProto.STATS);
1412 
1413             proto.end(token);
1414         }
1415     }
1416 }
1417