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