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 */
16package com.android.server;
17
18import android.annotation.NonNull;
19import android.app.ActivityManager;
20import android.app.ActivityManagerInternal;
21import android.app.AppOpsManager;
22import android.app.AppOpsManager.PackageOps;
23import android.app.IActivityManager;
24import android.app.IUidObserver;
25import android.app.usage.UsageStatsManager;
26import android.app.usage.UsageStatsManagerInternal;
27import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
28import android.content.BroadcastReceiver;
29import android.content.Context;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.database.ContentObserver;
33import android.net.Uri;
34import android.os.BatteryManager;
35import android.os.Handler;
36import android.os.Looper;
37import android.os.Message;
38import android.os.PowerManager.ServiceType;
39import android.os.PowerManagerInternal;
40import android.os.RemoteException;
41import android.os.ServiceManager;
42import android.os.UserHandle;
43import android.provider.Settings;
44import android.util.ArraySet;
45import android.util.Pair;
46import android.util.Slog;
47import android.util.SparseBooleanArray;
48import android.util.SparseSetArray;
49import android.util.proto.ProtoOutputStream;
50
51import com.android.internal.annotations.GuardedBy;
52import com.android.internal.annotations.VisibleForTesting;
53import com.android.internal.app.IAppOpsCallback;
54import com.android.internal.app.IAppOpsService;
55import com.android.internal.util.ArrayUtils;
56import com.android.internal.util.IndentingPrintWriter;
57import com.android.internal.util.Preconditions;
58import com.android.internal.util.StatLogger;
59import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage;
60import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
61
62import java.io.PrintWriter;
63import java.util.Arrays;
64import 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 */
77public 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