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