Home | History | Annotate | Download | only in server
      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 {
    200         FeatureFlagsObserver() {
    201             super(null);
    202         }
    203 
    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 
    213         boolean isForcedAppStandbyEnabled() {
    214             return injectGetGlobalSettingInt(Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1;
    215         }
    216 
    217         boolean isForcedAppStandbyForSmallBatteryEnabled() {
    218             return injectGetGlobalSettingInt(
    219                     Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 0) == 1;
    220         }
    221 
    222         @Override
    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          */
    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          */
    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          */
    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          */
    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          */
    311         private void onPowerSaveWhitelistedChanged(AppStateTracker sender) {
    312             updateAllJobs();
    313         }
    314 
    315         /**
    316          * This is called when the temp whitelist changes.
    317          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    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          */
    380         public void unblockAllUnrestrictedAlarms() {
    381         }
    382 
    383         /**
    384          * Called when all jobs for a specific UID are unblocked.
    385          */
    386         public void unblockAlarmsForUid(int uid) {
    387         }
    388 
    389         /**
    390          * Called when all alarms for a specific UID - package are unblocked.
    391          */
    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          */
    400         public void onUidForeground(int uid, boolean foreground) {
    401         }
    402     }
    403 
    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      */
    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
    472     AppOpsManager injectAppOpsManager() {
    473         return mContext.getSystemService(AppOpsManager.class);
    474     }
    475 
    476     @VisibleForTesting
    477     IAppOpsService injectIAppOpsService() {
    478         return IAppOpsService.Stub.asInterface(
    479                 ServiceManager.getService(Context.APP_OPS_SERVICE));
    480     }
    481 
    482     @VisibleForTesting
    483     IActivityManager injectIActivityManager() {
    484         return ActivityManager.getService();
    485     }
    486 
    487     @VisibleForTesting
    488     ActivityManagerInternal injectActivityManagerInternal() {
    489         return LocalServices.getService(ActivityManagerInternal.class);
    490     }
    491 
    492     @VisibleForTesting
    493     PowerManagerInternal injectPowerManagerInternal() {
    494         return LocalServices.getService(PowerManagerInternal.class);
    495     }
    496 
    497     @VisibleForTesting
    498     UsageStatsManagerInternal injectUsageStatsManagerInternal() {
    499         return LocalServices.getService(UsageStatsManagerInternal.class);
    500     }
    501 
    502     @VisibleForTesting
    503     boolean isSmallBatteryDevice() {
    504         return ActivityManager.isSmallBatteryDevice();
    505     }
    506 
    507     @VisibleForTesting
    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")
    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 
    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")
    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")
    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")
    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")
    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 
    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 
    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
    636         public void onUidStateChanged(int uid, int procState, long procStateSeq) {
    637             mHandler.onUidStateChanged(uid, procState);
    638         }
    639 
    640         @Override
    641         public void onUidActive(int uid) {
    642             mHandler.onUidActive(uid);
    643         }
    644 
    645         @Override
    646         public void onUidGone(int uid, boolean disabled) {
    647             mHandler.onUidGone(uid, disabled);
    648         }
    649 
    650         @Override
    651         public void onUidIdle(int uid, boolean disabled) {
    652             mHandler.onUidIdle(uid, disabled);
    653         }
    654 
    655         @Override
    656         public void onUidCachedChanged(int uid, boolean cached) {
    657         }
    658     }
    659 
    660     private final class AppOpsWatcher extends IAppOpsCallback.Stub {
    661         @Override
    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
    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
    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
    715         public void onParoleStateChanged(boolean isParoleOn) {
    716         }
    717     }
    718 
    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 
    742         public MyHandler(Looper looper) {
    743             super(looper);
    744         }
    745 
    746         public void notifyUidActiveStateChanged(int uid) {
    747             obtainMessage(MSG_UID_ACTIVE_STATE_CHANGED, uid, 0).sendToTarget();
    748         }
    749 
    750         public void notifyUidForegroundStateChanged(int uid) {
    751             obtainMessage(MSG_UID_FG_STATE_CHANGED, uid, 0).sendToTarget();
    752         }
    753 
    754         public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
    755             obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
    756         }
    757 
    758         public void notifyAllUnwhitelisted() {
    759             removeMessages(MSG_ALL_UNWHITELISTED);
    760             obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget();
    761         }
    762 
    763         public void notifyAllWhitelistChanged() {
    764             removeMessages(MSG_ALL_WHITELIST_CHANGED);
    765             obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget();
    766         }
    767 
    768         public void notifyTempWhitelistChanged() {
    769             removeMessages(MSG_TEMP_WHITELIST_CHANGED);
    770             obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget();
    771         }
    772 
    773         public void notifyForceAllAppsStandbyChanged() {
    774             removeMessages(MSG_FORCE_ALL_CHANGED);
    775             obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
    776         }
    777 
    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 
    783         public void notifyExemptChanged() {
    784             removeMessages(MSG_EXEMPT_CHANGED);
    785             obtainMessage(MSG_EXEMPT_CHANGED).sendToTarget();
    786         }
    787 
    788         public void doUserRemoved(int userId) {
    789             obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
    790         }
    791 
    792         public void onUidStateChanged(int uid, int procState) {
    793             obtainMessage(MSG_ON_UID_STATE_CHANGED, uid, procState).sendToTarget();
    794         }
    795 
    796         public void onUidActive(int uid) {
    797             obtainMessage(MSG_ON_UID_ACTIVE, uid, 0).sendToTarget();
    798         }
    799 
    800         public void onUidGone(int uid, boolean disabled) {
    801             obtainMessage(MSG_ON_UID_GONE, uid, disabled ? 1 : 0).sendToTarget();
    802         }
    803 
    804         public void onUidIdle(int uid, boolean disabled) {
    805             obtainMessage(MSG_ON_UID_IDLE, uid, disabled ? 1 : 0).sendToTarget();
    806         }
    807 
    808         @Override
    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 
    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 
    931         public void handleUidActive(int uid) {
    932             synchronized (mLock) {
    933                 if (addUidToArray(mActiveUids, uid)) {
    934                     mHandler.notifyUidActiveStateChanged(uid);
    935                 }
    936             }
    937         }
    938 
    939         public void handleUidGone(int uid, boolean disabled) {
    940             removeUid(uid, true);
    941         }
    942 
    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 
    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 
    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 
    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      */
    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
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   1220     public boolean isUidTempPowerSaveWhitelisted(int uid) {
   1221         synchronized (mLock) {
   1222             return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid));
   1223         }
   1224     }
   1225 
   1226     @Deprecated
   1227     public void dump(PrintWriter pw, String prefix) {
   1228         dump(new IndentingPrintWriter(pw, "  ").setIndent(prefix));
   1229     }
   1230 
   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 
   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 
   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