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