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.StatLogger;
58 import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage;
59 import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
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 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 = Objects.requireNonNull(injectIActivityManager());
420             mActivityManagerInternal = Objects.requireNonNull(injectActivityManagerInternal());
421             mAppOpsManager = Objects.requireNonNull(injectAppOpsManager());
422             mAppOpsService = Objects.requireNonNull(injectIAppOpsService());
423             mPowerManagerInternal = Objects.requireNonNull(injectPowerManagerInternal());
424             mUsageStatsManagerInternal = Objects.requireNonNull(
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             synchronized (mLock) {
704                 final boolean changed;
705                 if (bucket == UsageStatsManager.STANDBY_BUCKET_EXEMPTED) {
706                     changed = mExemptedPackages.add(userId, packageName);
707                 } else {
708                     changed = mExemptedPackages.remove(userId, packageName);
709                 }
710                 if (changed) {
711                     mHandler.notifyExemptChanged();
712                 }
713             }
714         }
715 
716         @Override
onParoleStateChanged(boolean isParoleOn)717         public void onParoleStateChanged(boolean isParoleOn) {
718         }
719     }
720 
cloneListeners()721     private Listener[] cloneListeners() {
722         synchronized (mLock) {
723             return mListeners.toArray(new Listener[mListeners.size()]);
724         }
725     }
726 
727     private class MyHandler extends Handler {
728         private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0;
729         private static final int MSG_UID_FG_STATE_CHANGED = 1;
730         private static final int MSG_RUN_ANY_CHANGED = 3;
731         private static final int MSG_ALL_UNWHITELISTED = 4;
732         private static final int MSG_ALL_WHITELIST_CHANGED = 5;
733         private static final int MSG_TEMP_WHITELIST_CHANGED = 6;
734         private static final int MSG_FORCE_ALL_CHANGED = 7;
735         private static final int MSG_USER_REMOVED = 8;
736         private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9;
737         private static final int MSG_EXEMPT_CHANGED = 10;
738 
739         private static final int MSG_ON_UID_STATE_CHANGED = 11;
740         private static final int MSG_ON_UID_ACTIVE = 12;
741         private static final int MSG_ON_UID_GONE = 13;
742         private static final int MSG_ON_UID_IDLE = 14;
743 
MyHandler(Looper looper)744         public MyHandler(Looper looper) {
745             super(looper);
746         }
747 
notifyUidActiveStateChanged(int uid)748         public void notifyUidActiveStateChanged(int uid) {
749             obtainMessage(MSG_UID_ACTIVE_STATE_CHANGED, uid, 0).sendToTarget();
750         }
751 
notifyUidForegroundStateChanged(int uid)752         public void notifyUidForegroundStateChanged(int uid) {
753             obtainMessage(MSG_UID_FG_STATE_CHANGED, uid, 0).sendToTarget();
754         }
755 
notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName)756         public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
757             obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
758         }
759 
notifyAllUnwhitelisted()760         public void notifyAllUnwhitelisted() {
761             removeMessages(MSG_ALL_UNWHITELISTED);
762             obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget();
763         }
764 
notifyAllWhitelistChanged()765         public void notifyAllWhitelistChanged() {
766             removeMessages(MSG_ALL_WHITELIST_CHANGED);
767             obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget();
768         }
769 
notifyTempWhitelistChanged()770         public void notifyTempWhitelistChanged() {
771             removeMessages(MSG_TEMP_WHITELIST_CHANGED);
772             obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget();
773         }
774 
notifyForceAllAppsStandbyChanged()775         public void notifyForceAllAppsStandbyChanged() {
776             removeMessages(MSG_FORCE_ALL_CHANGED);
777             obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
778         }
779 
notifyForcedAppStandbyFeatureFlagChanged()780         public void notifyForcedAppStandbyFeatureFlagChanged() {
781             removeMessages(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED);
782             obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
783         }
784 
notifyExemptChanged()785         public void notifyExemptChanged() {
786             removeMessages(MSG_EXEMPT_CHANGED);
787             obtainMessage(MSG_EXEMPT_CHANGED).sendToTarget();
788         }
789 
doUserRemoved(int userId)790         public void doUserRemoved(int userId) {
791             obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
792         }
793 
onUidStateChanged(int uid, int procState)794         public void onUidStateChanged(int uid, int procState) {
795             obtainMessage(MSG_ON_UID_STATE_CHANGED, uid, procState).sendToTarget();
796         }
797 
onUidActive(int uid)798         public void onUidActive(int uid) {
799             obtainMessage(MSG_ON_UID_ACTIVE, uid, 0).sendToTarget();
800         }
801 
onUidGone(int uid, boolean disabled)802         public void onUidGone(int uid, boolean disabled) {
803             obtainMessage(MSG_ON_UID_GONE, uid, disabled ? 1 : 0).sendToTarget();
804         }
805 
onUidIdle(int uid, boolean disabled)806         public void onUidIdle(int uid, boolean disabled) {
807             obtainMessage(MSG_ON_UID_IDLE, uid, disabled ? 1 : 0).sendToTarget();
808         }
809 
810         @Override
handleMessage(Message msg)811         public void handleMessage(Message msg) {
812             switch (msg.what) {
813                 case MSG_USER_REMOVED:
814                     handleUserRemoved(msg.arg1);
815                     return;
816             }
817 
818             // Only notify the listeners when started.
819             synchronized (mLock) {
820                 if (!mStarted) {
821                     return;
822                 }
823             }
824             final AppStateTracker sender = AppStateTracker.this;
825 
826             long start = mStatLogger.getTime();
827             switch (msg.what) {
828                 case MSG_UID_ACTIVE_STATE_CHANGED:
829                     for (Listener l : cloneListeners()) {
830                         l.onUidActiveStateChanged(sender, msg.arg1);
831                     }
832                     mStatLogger.logDurationStat(Stats.UID_ACTIVE_STATE_CHANGED, start);
833                     return;
834 
835                 case MSG_UID_FG_STATE_CHANGED:
836                     for (Listener l : cloneListeners()) {
837                         l.onUidForegroundStateChanged(sender, msg.arg1);
838                     }
839                     mStatLogger.logDurationStat(Stats.UID_FG_STATE_CHANGED, start);
840                     return;
841 
842                 case MSG_RUN_ANY_CHANGED:
843                     for (Listener l : cloneListeners()) {
844                         l.onRunAnyAppOpsChanged(sender, msg.arg1, (String) msg.obj);
845                     }
846                     mStatLogger.logDurationStat(Stats.RUN_ANY_CHANGED, start);
847                     return;
848 
849                 case MSG_ALL_UNWHITELISTED:
850                     for (Listener l : cloneListeners()) {
851                         l.onPowerSaveUnwhitelisted(sender);
852                     }
853                     mStatLogger.logDurationStat(Stats.ALL_UNWHITELISTED, start);
854                     return;
855 
856                 case MSG_ALL_WHITELIST_CHANGED:
857                     for (Listener l : cloneListeners()) {
858                         l.onPowerSaveWhitelistedChanged(sender);
859                     }
860                     mStatLogger.logDurationStat(Stats.ALL_WHITELIST_CHANGED, start);
861                     return;
862 
863                 case MSG_TEMP_WHITELIST_CHANGED:
864                     for (Listener l : cloneListeners()) {
865                         l.onTempPowerSaveWhitelistChanged(sender);
866                     }
867                     mStatLogger.logDurationStat(Stats.TEMP_WHITELIST_CHANGED, start);
868                     return;
869 
870                 case MSG_EXEMPT_CHANGED:
871                     for (Listener l : cloneListeners()) {
872                         l.onExemptChanged(sender);
873                     }
874                     mStatLogger.logDurationStat(Stats.EXEMPT_CHANGED, start);
875                     return;
876 
877                 case MSG_FORCE_ALL_CHANGED:
878                     for (Listener l : cloneListeners()) {
879                         l.onForceAllAppsStandbyChanged(sender);
880                     }
881                     mStatLogger.logDurationStat(Stats.FORCE_ALL_CHANGED, start);
882                     return;
883 
884                 case MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED:
885                     // Feature flag for forced app standby changed.
886                     final boolean unblockAlarms;
887                     synchronized (mLock) {
888                         unblockAlarms = !mForcedAppStandbyEnabled && !mForceAllAppsStandby;
889                     }
890                     for (Listener l : cloneListeners()) {
891                         l.updateAllJobs();
892                         if (unblockAlarms) {
893                             l.unblockAllUnrestrictedAlarms();
894                         }
895                     }
896                     mStatLogger.logDurationStat(
897                             Stats.FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED, start);
898                     return;
899 
900                 case MSG_USER_REMOVED:
901                     handleUserRemoved(msg.arg1);
902                     return;
903 
904                 case MSG_ON_UID_STATE_CHANGED:
905                     handleUidStateChanged(msg.arg1, msg.arg2);
906                     return;
907                 case MSG_ON_UID_ACTIVE:
908                     handleUidActive(msg.arg1);
909                     return;
910                 case MSG_ON_UID_GONE:
911                     handleUidGone(msg.arg1, msg.arg1 != 0);
912                     return;
913                 case MSG_ON_UID_IDLE:
914                     handleUidIdle(msg.arg1, msg.arg1 != 0);
915                     return;
916             }
917         }
918 
handleUidStateChanged(int uid, int procState)919         public void handleUidStateChanged(int uid, int procState) {
920             synchronized (mLock) {
921                 if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
922                     if (removeUidFromArray(mForegroundUids, uid, false)) {
923                         mHandler.notifyUidForegroundStateChanged(uid);
924                     }
925                 } else {
926                     if (addUidToArray(mForegroundUids, uid)) {
927                         mHandler.notifyUidForegroundStateChanged(uid);
928                     }
929                 }
930             }
931         }
932 
handleUidActive(int uid)933         public void handleUidActive(int uid) {
934             synchronized (mLock) {
935                 if (addUidToArray(mActiveUids, uid)) {
936                     mHandler.notifyUidActiveStateChanged(uid);
937                 }
938             }
939         }
940 
handleUidGone(int uid, boolean disabled)941         public void handleUidGone(int uid, boolean disabled) {
942             removeUid(uid, true);
943         }
944 
handleUidIdle(int uid, boolean disabled)945         public void handleUidIdle(int uid, boolean disabled) {
946             // Just to avoid excessive memcpy, don't remove from the array in this case.
947             removeUid(uid, false);
948         }
949 
removeUid(int uid, boolean remove)950         private void removeUid(int uid, boolean remove) {
951             synchronized (mLock) {
952                 if (removeUidFromArray(mActiveUids, uid, remove)) {
953                     mHandler.notifyUidActiveStateChanged(uid);
954                 }
955                 if (removeUidFromArray(mForegroundUids, uid, remove)) {
956                     mHandler.notifyUidForegroundStateChanged(uid);
957                 }
958             }
959         }
960     }
961 
handleUserRemoved(int removedUserId)962     void handleUserRemoved(int removedUserId) {
963         synchronized (mLock) {
964             for (int i = mRunAnyRestrictedPackages.size() - 1; i >= 0; i--) {
965                 final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
966                 final int uid = pair.first;
967                 final int userId = UserHandle.getUserId(uid);
968 
969                 if (userId == removedUserId) {
970                     mRunAnyRestrictedPackages.removeAt(i);
971                 }
972             }
973             cleanUpArrayForUser(mActiveUids, removedUserId);
974             cleanUpArrayForUser(mForegroundUids, removedUserId);
975             mExemptedPackages.remove(removedUserId);
976         }
977     }
978 
cleanUpArrayForUser(SparseBooleanArray array, int removedUserId)979     private void cleanUpArrayForUser(SparseBooleanArray array, int removedUserId) {
980         for (int i = array.size() - 1; i >= 0; i--) {
981             final int uid = array.keyAt(i);
982             final int userId = UserHandle.getUserId(uid);
983 
984             if (userId == removedUserId) {
985                 array.removeAt(i);
986             }
987         }
988     }
989 
990     /**
991      * Called by device idle controller to update the power save whitelists.
992      */
setPowerSaveWhitelistAppIds( int[] powerSaveWhitelistExceptIdleAppIdArray, int[] powerSaveWhitelistUserAppIdArray, int[] tempWhitelistAppIdArray)993     public void setPowerSaveWhitelistAppIds(
994             int[] powerSaveWhitelistExceptIdleAppIdArray,
995             int[] powerSaveWhitelistUserAppIdArray,
996             int[] tempWhitelistAppIdArray) {
997         synchronized (mLock) {
998             final int[] previousWhitelist = mPowerWhitelistedAllAppIds;
999             final int[] previousTempWhitelist = mTempWhitelistedAppIds;
1000 
1001             mPowerWhitelistedAllAppIds = powerSaveWhitelistExceptIdleAppIdArray;
1002             mTempWhitelistedAppIds = tempWhitelistAppIdArray;
1003             mPowerWhitelistedUserAppIds = powerSaveWhitelistUserAppIdArray;
1004 
1005             if (isAnyAppIdUnwhitelisted(previousWhitelist, mPowerWhitelistedAllAppIds)) {
1006                 mHandler.notifyAllUnwhitelisted();
1007             } else if (!Arrays.equals(previousWhitelist, mPowerWhitelistedAllAppIds)) {
1008                 mHandler.notifyAllWhitelistChanged();
1009             }
1010 
1011             if (!Arrays.equals(previousTempWhitelist, mTempWhitelistedAppIds)) {
1012                 mHandler.notifyTempWhitelistChanged();
1013             }
1014 
1015         }
1016     }
1017 
1018     /**
1019      * @retunr true if a sorted app-id array {@code prevArray} has at least one element
1020      * that's not in a sorted app-id array {@code newArray}.
1021      */
1022     @VisibleForTesting
isAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray)1023     static boolean isAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray) {
1024         int i1 = 0;
1025         int i2 = 0;
1026         boolean prevFinished;
1027         boolean newFinished;
1028 
1029         for (;;) {
1030             prevFinished = i1 >= prevArray.length;
1031             newFinished = i2 >= newArray.length;
1032             if (prevFinished || newFinished) {
1033                 break;
1034             }
1035             int a1 = prevArray[i1];
1036             int a2 = newArray[i2];
1037 
1038             if (a1 == a2) {
1039                 i1++;
1040                 i2++;
1041                 continue;
1042             }
1043             if (a1 < a2) {
1044                 // prevArray has an element that's not in a2.
1045                 return true;
1046             }
1047             i2++;
1048         }
1049         if (prevFinished) {
1050             return false;
1051         }
1052         return newFinished;
1053     }
1054 
1055     // Public interface.
1056 
1057     /**
1058      * Register a new listener.
1059      */
addListener(@onNull Listener listener)1060     public void addListener(@NonNull Listener listener) {
1061         synchronized (mLock) {
1062             mListeners.add(listener);
1063         }
1064     }
1065 
1066     /**
1067      * @return whether alarms should be restricted for a UID package-name.
1068      */
areAlarmsRestricted(int uid, @NonNull String packageName, boolean isExemptOnBatterySaver)1069     public boolean areAlarmsRestricted(int uid, @NonNull String packageName,
1070             boolean isExemptOnBatterySaver) {
1071         return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false,
1072                 isExemptOnBatterySaver);
1073     }
1074 
1075     /**
1076      * @return whether jobs should be restricted for a UID package-name.
1077      */
areJobsRestricted(int uid, @NonNull String packageName, boolean hasForegroundExemption)1078     public boolean areJobsRestricted(int uid, @NonNull String packageName,
1079             boolean hasForegroundExemption) {
1080         return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true,
1081                 hasForegroundExemption);
1082     }
1083 
1084     /**
1085      * @return whether foreground services should be suppressed in the background
1086      * due to forced app standby for the given app
1087      */
areForegroundServicesRestricted(int uid, @NonNull String packageName)1088     public boolean areForegroundServicesRestricted(int uid, @NonNull String packageName) {
1089         synchronized (mLock) {
1090             return isRunAnyRestrictedLocked(uid, packageName);
1091         }
1092     }
1093 
1094     /**
1095      * @return whether force-app-standby is effective for a UID package-name.
1096      */
isRestricted(int uid, @NonNull String packageName, boolean useTempWhitelistToo, boolean exemptOnBatterySaver)1097     private boolean isRestricted(int uid, @NonNull String packageName,
1098             boolean useTempWhitelistToo, boolean exemptOnBatterySaver) {
1099         if (isUidActive(uid)) {
1100             return false;
1101         }
1102         synchronized (mLock) {
1103             // Whitelisted?
1104             final int appId = UserHandle.getAppId(uid);
1105             if (ArrayUtils.contains(mPowerWhitelistedAllAppIds, appId)) {
1106                 return false;
1107             }
1108             if (useTempWhitelistToo &&
1109                     ArrayUtils.contains(mTempWhitelistedAppIds, appId)) {
1110                 return false;
1111             }
1112             if (mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName)) {
1113                 return true;
1114             }
1115             if (exemptOnBatterySaver) {
1116                 return false;
1117             }
1118             final int userId = UserHandle.getUserId(uid);
1119             if (mExemptedPackages.contains(userId, packageName)) {
1120                 return false;
1121             }
1122             return mForceAllAppsStandby;
1123         }
1124     }
1125 
1126     /**
1127      * @return whether a UID is in active or not *based on cached information.*
1128      *
1129      * Note this information is based on the UID proc state callback, meaning it's updated
1130      * asynchronously and may subtly be stale. If the fresh data is needed, use
1131      * {@link #isUidActiveSynced} instead.
1132      */
isUidActive(int uid)1133     public boolean isUidActive(int uid) {
1134         if (UserHandle.isCore(uid)) {
1135             return true;
1136         }
1137         synchronized (mLock) {
1138             return mActiveUids.get(uid);
1139         }
1140     }
1141 
1142     /**
1143      * @return whether a UID is in active or not *right now.*
1144      *
1145      * This gives the fresh information, but may access the activity manager so is slower.
1146      */
isUidActiveSynced(int uid)1147     public boolean isUidActiveSynced(int uid) {
1148         if (isUidActive(uid)) { // Use the cached one first.
1149             return true;
1150         }
1151         final long start = mStatLogger.getTime();
1152 
1153         final boolean ret = mActivityManagerInternal.isUidActive(uid);
1154         mStatLogger.logDurationStat(Stats.IS_UID_ACTIVE_RAW, start);
1155 
1156         return ret;
1157     }
1158 
1159     /**
1160      * @return whether a UID is in the foreground or not.
1161      *
1162      * Note this information is based on the UID proc state callback, meaning it's updated
1163      * asynchronously and may subtly be stale. If the fresh data is needed, use
1164      * {@link ActivityManagerInternal#getUidProcessState} instead.
1165      */
isUidInForeground(int uid)1166     public boolean isUidInForeground(int uid) {
1167         if (UserHandle.isCore(uid)) {
1168             return true;
1169         }
1170         synchronized (mLock) {
1171             return mForegroundUids.get(uid);
1172         }
1173     }
1174 
1175     /**
1176      * @return whether force all apps standby is enabled or not.
1177      *
1178      */
isForceAllAppsStandbyEnabled()1179     boolean isForceAllAppsStandbyEnabled() {
1180         synchronized (mLock) {
1181             return mForceAllAppsStandby;
1182         }
1183     }
1184 
1185     /**
1186      * @return whether a UID/package has {@code OP_RUN_ANY_IN_BACKGROUND} allowed or not.
1187      *
1188      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1189      */
isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName)1190     public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
1191         synchronized (mLock) {
1192             return !isRunAnyRestrictedLocked(uid, packageName);
1193         }
1194     }
1195 
1196     /**
1197      * @return whether a UID is in the user / system defined power-save whitelist or not.
1198      *
1199      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1200      */
isUidPowerSaveWhitelisted(int uid)1201     public boolean isUidPowerSaveWhitelisted(int uid) {
1202         synchronized (mLock) {
1203             return ArrayUtils.contains(mPowerWhitelistedAllAppIds, UserHandle.getAppId(uid));
1204         }
1205     }
1206 
1207     /**
1208      * @param uid the uid to check for
1209      * @return whether a UID is in the user defined power-save whitelist or not.
1210      */
isUidPowerSaveUserWhitelisted(int uid)1211     public boolean isUidPowerSaveUserWhitelisted(int uid) {
1212         synchronized (mLock) {
1213             return ArrayUtils.contains(mPowerWhitelistedUserAppIds, UserHandle.getAppId(uid));
1214         }
1215     }
1216 
1217     /**
1218      * @return whether a UID is in the temp power-save whitelist or not.
1219      *
1220      * Note clients normally shouldn't need to access it. It's only for dumpsys.
1221      */
isUidTempPowerSaveWhitelisted(int uid)1222     public boolean isUidTempPowerSaveWhitelisted(int uid) {
1223         synchronized (mLock) {
1224             return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid));
1225         }
1226     }
1227 
1228     @Deprecated
dump(PrintWriter pw, String prefix)1229     public void dump(PrintWriter pw, String prefix) {
1230         dump(new IndentingPrintWriter(pw, "  ").setIndent(prefix));
1231     }
1232 
dump(IndentingPrintWriter pw)1233     public void dump(IndentingPrintWriter pw) {
1234         synchronized (mLock) {
1235             pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled);
1236 
1237             pw.print("Force all apps standby: ");
1238             pw.println(isForceAllAppsStandbyEnabled());
1239 
1240             pw.print("Small Battery Device: ");
1241             pw.println(isSmallBatteryDevice());
1242 
1243             pw.print("Force all apps standby for small battery device: ");
1244             pw.println(mForceAllAppStandbyForSmallBattery);
1245 
1246             pw.print("Plugged In: ");
1247             pw.println(mIsPluggedIn);
1248 
1249             pw.print("Active uids: ");
1250             dumpUids(pw, mActiveUids);
1251 
1252             pw.print("Foreground uids: ");
1253             dumpUids(pw, mForegroundUids);
1254 
1255             pw.print("Except-idle + user whitelist appids: ");
1256             pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
1257 
1258             pw.print("User whitelist appids: ");
1259             pw.println(Arrays.toString(mPowerWhitelistedUserAppIds));
1260 
1261             pw.print("Temp whitelist appids: ");
1262             pw.println(Arrays.toString(mTempWhitelistedAppIds));
1263 
1264             pw.println("Exempted packages:");
1265             pw.increaseIndent();
1266             for (int i = 0; i < mExemptedPackages.size(); i++) {
1267                 pw.print("User ");
1268                 pw.print(mExemptedPackages.keyAt(i));
1269                 pw.println();
1270 
1271                 pw.increaseIndent();
1272                 for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
1273                     pw.print(mExemptedPackages.valueAt(i, j));
1274                     pw.println();
1275                 }
1276                 pw.decreaseIndent();
1277             }
1278             pw.decreaseIndent();
1279             pw.println();
1280 
1281             pw.println("Restricted packages:");
1282             pw.increaseIndent();
1283             for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
1284                 pw.print(UserHandle.formatUid(uidAndPackage.first));
1285                 pw.print(" ");
1286                 pw.print(uidAndPackage.second);
1287                 pw.println();
1288             }
1289             pw.decreaseIndent();
1290 
1291             mStatLogger.dump(pw);
1292         }
1293     }
1294 
dumpUids(PrintWriter pw, SparseBooleanArray array)1295     private void dumpUids(PrintWriter pw, SparseBooleanArray array) {
1296         pw.print("[");
1297 
1298         String sep = "";
1299         for (int i = 0; i < array.size(); i++) {
1300             if (array.valueAt(i)) {
1301                 pw.print(sep);
1302                 pw.print(UserHandle.formatUid(array.keyAt(i)));
1303                 sep = " ";
1304             }
1305         }
1306         pw.println("]");
1307     }
1308 
dumpProto(ProtoOutputStream proto, long fieldId)1309     public void dumpProto(ProtoOutputStream proto, long fieldId) {
1310         synchronized (mLock) {
1311             final long token = proto.start(fieldId);
1312 
1313             proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
1314             proto.write(ForceAppStandbyTrackerProto.IS_SMALL_BATTERY_DEVICE,
1315                     isSmallBatteryDevice());
1316             proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY,
1317                     mForceAllAppStandbyForSmallBattery);
1318             proto.write(ForceAppStandbyTrackerProto.IS_PLUGGED_IN, mIsPluggedIn);
1319 
1320             for (int i = 0; i < mActiveUids.size(); i++) {
1321                 if (mActiveUids.valueAt(i)) {
1322                     proto.write(ForceAppStandbyTrackerProto.ACTIVE_UIDS,
1323                             mActiveUids.keyAt(i));
1324                 }
1325             }
1326 
1327             for (int i = 0; i < mForegroundUids.size(); i++) {
1328                 if (mForegroundUids.valueAt(i)) {
1329                     proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS,
1330                             mForegroundUids.keyAt(i));
1331                 }
1332             }
1333 
1334             for (int appId : mPowerWhitelistedAllAppIds) {
1335                 proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
1336             }
1337 
1338             for (int appId : mPowerWhitelistedUserAppIds) {
1339                 proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_USER_WHITELIST_APP_IDS, appId);
1340             }
1341 
1342             for (int appId : mTempWhitelistedAppIds) {
1343                 proto.write(ForceAppStandbyTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
1344             }
1345 
1346             for (int i = 0; i < mExemptedPackages.size(); i++) {
1347                 for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
1348                     final long token2 = proto.start(
1349                             ForceAppStandbyTrackerProto.EXEMPTED_PACKAGES);
1350 
1351                     proto.write(ExemptedPackage.USER_ID, mExemptedPackages.keyAt(i));
1352                     proto.write(ExemptedPackage.PACKAGE_NAME, mExemptedPackages.valueAt(i, j));
1353 
1354                     proto.end(token2);
1355                 }
1356             }
1357 
1358             for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
1359                 final long token2 = proto.start(
1360                         ForceAppStandbyTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
1361                 proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
1362                 proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME,
1363                         uidAndPackage.second);
1364                 proto.end(token2);
1365             }
1366 
1367             mStatLogger.dumpProto(proto, ForceAppStandbyTrackerProto.STATS);
1368 
1369             proto.end(token);
1370         }
1371     }
1372 }
1373