• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 
17 package com.android.server.am;
18 
19 import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
20 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
21 import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
22 import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
23 import static android.app.ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
24 import static android.app.ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED;
25 import static android.app.ActivityManager.RESTRICTION_LEVEL_EXEMPTED;
26 import static android.app.ActivityManager.RESTRICTION_LEVEL_FORCE_STOPPED;
27 import static android.app.ActivityManager.RESTRICTION_LEVEL_MAX;
28 import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET;
29 import static android.app.ActivityManager.RESTRICTION_LEVEL_UNKNOWN;
30 import static android.app.ActivityManager.RESTRICTION_LEVEL_UNRESTRICTED;
31 import static android.app.ActivityManager.RESTRICTION_LEVEL_USER_LAUNCH_ONLY;
32 import static android.app.ActivityManager.RESTRICTION_REASON_DEFAULT;
33 import static android.app.ActivityManager.RESTRICTION_REASON_DORMANT;
34 import static android.app.ActivityManager.RESTRICTION_REASON_POLICY;
35 import static android.app.ActivityManager.RESTRICTION_REASON_SYSTEM_HEALTH;
36 import static android.app.ActivityManager.RESTRICTION_REASON_USAGE;
37 import static android.app.ActivityManager.RESTRICTION_REASON_USER;
38 import static android.app.ActivityManager.RESTRICTION_SUBREASON_MAX_LENGTH;
39 import static android.app.ActivityManager.UID_OBSERVER_ACTIVE;
40 import static android.app.ActivityManager.UID_OBSERVER_GONE;
41 import static android.app.ActivityManager.UID_OBSERVER_IDLE;
42 import static android.app.ActivityManager.UID_OBSERVER_PROCSTATE;
43 import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
44 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
45 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
46 import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK;
47 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
48 import static android.app.usage.UsageStatsManager.REASON_SUB_DEFAULT_UNDEFINED;
49 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_UNDEFINED;
50 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_USER_FLAG_INTERACTION;
51 import static android.app.usage.UsageStatsManager.REASON_SUB_MASK;
52 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
53 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
54 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
55 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
56 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
57 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
58 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
59 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED;
60 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
61 import static android.app.usage.UsageStatsManager.reasonToString;
62 import static android.content.Intent.ACTION_SHOW_FOREGROUND_SERVICE_MANAGER;
63 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
64 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
65 import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
66 import static android.os.PowerExemptionManager.REASON_ACTIVE_DEVICE_ADMIN;
67 import static android.os.PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE;
68 import static android.os.PowerExemptionManager.REASON_CARRIER_PRIVILEGED_APP;
69 import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER;
70 import static android.os.PowerExemptionManager.REASON_DENIED;
71 import static android.os.PowerExemptionManager.REASON_DEVICE_DEMO_MODE;
72 import static android.os.PowerExemptionManager.REASON_DEVICE_OWNER;
73 import static android.os.PowerExemptionManager.REASON_DISALLOW_APPS_CONTROL;
74 import static android.os.PowerExemptionManager.REASON_DPO_PROTECTED_APP;
75 import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_PLATFORM_VPN;
76 import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_VPN;
77 import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT;
78 import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI;
79 import static android.os.PowerExemptionManager.REASON_PROFILE_OWNER;
80 import static android.os.PowerExemptionManager.REASON_ROLE_DIALER;
81 import static android.os.PowerExemptionManager.REASON_ROLE_EMERGENCY;
82 import static android.os.PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED;
83 import static android.os.PowerExemptionManager.REASON_SYSTEM_EXEMPT_APP_OP;
84 import static android.os.PowerExemptionManager.REASON_SYSTEM_MODULE;
85 import static android.os.PowerExemptionManager.REASON_SYSTEM_UID;
86 import static android.os.PowerExemptionManager.getExemptionReasonForStatsd;
87 import static android.os.PowerExemptionManager.reasonCodeToString;
88 import static android.os.Process.SYSTEM_UID;
89 import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
90 
91 import static com.android.internal.notification.SystemNotificationChannels.ABUSIVE_BACKGROUND_APPS;
92 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
93 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
94 import static com.android.server.am.AppFGSTracker.foregroundServiceTypeToIndex;
95 import static com.android.server.am.BaseAppStateTracker.ONE_DAY;
96 
97 import android.annotation.CurrentTimeMillisLong;
98 import android.annotation.IntDef;
99 import android.annotation.NonNull;
100 import android.annotation.Nullable;
101 import android.annotation.UserIdInt;
102 import android.app.ActivityManager;
103 import android.app.ActivityManager.RestrictionLevel;
104 import android.app.ActivityManager.RestrictionReason;
105 import android.app.ActivityManager.RestrictionSource;
106 import android.app.ActivityManagerInternal;
107 import android.app.ActivityManagerInternal.AppBackgroundRestrictionListener;
108 import android.app.AppOpsManager;
109 import android.app.IActivityManager;
110 import android.app.IUidObserver;
111 import android.app.Notification;
112 import android.app.NotificationManager;
113 import android.app.PendingIntent;
114 import android.app.UidObserver;
115 import android.app.role.OnRoleHoldersChangedListener;
116 import android.app.role.RoleManager;
117 import android.app.usage.AppStandbyInfo;
118 import android.app.usage.UsageStatsManager;
119 import android.content.BroadcastReceiver;
120 import android.content.Context;
121 import android.content.Intent;
122 import android.content.IntentFilter;
123 import android.content.pm.ApplicationInfo;
124 import android.content.pm.ModuleInfo;
125 import android.content.pm.PackageInfo;
126 import android.content.pm.PackageManager;
127 import android.content.pm.PackageManagerInternal;
128 import android.content.pm.ServiceInfo;
129 import android.content.pm.ServiceInfo.ForegroundServiceType;
130 import android.graphics.drawable.Icon;
131 import android.net.Uri;
132 import android.os.AppBackgroundRestrictionsInfo;
133 import android.os.Build;
134 import android.os.Environment;
135 import android.os.Handler;
136 import android.os.HandlerExecutor;
137 import android.os.HandlerThread;
138 import android.os.Looper;
139 import android.os.Message;
140 import android.os.PowerExemptionManager.ReasonCode;
141 import android.os.RemoteException;
142 import android.os.SystemClock;
143 import android.os.UserHandle;
144 import android.os.UserManager;
145 import android.provider.DeviceConfig;
146 import android.provider.DeviceConfig.OnPropertiesChangedListener;
147 import android.provider.DeviceConfig.Properties;
148 import android.provider.Settings;
149 import android.telephony.TelephonyManager;
150 import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
151 import android.text.TextUtils;
152 import android.util.ArraySet;
153 import android.util.AtomicFile;
154 import android.util.Pair;
155 import android.util.Slog;
156 import android.util.SparseArray;
157 import android.util.SparseArrayMap;
158 import android.util.TimeUtils;
159 import android.util.Xml;
160 import android.util.proto.ProtoOutputStream;
161 
162 import com.android.internal.annotations.GuardedBy;
163 import com.android.internal.annotations.VisibleForTesting;
164 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
165 import com.android.internal.util.ArrayUtils;
166 import com.android.internal.util.FrameworkStatsLog;
167 import com.android.internal.util.function.TriConsumer;
168 import com.android.modules.utils.TypedXmlPullParser;
169 import com.android.modules.utils.TypedXmlSerializer;
170 import com.android.server.AppStateTracker;
171 import com.android.server.LocalServices;
172 import com.android.server.SystemConfig;
173 import com.android.server.am.AppBatteryTracker.ImmutableBatteryUsage;
174 import com.android.server.apphibernation.AppHibernationManagerInternal;
175 import com.android.server.pm.UserManagerInternal;
176 import com.android.server.usage.AppStandbyInternal;
177 import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
178 
179 import org.xmlpull.v1.XmlPullParser;
180 import org.xmlpull.v1.XmlPullParserException;
181 
182 import java.io.ByteArrayOutputStream;
183 import java.io.File;
184 import java.io.FileInputStream;
185 import java.io.FileOutputStream;
186 import java.io.IOException;
187 import java.io.InputStream;
188 import java.io.PrintWriter;
189 import java.lang.annotation.Retention;
190 import java.lang.annotation.RetentionPolicy;
191 import java.util.ArrayList;
192 import java.util.Arrays;
193 import java.util.Collections;
194 import java.util.Comparator;
195 import java.util.HashMap;
196 import java.util.List;
197 import java.util.Set;
198 import java.util.concurrent.CopyOnWriteArraySet;
199 import java.util.concurrent.atomic.AtomicBoolean;
200 import java.util.function.Consumer;
201 
202 /**
203  * This class tracks various state of the apps and mutates their restriction levels accordingly.
204  */
205 public final class AppRestrictionController {
206     static final String TAG = TAG_WITH_CLASS_NAME ? "AppRestrictionController" : TAG_AM;
207     static final boolean DEBUG_BG_RESTRICTION_CONTROLLER = false;
208 
209     /**
210      * The prefix for the sub-namespace of our device configs under
211      * the {@link android.provider.DeviceConfig#NAMESPACE_ACTIVITY_MANAGER}.
212      */
213     static final String DEVICE_CONFIG_SUBNAMESPACE_PREFIX = "bg_";
214 
215     static final int STOCK_PM_FLAGS = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
216             | MATCH_DISABLED_UNTIL_USED_COMPONENTS;
217 
218     /**
219      * Whether or not to show the foreground service manager on tapping notifications.
220      */
221     private static final boolean ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER = true;
222 
223     /**
224      * Whether or not to show the action to the foreground service manager when
225      * posting the notification for background restriction.
226      */
227     private static final boolean ENABLE_SHOW_FGS_MANAGER_ACTION_ON_BG_RESTRICTION = false;
228 
229     private static final String APP_RESTRICTION_SETTINGS_DIRNAME = "apprestriction";
230     private static final String APP_RESTRICTION_SETTINGS_FILENAME = "settings.xml";
231 
232     private static final String TAG_SETTINGS = "settings";
233     private static final String ATTR_PACKAGE = "package";
234     private static final String ATTR_UID = "uid";
235     private static final String ATTR_CUR_LEVEL = "curlevel";
236     private static final String ATTR_LEVEL_TS = "levelts";
237     private static final String ATTR_REASON = "reason";
238 
239     private static final String[] ROLES_IN_INTEREST = {
240         RoleManager.ROLE_DIALER,
241         RoleManager.ROLE_EMERGENCY,
242     };
243 
244     private final Context mContext;
245     private final HandlerThread mBgHandlerThread;
246     private final BgHandler mBgHandler;
247     private final HandlerExecutor mBgExecutor;
248     private final HandlerExecutor mExecutor;
249 
250     // No lock is needed, as it's immutable after initialization in constructor.
251     private final ArrayList<BaseAppStateTracker> mAppStateTrackers = new ArrayList<>();
252 
253     @VisibleForTesting
254     @GuardedBy("mSettingsLock")
255     final RestrictionSettings mRestrictionSettings = new RestrictionSettings();
256 
257     private final CopyOnWriteArraySet<AppBackgroundRestrictionListener> mRestrictionListeners =
258             new CopyOnWriteArraySet<>();
259 
260     /**
261      * A mapping between the UID/Pkg and its pending work which should be triggered on inactive;
262      * an active UID/pkg pair should have an entry here, although its pending work could be null.
263      */
264     @GuardedBy("mSettingsLock")
265     private final SparseArrayMap<String, Runnable> mActiveUids = new SparseArrayMap<>();
266 
267     // No lock is needed as it's accessed in bg handler thread only.
268     private final ArrayList<Runnable> mTmpRunnables = new ArrayList<>();
269 
270     /**
271      * Power-save allowlisted app-ids (not including except-idle-allowlisted ones).
272      */
273     private int[] mDeviceIdleAllowlist = new int[0]; // No lock is needed.
274 
275     /**
276      * Power-save allowlisted app-ids (including except-idle-allowlisted ones).
277      */
278     private int[] mDeviceIdleExceptIdleAllowlist = new int[0]; // No lock is needed.
279 
280     /**
281      * The pre-configured system app-ids in the power-save allow list.
282      *
283      * @see #mDeviceIdleAllowlist.
284      */
285     private final ArraySet<Integer> mSystemDeviceIdleAllowlist = new ArraySet<>();
286 
287     /**
288      * The pre-configured system app-ids in the power-save allow list, except-idle.
289      *
290      * @see #mDeviceIdleExceptIdleAllowlist.
291      */
292     private final ArraySet<Integer> mSystemDeviceIdleExceptIdleAllowlist = new ArraySet<>();
293 
294     private final Object mLock = new Object();
295     private final Object mSettingsLock = new Object();
296     private final Injector mInjector;
297     private final NotificationHelper mNotificationHelper;
298 
299     private final OnRoleHoldersChangedListener mRoleHolderChangedListener =
300             this::onRoleHoldersChanged;
301 
302     /**
303      * The key is the UID, the value is the list of the roles it holds.
304      */
305     @GuardedBy("mLock")
306     private final SparseArray<ArrayList<String>> mUidRolesMapping = new SparseArray<>();
307 
308     /**
309      * Cache the package name and information about if it's a system module.
310      */
311     @GuardedBy("mSystemModulesCache")
312     private final HashMap<String, Boolean> mSystemModulesCache = new HashMap<>();
313 
314     /**
315      * The pre-config packages that are exempted from the background restrictions.
316      */
317     ArraySet<String> mBgRestrictionExemptioFromSysConfig;
318 
319     /**
320      * Lock specifically for bookkeeping around the carrier-privileged app set.
321      * Do not acquire any other locks while holding this one. Methods that
322      * require this lock to be held are named with a "CPL" suffix.
323      */
324     private final Object mCarrierPrivilegedLock = new Object();
325 
326     /**
327      * List of carrier-privileged apps that should be excluded from standby,
328      * the key of this array here is the phone id.
329      */
330     @GuardedBy("mCarrierPrivilegedLock")
331     private final SparseArray<Set<String>> mCarrierPrivilegedApps = new SparseArray<>();
332 
333     /**
334      * Holding the callbacks to the carrier privileged app changes.
335      *
336      * it's lock free.
337      */
338     private volatile ArrayList<PhoneCarrierPrivilegesCallback> mCarrierPrivilegesCallbacks;
339 
340     /**
341      * Whether or not we've loaded the restriction settings from the persistent storage.
342      */
343     private final AtomicBoolean mRestrictionSettingsXmlLoaded = new AtomicBoolean();
344 
345     final ActivityManagerService mActivityManagerService;
346 
347     private volatile boolean mLockedBootCompleted = false;
348 
349     static final int TRACKER_TYPE_UNKNOWN = 0;
350     static final int TRACKER_TYPE_BATTERY = 1;
351     static final int TRACKER_TYPE_BATTERY_EXEMPTION = 2;
352     static final int TRACKER_TYPE_FGS = 3;
353     static final int TRACKER_TYPE_MEDIA_SESSION = 4;
354     static final int TRACKER_TYPE_PERMISSION = 5;
355     static final int TRACKER_TYPE_BROADCAST_EVENTS = 6;
356     static final int TRACKER_TYPE_BIND_SERVICE_EVENTS = 7;
357 
358     @IntDef(prefix = { "TRACKER_TYPE_" }, value = {
359             TRACKER_TYPE_UNKNOWN,
360             TRACKER_TYPE_BATTERY,
361             TRACKER_TYPE_BATTERY_EXEMPTION,
362             TRACKER_TYPE_FGS,
363             TRACKER_TYPE_MEDIA_SESSION,
364             TRACKER_TYPE_PERMISSION,
365             TRACKER_TYPE_BROADCAST_EVENTS,
366             TRACKER_TYPE_BIND_SERVICE_EVENTS,
367     })
368     @interface TrackerType {}
369 
370     private final TrackerInfo mEmptyTrackerInfo = new TrackerInfo();
371 
372     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
373         @Override
374         public void onReceive(Context context, Intent intent) {
375             final String action = intent.getAction();
376             if (action == null) {
377                 return;
378             }
379             switch (action) {
380                 case Intent.ACTION_PACKAGE_ADDED: {
381                     if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
382                         final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
383                         if (uid >= 0) {
384                             onUidAdded(uid);
385                         }
386                     }
387                 } break;
388                 case Intent.ACTION_PACKAGE_FULLY_REMOVED: {
389                     final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
390                     final Uri data = intent.getData();
391                     String ssp;
392                     if (uid >= 0 && data != null
393                             && (ssp = data.getSchemeSpecificPart()) != null) {
394                         onPackageRemoved(ssp, uid);
395                     }
396                 } break;
397                 case Intent.ACTION_UID_REMOVED: {
398                     if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
399                         final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
400                         if (uid >= 0) {
401                             onUidRemoved(uid);
402                         }
403                     }
404                 } break;
405                 case Intent.ACTION_USER_ADDED: {
406                     final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
407                     if (userId >= 0) {
408                         onUserAdded(userId);
409                     }
410                 } break;
411                 case Intent.ACTION_USER_STARTED: {
412                     final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
413                     if (userId >= 0) {
414                         onUserStarted(userId);
415                     }
416                 } break;
417                 case Intent.ACTION_USER_STOPPED: {
418                     final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
419                     if (userId >= 0) {
420                         onUserStopped(userId);
421                     }
422                 } break;
423                 case Intent.ACTION_USER_REMOVED: {
424                     final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
425                     if (userId >= 0) {
426                         onUserRemoved(userId);
427                     }
428                 } break;
429                 case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED: {
430                     unregisterCarrierPrivilegesCallbacks();
431                     registerCarrierPrivilegesCallbacks();
432                 } break;
433             }
434         }
435     };
436 
437     private final BroadcastReceiver mBootReceiver = new BroadcastReceiver() {
438         @Override
439         public void onReceive(Context context, Intent intent) {
440             final String action = intent.getAction();
441             switch (intent.getAction()) {
442                 case Intent.ACTION_LOCKED_BOOT_COMPLETED: {
443                     onLockedBootCompleted();
444                 } break;
445             }
446         }
447     };
448 
449     /**
450      * The restriction levels that each package is on, the levels here are defined in
451      * {@link android.app.ActivityManager.RESTRICTION_LEVEL_*}.
452      */
453     final class RestrictionSettings {
454         @GuardedBy("mSettingsLock")
455         final SparseArrayMap<String, PkgSettings> mRestrictionLevels = new SparseArrayMap();
456 
457         final class PkgSettings {
458             private final String mPackageName;
459             private final int mUid;
460 
461             private @RestrictionLevel int mCurrentRestrictionLevel;
462             private @RestrictionLevel int mLastRestrictionLevel;
463             private @CurrentTimeMillisLong long mLevelChangeTime;
464             private int mReason;
465 
466             private @CurrentTimeMillisLong long[] mLastNotificationShownTime;
467             private int[] mNotificationId;
468 
PkgSettings(String packageName, int uid)469             PkgSettings(String packageName, int uid) {
470                 mPackageName = packageName;
471                 mUid = uid;
472                 mCurrentRestrictionLevel = mLastRestrictionLevel = RESTRICTION_LEVEL_UNKNOWN;
473             }
474 
475             @GuardedBy("mSettingsLock")
update(@estrictionLevel int level, int reason, int subReason)476             @RestrictionLevel int update(@RestrictionLevel int level, int reason, int subReason) {
477                 if (level != mCurrentRestrictionLevel) {
478                     mLastRestrictionLevel = mCurrentRestrictionLevel;
479                     mCurrentRestrictionLevel = level;
480                     mLevelChangeTime = mInjector.currentTimeMillis();
481                     mReason = (REASON_MAIN_MASK & reason) | (REASON_SUB_MASK & subReason);
482                     mBgHandler.obtainMessage(BgHandler.MSG_APP_RESTRICTION_LEVEL_CHANGED,
483                             mUid, level, mPackageName).sendToTarget();
484                 }
485                 return mLastRestrictionLevel;
486             }
487 
488             @Override
489             @GuardedBy("mSettingsLock")
toString()490             public String toString() {
491                 final StringBuilder sb = new StringBuilder(128);
492                 sb.append("RestrictionLevel{");
493                 sb.append(Integer.toHexString(System.identityHashCode(this)));
494                 sb.append(':');
495                 sb.append(mPackageName);
496                 sb.append('/');
497                 sb.append(UserHandle.formatUid(mUid));
498                 sb.append('}');
499                 sb.append(' ');
500                 sb.append(ActivityManager.restrictionLevelToName(mCurrentRestrictionLevel));
501                 sb.append('(');
502                 sb.append(reasonToString(mReason));
503                 sb.append(')');
504                 return sb.toString();
505             }
506 
dump(PrintWriter pw, @CurrentTimeMillisLong long now)507             void dump(PrintWriter pw, @CurrentTimeMillisLong long now) {
508                 synchronized (mSettingsLock) {
509                     pw.print(toString());
510                     if (mLastRestrictionLevel != RESTRICTION_LEVEL_UNKNOWN) {
511                         pw.print('/');
512                         pw.print(ActivityManager.restrictionLevelToName(mLastRestrictionLevel));
513                     }
514                     pw.print(" levelChange=");
515                     TimeUtils.formatDuration(mLevelChangeTime - now, pw);
516                     if (mLastNotificationShownTime != null) {
517                         for (int i = 0; i < mLastNotificationShownTime.length; i++) {
518                             if (mLastNotificationShownTime[i] > 0) {
519                                 pw.print(" lastNoti(");
520                                 pw.print(mNotificationHelper.notificationTypeToString(i));
521                                 pw.print(")=");
522                                 TimeUtils.formatDuration(mLastNotificationShownTime[i] - now, pw);
523                             }
524                         }
525                     }
526                 }
527                 pw.print(" effectiveExemption=");
528                 pw.print(reasonCodeToString(getBackgroundRestrictionExemptionReason(mUid)));
529             }
530 
getPackageName()531             String getPackageName() {
532                 return mPackageName;
533             }
534 
getUid()535             int getUid() {
536                 return mUid;
537             }
538 
539             @GuardedBy("mSettingsLock")
getCurrentRestrictionLevel()540             @RestrictionLevel int getCurrentRestrictionLevel() {
541                 return mCurrentRestrictionLevel;
542             }
543 
544             @GuardedBy("mSettingsLock")
getLastRestrictionLevel()545             @RestrictionLevel int getLastRestrictionLevel() {
546                 return mLastRestrictionLevel;
547             }
548 
549             @GuardedBy("mSettingsLock")
getReason()550             int getReason() {
551                 return mReason;
552             }
553 
554             @GuardedBy("mSettingsLock")
getLastNotificationTime( @otificationHelper.NotificationType int notificationType)555             @CurrentTimeMillisLong long getLastNotificationTime(
556                     @NotificationHelper.NotificationType int notificationType) {
557                 if (mLastNotificationShownTime == null) {
558                     return 0;
559                 }
560                 return mLastNotificationShownTime[notificationType];
561             }
562 
563             @GuardedBy("mSettingsLock")
setLastNotificationTime(@otificationHelper.NotificationType int notificationType, @CurrentTimeMillisLong long timestamp)564             void setLastNotificationTime(@NotificationHelper.NotificationType int notificationType,
565                     @CurrentTimeMillisLong long timestamp) {
566                 setLastNotificationTime(notificationType, timestamp, true);
567             }
568 
569             @VisibleForTesting
570             @GuardedBy("mSettingsLock")
setLastNotificationTime(@otificationHelper.NotificationType int notificationType, @CurrentTimeMillisLong long timestamp, boolean persist)571             void setLastNotificationTime(@NotificationHelper.NotificationType int notificationType,
572                     @CurrentTimeMillisLong long timestamp, boolean persist) {
573                 if (mLastNotificationShownTime == null) {
574                     mLastNotificationShownTime =
575                             new long[NotificationHelper.NOTIFICATION_TYPE_LAST];
576                 }
577                 mLastNotificationShownTime[notificationType] = timestamp;
578                 if (persist && mRestrictionSettingsXmlLoaded.get()) {
579                     schedulePersistToXml(UserHandle.getUserId(mUid));
580                 }
581             }
582 
583             @GuardedBy("mSettingsLock")
getNotificationId(@otificationHelper.NotificationType int notificationType)584             int getNotificationId(@NotificationHelper.NotificationType int notificationType) {
585                 if (mNotificationId == null) {
586                     return 0;
587                 }
588                 return mNotificationId[notificationType];
589             }
590 
591             @GuardedBy("mSettingsLock")
setNotificationId(@otificationHelper.NotificationType int notificationType, int notificationId)592             void setNotificationId(@NotificationHelper.NotificationType int notificationType,
593                     int notificationId) {
594                 if (mNotificationId == null) {
595                     mNotificationId = new int[NotificationHelper.NOTIFICATION_TYPE_LAST];
596                 }
597                 mNotificationId[notificationType] = notificationId;
598             }
599 
600             @VisibleForTesting
601             @GuardedBy("mSettingsLock")
setLevelChangeTime(@urrentTimeMillisLong long timestamp)602             void setLevelChangeTime(@CurrentTimeMillisLong long timestamp) {
603                 mLevelChangeTime = timestamp;
604             }
605 
606             @GuardedBy("mSettingsLock")
607             @Override
clone()608             public Object clone() {
609                 final PkgSettings newObj = new PkgSettings(mPackageName, mUid);
610                 newObj.mCurrentRestrictionLevel = mCurrentRestrictionLevel;
611                 newObj.mLastRestrictionLevel = mLastRestrictionLevel;
612                 newObj.mLevelChangeTime = mLevelChangeTime;
613                 newObj.mReason = mReason;
614                 if (mLastNotificationShownTime != null) {
615                     newObj.mLastNotificationShownTime = Arrays.copyOf(
616                             mLastNotificationShownTime, mLastNotificationShownTime.length);
617                 }
618                 if (mNotificationId != null) {
619                     newObj.mNotificationId = Arrays.copyOf(mNotificationId, mNotificationId.length);
620                 }
621                 return newObj;
622             }
623 
624             @GuardedBy("mSettingsLock")
625             @Override
equals(Object other)626             public boolean equals(Object other) {
627                 if (other == this) {
628                     return true;
629                 }
630                 if (other == null || !(other instanceof PkgSettings)) {
631                     return false;
632                 }
633                 final PkgSettings otherSettings = (PkgSettings) other;
634                 return otherSettings.mUid == mUid
635                         && otherSettings.mCurrentRestrictionLevel == mCurrentRestrictionLevel
636                         && otherSettings.mLastRestrictionLevel == mLastRestrictionLevel
637                         && otherSettings.mLevelChangeTime == mLevelChangeTime
638                         && otherSettings.mReason == mReason
639                         && TextUtils.equals(otherSettings.mPackageName, mPackageName)
640                         && Arrays.equals(otherSettings.mLastNotificationShownTime,
641                                 mLastNotificationShownTime)
642                         && Arrays.equals(otherSettings.mNotificationId, mNotificationId);
643             }
644         }
645 
646         /**
647          * Update the restriction level.
648          *
649          * @return The previous restriction level.
650          */
update(String packageName, int uid, @RestrictionLevel int level, int reason, int subReason)651         @RestrictionLevel int update(String packageName, int uid, @RestrictionLevel int level,
652                 int reason, int subReason) {
653             synchronized (mSettingsLock) {
654                 PkgSettings settings = getRestrictionSettingsLocked(uid, packageName);
655                 if (settings == null) {
656                     settings = new PkgSettings(packageName, uid);
657                     mRestrictionLevels.add(uid, packageName, settings);
658                 }
659                 return settings.update(level, reason, subReason);
660             }
661         }
662 
663         /**
664          * @return The reason of why it's in this level.
665          */
getReason(String packageName, int uid)666         int getReason(String packageName, int uid) {
667             synchronized (mSettingsLock) {
668                 final PkgSettings settings = mRestrictionLevels.get(uid, packageName);
669                 return settings != null ? settings.getReason()
670                         : (REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_UNDEFINED);
671             }
672         }
673 
getRestrictionLevel(int uid)674         @RestrictionLevel int getRestrictionLevel(int uid) {
675             synchronized (mSettingsLock) {
676                 final int uidKeyIndex = mRestrictionLevels.indexOfKey(uid);
677                 if (uidKeyIndex < 0) {
678                     return RESTRICTION_LEVEL_UNKNOWN;
679                 }
680                 final int numPackages = mRestrictionLevels.numElementsForKeyAt(uidKeyIndex);
681                 if (numPackages == 0) {
682                     return RESTRICTION_LEVEL_UNKNOWN;
683                 }
684                 @RestrictionLevel int level = RESTRICTION_LEVEL_UNKNOWN;
685                 for (int i = 0; i < numPackages; i++) {
686                     final PkgSettings setting = mRestrictionLevels.valueAt(uidKeyIndex, i);
687                     if (setting != null) {
688                         final @RestrictionLevel int l = setting.getCurrentRestrictionLevel();
689                         level = (level == RESTRICTION_LEVEL_UNKNOWN) ? l : Math.min(level, l);
690                     }
691                 }
692                 return level;
693             }
694         }
695 
getRestrictionLevel(int uid, String packageName)696         @RestrictionLevel int getRestrictionLevel(int uid, String packageName) {
697             synchronized (mSettingsLock) {
698                 final PkgSettings settings = getRestrictionSettingsLocked(uid, packageName);
699                 return settings == null
700                         ? getRestrictionLevel(uid) : settings.getCurrentRestrictionLevel();
701             }
702         }
703 
getRestrictionLevel(String packageName, @UserIdInt int userId)704         @RestrictionLevel int getRestrictionLevel(String packageName, @UserIdInt int userId) {
705             final PackageManagerInternal pm = mInjector.getPackageManagerInternal();
706             final int uid = pm.getPackageUid(packageName, STOCK_PM_FLAGS, userId);
707             return getRestrictionLevel(uid, packageName);
708         }
709 
getLastRestrictionLevel(int uid, String packageName)710         private @RestrictionLevel int getLastRestrictionLevel(int uid, String packageName) {
711             synchronized (mSettingsLock) {
712                 final PkgSettings settings = mRestrictionLevels.get(uid, packageName);
713                 return settings == null
714                         ? RESTRICTION_LEVEL_UNKNOWN : settings.getLastRestrictionLevel();
715             }
716         }
717 
718         @GuardedBy("mSettingsLock")
forEachPackageInUidLocked(int uid, @NonNull TriConsumer<String, Integer, Integer> consumer)719         void forEachPackageInUidLocked(int uid,
720                 @NonNull TriConsumer<String, Integer, Integer> consumer) {
721             final int uidKeyIndex = mRestrictionLevels.indexOfKey(uid);
722             if (uidKeyIndex < 0) {
723                 return;
724             }
725             final int numPackages = mRestrictionLevels.numElementsForKeyAt(uidKeyIndex);
726             for (int i = 0; i < numPackages; i++) {
727                 final PkgSettings settings = mRestrictionLevels.valueAt(uidKeyIndex, i);
728                 consumer.accept(mRestrictionLevels.keyAt(uidKeyIndex, i),
729                         settings.getCurrentRestrictionLevel(), settings.getReason());
730             }
731         }
732 
733         @GuardedBy("mSettingsLock")
forEachUidLocked(@onNull Consumer<Integer> consumer)734         void forEachUidLocked(@NonNull Consumer<Integer> consumer) {
735             for (int i = mRestrictionLevels.numMaps() - 1; i >= 0; i--) {
736                 consumer.accept(mRestrictionLevels.keyAt(i));
737             }
738         }
739 
740         @GuardedBy("mSettingsLock")
getRestrictionSettingsLocked(int uid, String packageName)741         PkgSettings getRestrictionSettingsLocked(int uid, String packageName) {
742             return mRestrictionLevels.get(uid, packageName);
743         }
744 
removeUser(@serIdInt int userId)745         void removeUser(@UserIdInt int userId) {
746             synchronized (mSettingsLock) {
747                 for (int i = mRestrictionLevels.numMaps() - 1; i >= 0; i--) {
748                     final int uid = mRestrictionLevels.keyAt(i);
749                     if (UserHandle.getUserId(uid) != userId) {
750                         continue;
751                     }
752                     mRestrictionLevels.deleteAt(i);
753                 }
754             }
755         }
756 
removePackage(String pkgName, int uid)757         void removePackage(String pkgName, int uid) {
758             removePackage(pkgName, uid, true);
759         }
760 
removePackage(String pkgName, int uid, boolean persist)761         void removePackage(String pkgName, int uid, boolean persist) {
762             synchronized (mSettingsLock) {
763                 final int keyIndex = mRestrictionLevels.indexOfKey(uid);
764                 mRestrictionLevels.delete(uid, pkgName);
765                 if (keyIndex >= 0 && mRestrictionLevels.numElementsForKeyAt(keyIndex) == 0) {
766                     mRestrictionLevels.deleteAt(keyIndex);
767                 }
768             }
769             if (persist && mRestrictionSettingsXmlLoaded.get()) {
770                 schedulePersistToXml(UserHandle.getUserId(uid));
771             }
772         }
773 
removeUid(int uid)774         void removeUid(int uid) {
775             removeUid(uid, true);
776         }
777 
removeUid(int uid, boolean persist)778         void removeUid(int uid, boolean persist) {
779             synchronized (mSettingsLock) {
780                 mRestrictionLevels.delete(uid);
781             }
782             if (persist && mRestrictionSettingsXmlLoaded.get()) {
783                 schedulePersistToXml(UserHandle.getUserId(uid));
784             }
785         }
786 
787         @VisibleForTesting
reset()788         void reset() {
789             synchronized (mSettingsLock) {
790                 for (int i = mRestrictionLevels.numMaps() - 1; i >= 0; i--) {
791                     mRestrictionLevels.deleteAt(i);
792                 }
793             }
794         }
795 
796         @VisibleForTesting
resetToDefault()797         void resetToDefault() {
798             synchronized (mSettingsLock) {
799                 mRestrictionLevels.forEach(settings -> {
800                     settings.mCurrentRestrictionLevel = RESTRICTION_LEVEL_UNKNOWN;
801                     settings.mLastRestrictionLevel = RESTRICTION_LEVEL_UNKNOWN;
802                     settings.mLevelChangeTime = 0L;
803                     settings.mReason = REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_UNDEFINED;
804                     if (settings.mLastNotificationShownTime != null) {
805                         for (int i = 0; i < settings.mLastNotificationShownTime.length; i++) {
806                             settings.mLastNotificationShownTime[i] = 0L;
807                         }
808                     }
809                 });
810             }
811         }
812 
dump(PrintWriter pw, String prefix)813         void dump(PrintWriter pw, String prefix) {
814             final ArrayList<PkgSettings> settings = new ArrayList<>();
815             synchronized (mSettingsLock) {
816                 mRestrictionLevels.forEach(setting -> settings.add(setting));
817             }
818             Collections.sort(settings, Comparator.comparingInt(PkgSettings::getUid));
819             final long now = mInjector.currentTimeMillis();
820             for (int i = 0, size = settings.size(); i < size; i++) {
821                 pw.print(prefix);
822                 pw.print('#');
823                 pw.print(i);
824                 pw.print(' ');
825                 settings.get(i).dump(pw, now);
826                 pw.println();
827             }
828         }
829 
830         @VisibleForTesting
schedulePersistToXml(@serIdInt int userId)831         void schedulePersistToXml(@UserIdInt int userId) {
832             mBgHandler.obtainMessage(BgHandler.MSG_PERSIST_RESTRICTION_SETTINGS, userId, 0)
833                     .sendToTarget();
834         }
835 
836         @VisibleForTesting
scheduleLoadFromXml()837         void scheduleLoadFromXml() {
838             mBgHandler.sendEmptyMessage(BgHandler.MSG_LOAD_RESTRICTION_SETTINGS);
839         }
840 
841         @VisibleForTesting
getXmlFileNameForUser(@serIdInt int userId)842         File getXmlFileNameForUser(@UserIdInt int userId) {
843             final File dir = new File(mInjector.getDataSystemDeDirectory(
844                     userId), APP_RESTRICTION_SETTINGS_DIRNAME);
845             return new File(dir, APP_RESTRICTION_SETTINGS_FILENAME);
846         }
847 
848         @VisibleForTesting
loadFromXml(boolean applyLevel)849         void loadFromXml(boolean applyLevel) {
850             final int[] allUsers = mInjector.getUserManagerInternal().getUserIds();
851             for (int userId : allUsers) {
852                 loadFromXml(userId, applyLevel);
853             }
854             mRestrictionSettingsXmlLoaded.set(true);
855         }
856 
loadFromXml(@serIdInt int userId, boolean applyLevel)857         void loadFromXml(@UserIdInt int userId, boolean applyLevel) {
858             final File file = getXmlFileNameForUser(userId);
859             if (!file.exists()) {
860                 return;
861             }
862             final long[] ts = new long[NotificationHelper.NOTIFICATION_TYPE_LAST];
863             try (InputStream in = new FileInputStream(file)) {
864                 final TypedXmlPullParser parser = Xml.resolvePullParser(in);
865                 final long now = SystemClock.elapsedRealtime();
866                 int type;
867                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
868                     if (type != XmlPullParser.START_TAG) {
869                         continue;
870                     }
871                     final String tagName = parser.getName();
872                     if (!TAG_SETTINGS.equals(tagName)) {
873                         Slog.w(TAG, "Unexpected tag name: " + tagName);
874                         continue;
875                     }
876                     loadOneFromXml(parser, now, ts, applyLevel);
877                 }
878                 if (DEBUG_BG_RESTRICTION_CONTROLLER) {
879                     Slog.i(TAG, "Loaded from " + file);
880                 }
881             } catch (IOException | XmlPullParserException e) {
882             }
883         }
884 
loadOneFromXml(TypedXmlPullParser parser, long now, long[] ts, boolean applyLevel)885         private void loadOneFromXml(TypedXmlPullParser parser, long now, long[] ts,
886                 boolean applyLevel) {
887             // Reset the buffer.
888             for (int i = 0; i < ts.length; i++) {
889                 ts[i] = 0L;
890             }
891             // Walk through the attributes.
892             int uid = 0;
893             String packageName = null;
894             int curLevel = RESTRICTION_LEVEL_UNKNOWN;
895             int reason = REASON_MAIN_DEFAULT;
896             long levelTs = 0L;
897             for (int i = 0; i < parser.getAttributeCount(); i++) {
898                 try {
899                     final String attrName = parser.getAttributeName(i);
900                     final String attrValue = parser.getAttributeValue(i);
901                     switch (attrName) {
902                         case ATTR_UID:
903                             uid = Integer.parseInt(attrValue);
904                             break;
905                         case ATTR_PACKAGE:
906                             packageName = attrValue;
907                             break;
908                         case ATTR_CUR_LEVEL:
909                             curLevel = Integer.parseInt(attrValue);
910                             break;
911                         case ATTR_LEVEL_TS:
912                             levelTs = Long.parseLong(attrValue);
913                             break;
914                         case ATTR_REASON:
915                             reason = Integer.parseInt(attrValue);
916                             break;
917                         default:
918                             @NotificationHelper.NotificationType int type =
919                                     NotificationHelper.notificationTimeAttrToType(attrName);
920                             ts[type] = Long.parseLong(attrValue);
921                             break;
922                     }
923                 } catch (IllegalArgumentException e) {
924                 }
925             }
926             if (uid != 0) {
927                 if (DEBUG_BG_RESTRICTION_CONTROLLER) {
928                     Slog.i(TAG, "Restoring " + packageName + "/" + UserHandle.formatUid(uid)
929                             + " level=" + curLevel + " reason=" + Integer.toHexString(reason)
930                             + " ts=" + levelTs + " noti=" + Arrays.toString(ts));
931                 }
932                 final PkgSettings pkgSettings;
933                 synchronized (mSettingsLock) {
934                     pkgSettings = getRestrictionSettingsLocked(uid, packageName);
935                     if (pkgSettings == null) {
936                         return;
937                     }
938                     for (int i = 0; i < ts.length; i++) {
939                         if (pkgSettings.getLastNotificationTime(i) == 0 && ts[i] != 0) {
940                             pkgSettings.setLastNotificationTime(i, ts[i], false);
941                         }
942                     }
943                     if (pkgSettings.mCurrentRestrictionLevel >= curLevel) {
944                         // The current restriction level is the same or more restrictive,
945                         // don't restore.
946                         return;
947                     }
948                 }
949                 final int curBucket = mInjector.getAppStandbyInternal().getAppStandbyBucket(
950                         packageName, UserHandle.getUserId(uid), now, false);
951                 if (applyLevel) {
952                     applyRestrictionLevel(packageName, uid, curLevel, mEmptyTrackerInfo,
953                             curBucket, true, reason & REASON_MAIN_MASK, reason & REASON_SUB_MASK);
954                 } else {
955                     pkgSettings.update(curLevel,
956                             reason & REASON_MAIN_MASK, reason & REASON_SUB_MASK);
957                 }
958                 synchronized (mSettingsLock) {
959                     // Restore the mLevelChangeTime too.
960                     pkgSettings.setLevelChangeTime(levelTs);
961                 }
962             }
963         }
964 
965         @VisibleForTesting
persistToXml(@serIdInt int userId)966         void persistToXml(@UserIdInt int userId) {
967             final File file = getXmlFileNameForUser(userId);
968             final File dir = file.getParentFile();
969             if (!dir.isDirectory() && !dir.mkdirs()) {
970                 Slog.w(TAG, "Failed to create folder for " + userId);
971                 return;
972             }
973             final AtomicFile atomicFile = new AtomicFile(file);
974             FileOutputStream stream = null;
975             try {
976                 stream = atomicFile.startWrite();
977                 stream.write(toXmlByteArray(userId));
978             } catch (Exception e) {
979                 Slog.e(TAG, "Failed to write file " + file, e);
980                 if (stream != null) {
981                     atomicFile.failWrite(stream);
982                 }
983                 return;
984             }
985             atomicFile.finishWrite(stream);
986             if (DEBUG_BG_RESTRICTION_CONTROLLER) {
987                 Slog.i(TAG, "Successfully written to " + atomicFile);
988             }
989         }
990 
toXmlByteArray(@serIdInt int userId)991         private byte[] toXmlByteArray(@UserIdInt int userId) {
992             try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
993                 final TypedXmlSerializer serializer = Xml.resolveSerializer(os);
994 
995                 serializer.startDocument(/* encoding */ null, /* standalone */ true);
996 
997                 synchronized (mSettingsLock) {
998                     for (int i = mRestrictionLevels.numMaps() - 1; i >= 0; i--) {
999                         for (int j = mRestrictionLevels.numElementsForKeyAt(i) - 1; j >= 0; j--) {
1000                             final PkgSettings settings = mRestrictionLevels.valueAt(i, j);
1001                             final int uid = settings.getUid();
1002                             if (UserHandle.getUserId(uid) != userId) {
1003                                 continue;
1004                             }
1005                             serializer.startTag(null, TAG_SETTINGS);
1006                             serializer.attributeInt(null, ATTR_UID, uid);
1007                             serializer.attribute(null, ATTR_PACKAGE, settings.getPackageName());
1008                             serializer.attributeInt(null, ATTR_CUR_LEVEL,
1009                                     settings.mCurrentRestrictionLevel);
1010                             serializer.attributeLong(null, ATTR_LEVEL_TS,
1011                                     settings.mLevelChangeTime);
1012                             serializer.attributeInt(null, ATTR_REASON, settings.mReason);
1013                             for (int k = 0; k < NotificationHelper.NOTIFICATION_TYPE_LAST; k++) {
1014                                 serializer.attributeLong(null,
1015                                         NotificationHelper.notificationTypeToTimeAttr(k),
1016                                         settings.getLastNotificationTime(k));
1017                             }
1018                             serializer.endTag(null, TAG_SETTINGS);
1019                         }
1020                     }
1021                 }
1022 
1023                 serializer.endDocument();
1024                 serializer.flush();
1025 
1026                 return os.toByteArray();
1027             } catch (IOException e) {
1028                 return null;
1029             }
1030         }
1031 
1032         @VisibleForTesting
removeXml()1033         void removeXml() {
1034             final int[] allUsers = mInjector.getUserManagerInternal().getUserIds();
1035             for (int userId : allUsers) {
1036                 getXmlFileNameForUser(userId).delete();
1037             }
1038         }
1039 
1040         @Override
clone()1041         public Object clone() {
1042             final RestrictionSettings newObj = new RestrictionSettings();
1043             synchronized (mSettingsLock) {
1044                 for (int i = mRestrictionLevels.numMaps() - 1; i >= 0; i--) {
1045                     for (int j = mRestrictionLevels.numElementsForKeyAt(i) - 1; j >= 0; j--) {
1046                         final PkgSettings settings = mRestrictionLevels.valueAt(i, j);
1047                         newObj.mRestrictionLevels.add(mRestrictionLevels.keyAt(i),
1048                                 mRestrictionLevels.keyAt(i, j), (PkgSettings) settings.clone());
1049                     }
1050                 }
1051             }
1052             return newObj;
1053         }
1054 
1055         @Override
equals(Object other)1056         public boolean equals(Object other) {
1057             if (other == this) {
1058                 return true;
1059             }
1060             if (other == null || !(other instanceof RestrictionSettings)) {
1061                 return false;
1062             }
1063             final SparseArrayMap<String, PkgSettings> otherSettings = ((RestrictionSettings) other)
1064                     .mRestrictionLevels;
1065             synchronized (mSettingsLock) {
1066                 if (otherSettings.numMaps() != mRestrictionLevels.numMaps()) {
1067                     return false;
1068                 }
1069                 for (int i = mRestrictionLevels.numMaps() - 1; i >= 0; i--) {
1070                     final int uid = mRestrictionLevels.keyAt(i);
1071                     if (otherSettings.numElementsForKey(uid)
1072                             != mRestrictionLevels.numElementsForKeyAt(i)) {
1073                         return false;
1074                     }
1075                     for (int j = mRestrictionLevels.numElementsForKeyAt(i) - 1; j >= 0; j--) {
1076                         final PkgSettings settings = mRestrictionLevels.valueAt(i, j);
1077                         if (!settings.equals(otherSettings.get(uid, settings.getPackageName()))) {
1078                             return false;
1079                         }
1080                     }
1081                 }
1082             }
1083             return true;
1084         }
1085     }
1086 
1087     final class ConstantsObserver implements OnPropertiesChangedListener {
1088         /**
1089          * Whether or not to set the app to restricted standby bucket automatically
1090          * when it's background-restricted.
1091          */
1092         static final String KEY_BG_AUTO_RESTRICTED_BUCKET_ON_BG_RESTRICTION =
1093                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "auto_restricted_bucket_on_bg_restricted";
1094 
1095         /**
1096          * Whether or not to move the app to restricted standby level automatically
1097          * when system detects it's abusive.
1098          */
1099         static final String KEY_BG_AUTO_RESTRICT_ABUSIVE_APPS =
1100                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "auto_restrict_abusive_apps";
1101 
1102         /**
1103          * The minimal interval in ms before posting a notification again on abusive behaviors
1104          * of a certain package.
1105          */
1106         static final String KEY_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL =
1107                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "abusive_notification_minimal_interval";
1108 
1109         /**
1110          * The minimal interval in ms before posting a notification again on long running FGS
1111          * from a certain package.
1112          */
1113         static final String KEY_BG_LONG_FGS_NOTIFICATION_MINIMAL_INTERVAL =
1114                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "long_fgs_notification_minimal_interval";
1115 
1116         /**
1117          * The behavior for an app with a FGS and its notification is still showing, when the system
1118          * detects it's abusive and should be put into bg restricted level. {@code true} - we'll
1119          * show the prompt to user, {@code false} - we'll not show it.
1120          */
1121         static final String KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED =
1122                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "prompt_fgs_with_noti_to_bg_restricted";
1123 
1124         /**
1125          * The behavior for an app with a FGS and its notification is still showing, when the system
1126          * detects it's running for a very long time, should we prompt the user.
1127          * {@code true} - we'll show the prompt to user, {@code false} - we'll not show it.
1128          */
1129         static final String KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING =
1130                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "prompt_fgs_with_noti_on_long_running";
1131 
1132         /**
1133          * The behavior for an app with a FGS, when the system detects it's running for
1134          * a very long time, should we prompt the user.
1135          * {@code true} - we'll show the prompt to user, {@code false} - we'll not show it.
1136          */
1137         static final String KEY_BG_PROMPT_FGS_ON_LONG_RUNNING =
1138                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "prompt_fgs_on_long_running";
1139 
1140         /**
1141          * The list of packages to be exempted from all these background restrictions.
1142          */
1143         static final String KEY_BG_RESTRICTION_EXEMPTED_PACKAGES =
1144                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "restriction_exempted_packages";
1145 
1146         /**
1147          * Whether or not to show the notification for abusive apps, i.e. when the system
1148          * detects it's draining significant amount of battery in the background.
1149          * {@code true} - we'll show the prompt to user, {@code false} - we'll not show it.
1150          */
1151         static final String KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED =
1152                 DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "prompt_abusive_apps_to_bg_restricted";
1153 
1154         /**
1155          * Default value to {@link #mBgAutoRestrictAbusiveApps}.
1156          */
1157         static final boolean DEFAULT_BG_AUTO_RESTRICT_ABUSIVE_APPS = true;
1158 
1159         /**
1160          * Default value to {@link #mBgAutoRestrictedBucket}.
1161          */
1162         static final boolean DEFAULT_BG_AUTO_RESTRICTED_BUCKET_ON_BG_RESTRICTION = false;
1163 
1164         /**
1165          * Default value to {@link #mBgAbusiveNotificationMinIntervalMs}.
1166          */
1167         static final long DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS = 30 * ONE_DAY;
1168 
1169         /**
1170          * Default value to {@link #mBgAbusiveNotificationMinIntervalMs}.
1171          */
1172         static final long DEFAULT_BG_LONG_FGS_NOTIFICATION_MINIMAL_INTERVAL_MS = 30 * ONE_DAY;
1173 
1174         /**
1175          * Default value to {@link #mBgPromptFgsWithNotiOnLongRunning}.
1176          */
1177         static final boolean DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING = false;
1178 
1179         /**
1180          * Default value to {@link #mBgPromptFgsOnLongRunning}.
1181          */
1182         static final boolean DEFAULT_BG_PROMPT_FGS_ON_LONG_RUNNING = true;
1183 
1184         /**
1185          * Default value to {@link #mBgPromptFgsWithNotiToBgRestricted}.
1186          */
1187         final boolean mDefaultBgPromptFgsWithNotiToBgRestricted;
1188 
1189         /**
1190          * Default value to {@link #mBgPromptAbusiveAppsToBgRestricted}.
1191          */
1192         final boolean mDefaultBgPromptAbusiveAppToBgRestricted;
1193 
1194         volatile boolean mBgAutoRestrictedBucket;
1195 
1196         volatile boolean mBgAutoRestrictAbusiveApps;
1197 
1198         volatile long mBgAbusiveNotificationMinIntervalMs;
1199 
1200         volatile long mBgLongFgsNotificationMinIntervalMs;
1201 
1202         /**
1203          * @see #KEY_BG_RESTRICTION_EXEMPTED_PACKAGES.
1204          *
1205          *<p> Mutations on them would result in copy-on-write.</p>
1206          */
1207         volatile Set<String> mBgRestrictionExemptedPackages = Collections.emptySet();
1208 
1209         /**
1210          * @see #KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED.
1211          */
1212         volatile boolean mBgPromptFgsWithNotiToBgRestricted;
1213 
1214         /**
1215          * @see #KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING.
1216          */
1217         volatile boolean mBgPromptFgsWithNotiOnLongRunning;
1218 
1219         /**
1220          * @see #KEY_BG_PROMPT_FGS_ON_LONG_RUNNING.
1221          */
1222         volatile boolean mBgPromptFgsOnLongRunning;
1223 
1224         /**
1225          * @see #KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED.
1226          */
1227         volatile boolean mBgPromptAbusiveAppsToBgRestricted;
1228 
ConstantsObserver(Handler handler, Context context)1229         ConstantsObserver(Handler handler, Context context) {
1230             mDefaultBgPromptFgsWithNotiToBgRestricted = context.getResources().getBoolean(
1231                     com.android.internal.R.bool.config_bg_prompt_fgs_with_noti_to_bg_restricted);
1232             mDefaultBgPromptAbusiveAppToBgRestricted = context.getResources().getBoolean(
1233                     com.android.internal.R.bool.config_bg_prompt_abusive_apps_to_bg_restricted);
1234         }
1235 
1236         @Override
onPropertiesChanged(Properties properties)1237         public void onPropertiesChanged(Properties properties) {
1238             for (String name : properties.getKeyset()) {
1239                 if (name == null || !name.startsWith(DEVICE_CONFIG_SUBNAMESPACE_PREFIX)) {
1240                     return;
1241                 }
1242                 switch (name) {
1243                     case KEY_BG_AUTO_RESTRICTED_BUCKET_ON_BG_RESTRICTION:
1244                         updateBgAutoRestrictedBucketChanged();
1245                         break;
1246                     case KEY_BG_AUTO_RESTRICT_ABUSIVE_APPS:
1247                         updateBgAutoRestrictAbusiveApps();
1248                         break;
1249                     case KEY_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL:
1250                         updateBgAbusiveNotificationMinimalInterval();
1251                         break;
1252                     case KEY_BG_LONG_FGS_NOTIFICATION_MINIMAL_INTERVAL:
1253                         updateBgLongFgsNotificationMinimalInterval();
1254                         break;
1255                     case KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED:
1256                         updateBgPromptFgsWithNotiToBgRestricted();
1257                         break;
1258                     case KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING:
1259                         updateBgPromptFgsWithNotiOnLongRunning();
1260                         break;
1261                     case KEY_BG_PROMPT_FGS_ON_LONG_RUNNING:
1262                         updateBgPromptFgsOnLongRunning();
1263                         break;
1264                     case KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED:
1265                         updateBgPromptAbusiveAppToBgRestricted();
1266                         break;
1267                     case KEY_BG_RESTRICTION_EXEMPTED_PACKAGES:
1268                         updateBgRestrictionExemptedPackages();
1269                         break;
1270                 }
1271                 AppRestrictionController.this.onPropertiesChanged(name);
1272             }
1273         }
1274 
start()1275         public void start() {
1276             updateDeviceConfig();
1277         }
1278 
updateDeviceConfig()1279         void updateDeviceConfig() {
1280             updateBgAutoRestrictedBucketChanged();
1281             updateBgAutoRestrictAbusiveApps();
1282             updateBgAbusiveNotificationMinimalInterval();
1283             updateBgLongFgsNotificationMinimalInterval();
1284             updateBgPromptFgsWithNotiToBgRestricted();
1285             updateBgPromptFgsWithNotiOnLongRunning();
1286             updateBgPromptFgsOnLongRunning();
1287             updateBgPromptAbusiveAppToBgRestricted();
1288             updateBgRestrictionExemptedPackages();
1289         }
1290 
updateBgAutoRestrictedBucketChanged()1291         private void updateBgAutoRestrictedBucketChanged() {
1292             boolean oldValue = mBgAutoRestrictedBucket;
1293             mBgAutoRestrictedBucket = DeviceConfig.getBoolean(
1294                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1295                     KEY_BG_AUTO_RESTRICTED_BUCKET_ON_BG_RESTRICTION,
1296                     DEFAULT_BG_AUTO_RESTRICTED_BUCKET_ON_BG_RESTRICTION);
1297             if (oldValue != mBgAutoRestrictedBucket) {
1298                 dispatchAutoRestrictedBucketFeatureFlagChanged(mBgAutoRestrictedBucket);
1299             }
1300         }
1301 
updateBgAutoRestrictAbusiveApps()1302         private void updateBgAutoRestrictAbusiveApps() {
1303             mBgAutoRestrictAbusiveApps = DeviceConfig.getBoolean(
1304                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1305                     KEY_BG_AUTO_RESTRICT_ABUSIVE_APPS,
1306                     DEFAULT_BG_AUTO_RESTRICT_ABUSIVE_APPS);
1307         }
1308 
updateBgAbusiveNotificationMinimalInterval()1309         private void updateBgAbusiveNotificationMinimalInterval() {
1310             mBgAbusiveNotificationMinIntervalMs = DeviceConfig.getLong(
1311                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1312                     KEY_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL,
1313                     DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS);
1314         }
1315 
updateBgLongFgsNotificationMinimalInterval()1316         private void updateBgLongFgsNotificationMinimalInterval() {
1317             mBgLongFgsNotificationMinIntervalMs = DeviceConfig.getLong(
1318                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1319                     KEY_BG_LONG_FGS_NOTIFICATION_MINIMAL_INTERVAL,
1320                     DEFAULT_BG_LONG_FGS_NOTIFICATION_MINIMAL_INTERVAL_MS);
1321         }
1322 
updateBgPromptFgsWithNotiToBgRestricted()1323         private void updateBgPromptFgsWithNotiToBgRestricted() {
1324             mBgPromptFgsWithNotiToBgRestricted = DeviceConfig.getBoolean(
1325                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1326                     KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED,
1327                     mDefaultBgPromptFgsWithNotiToBgRestricted);
1328         }
1329 
updateBgPromptFgsWithNotiOnLongRunning()1330         private void updateBgPromptFgsWithNotiOnLongRunning() {
1331             mBgPromptFgsWithNotiOnLongRunning = DeviceConfig.getBoolean(
1332                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1333                     KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING,
1334                     DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
1335         }
1336 
updateBgPromptFgsOnLongRunning()1337         private void updateBgPromptFgsOnLongRunning() {
1338             mBgPromptFgsOnLongRunning = DeviceConfig.getBoolean(
1339                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1340                     KEY_BG_PROMPT_FGS_ON_LONG_RUNNING,
1341                     DEFAULT_BG_PROMPT_FGS_ON_LONG_RUNNING);
1342         }
1343 
updateBgPromptAbusiveAppToBgRestricted()1344         private void updateBgPromptAbusiveAppToBgRestricted() {
1345             mBgPromptAbusiveAppsToBgRestricted = DeviceConfig.getBoolean(
1346                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1347                     KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED,
1348                     mDefaultBgPromptAbusiveAppToBgRestricted);
1349         }
1350 
updateBgRestrictionExemptedPackages()1351         private void updateBgRestrictionExemptedPackages() {
1352             final String settings = DeviceConfig.getString(
1353                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1354                     KEY_BG_RESTRICTION_EXEMPTED_PACKAGES,
1355                     null);
1356             if (settings == null) {
1357                 mBgRestrictionExemptedPackages = Collections.emptySet();
1358                 return;
1359             }
1360             final String[] settingsList = settings.split(",");
1361             final ArraySet<String> packages = new ArraySet<>();
1362             for (String pkg : settingsList) {
1363                 packages.add(pkg);
1364             }
1365             mBgRestrictionExemptedPackages = Collections.unmodifiableSet(packages);
1366         }
1367 
dump(PrintWriter pw, String prefix)1368         void dump(PrintWriter pw, String prefix) {
1369             pw.print(prefix);
1370             pw.println("BACKGROUND RESTRICTION POLICY SETTINGS:");
1371             final String indent = "  ";
1372             prefix = indent + prefix;
1373             pw.print(prefix);
1374             pw.print(KEY_BG_AUTO_RESTRICTED_BUCKET_ON_BG_RESTRICTION);
1375             pw.print('=');
1376             pw.println(mBgAutoRestrictedBucket);
1377             pw.print(prefix);
1378             pw.print(KEY_BG_AUTO_RESTRICT_ABUSIVE_APPS);
1379             pw.print('=');
1380             pw.println(mBgAutoRestrictAbusiveApps);
1381             pw.print(prefix);
1382             pw.print(KEY_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL);
1383             pw.print('=');
1384             pw.println(mBgAbusiveNotificationMinIntervalMs);
1385             pw.print(prefix);
1386             pw.print(KEY_BG_LONG_FGS_NOTIFICATION_MINIMAL_INTERVAL);
1387             pw.print('=');
1388             pw.println(mBgLongFgsNotificationMinIntervalMs);
1389             pw.print(prefix);
1390             pw.print(KEY_BG_PROMPT_FGS_ON_LONG_RUNNING);
1391             pw.print('=');
1392             pw.println(mBgPromptFgsOnLongRunning);
1393             pw.print(prefix);
1394             pw.print(KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
1395             pw.print('=');
1396             pw.println(mBgPromptFgsWithNotiOnLongRunning);
1397             pw.print(prefix);
1398             pw.print(KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_TO_BG_RESTRICTED);
1399             pw.print('=');
1400             pw.println(mBgPromptFgsWithNotiToBgRestricted);
1401             pw.print(prefix);
1402             pw.print(KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED);
1403             pw.print('=');
1404             pw.println(mBgPromptAbusiveAppsToBgRestricted);
1405             pw.print(prefix);
1406             pw.print(KEY_BG_RESTRICTION_EXEMPTED_PACKAGES);
1407             pw.print('=');
1408             pw.println(mBgRestrictionExemptedPackages.toString());
1409         }
1410     }
1411 
1412     /**
1413      * A helper object which holds an app state tracker's type and its relevant info used for
1414      * logging atoms to statsd.
1415      */
1416     private class TrackerInfo {
1417         final int mType; // tracker type
1418         final byte[] mInfo; // tracker info proto object for statsd
1419 
TrackerInfo()1420         TrackerInfo() {
1421             mType = TRACKER_TYPE_UNKNOWN;
1422             mInfo = null;
1423         }
1424 
TrackerInfo(int type, byte[] info)1425         TrackerInfo(int type, byte[] info) {
1426             mType = type;
1427             mInfo = info;
1428         }
1429     }
1430 
1431     private final ConstantsObserver mConstantsObserver;
1432 
1433     private final AppStateTracker.BackgroundRestrictedAppListener mBackgroundRestrictionListener =
1434             new AppStateTracker.BackgroundRestrictedAppListener() {
1435                 @Override
1436                 public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
1437                         boolean restricted) {
1438                     mBgHandler.obtainMessage(BgHandler.MSG_BACKGROUND_RESTRICTION_CHANGED,
1439                             uid, restricted ? 1 : 0, packageName).sendToTarget();
1440                 }
1441             };
1442 
1443     private final AppIdleStateChangeListener mAppIdleStateChangeListener =
1444             new AppIdleStateChangeListener() {
1445                 @Override
1446                 public void onAppIdleStateChanged(String packageName, @UserIdInt int userId,
1447                         boolean idle, int bucket, int reason) {
1448                     mBgHandler.obtainMessage(BgHandler.MSG_APP_STANDBY_BUCKET_CHANGED,
1449                             userId, bucket, packageName).sendToTarget();
1450                 }
1451 
1452                 @Override
1453                 public void onUserInteractionStarted(String packageName, @UserIdInt int userId) {
1454                     mBgHandler.obtainMessage(BgHandler.MSG_USER_INTERACTION_STARTED,
1455                             userId, 0, packageName).sendToTarget();
1456                 }
1457             };
1458 
1459     private final IUidObserver mUidObserver =
1460             new UidObserver() {
1461                 @Override
1462                 public void onUidStateChanged(int uid, int procState, long procStateSeq,
1463                         int capability) {
1464                     mBgHandler.obtainMessage(BgHandler.MSG_UID_PROC_STATE_CHANGED, uid, procState)
1465                             .sendToTarget();
1466                 }
1467 
1468                 @Override
1469                 public void onUidIdle(int uid, boolean disabled) {
1470                     mBgHandler.obtainMessage(BgHandler.MSG_UID_IDLE, uid, disabled ? 1 : 0)
1471                             .sendToTarget();
1472                 }
1473 
1474                 @Override
1475                 public void onUidGone(int uid, boolean disabled) {
1476                     mBgHandler.obtainMessage(BgHandler.MSG_UID_GONE, uid, disabled ? 1 : 0)
1477                             .sendToTarget();
1478                 }
1479 
1480                 @Override
1481                 public void onUidActive(int uid) {
1482                     mBgHandler.obtainMessage(BgHandler.MSG_UID_ACTIVE, uid, 0).sendToTarget();
1483                 }
1484             };
1485 
1486     /**
1487      * Register the background restriction listener callback.
1488      */
addAppBackgroundRestrictionListener( @onNull AppBackgroundRestrictionListener listener)1489     public void addAppBackgroundRestrictionListener(
1490             @NonNull AppBackgroundRestrictionListener listener) {
1491         mRestrictionListeners.add(listener);
1492     }
1493 
AppRestrictionController(final Context context, final ActivityManagerService service)1494     AppRestrictionController(final Context context, final ActivityManagerService service) {
1495         this(new Injector(context), service);
1496     }
1497 
AppRestrictionController(final Injector injector, final ActivityManagerService service)1498     AppRestrictionController(final Injector injector, final ActivityManagerService service) {
1499         mInjector = injector;
1500         mContext = injector.getContext();
1501         mActivityManagerService = service;
1502         mBgHandlerThread = new HandlerThread("bgres-controller", THREAD_PRIORITY_BACKGROUND);
1503         mBgHandlerThread.start();
1504         mBgHandler = new BgHandler(mBgHandlerThread.getLooper(), injector);
1505         mBgExecutor = new HandlerExecutor(mBgHandler);
1506         mConstantsObserver = new ConstantsObserver(mBgHandler, mContext);
1507         mNotificationHelper = new NotificationHelper(this);
1508         injector.initAppStateTrackers(this);
1509         mExecutor = new HandlerExecutor(injector.getDefaultHandler());
1510     }
1511 
onSystemReady()1512     void onSystemReady() {
1513         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
1514                 mBgExecutor, mConstantsObserver);
1515         mConstantsObserver.start();
1516         initBgRestrictionExemptioFromSysConfig();
1517         initRestrictionStates();
1518         initSystemModuleNames();
1519         initRolesInInterest();
1520         registerForUidObservers();
1521         registerForSystemBroadcasts();
1522         registerCarrierPrivilegesCallbacks();
1523         mNotificationHelper.onSystemReady();
1524         mInjector.getAppStateTracker().addBackgroundRestrictedAppListener(
1525                 mBackgroundRestrictionListener);
1526         mInjector.getAppStandbyInternal().addListener(mAppIdleStateChangeListener);
1527         mInjector.getRoleManager().addOnRoleHoldersChangedListenerAsUser(mExecutor,
1528                 mRoleHolderChangedListener, UserHandle.ALL);
1529         mInjector.scheduleInitTrackers(mBgHandler, () -> {
1530             for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
1531                 mAppStateTrackers.get(i).onSystemReady();
1532             }
1533         });
1534     }
1535 
1536     @VisibleForTesting
resetRestrictionSettings()1537     void resetRestrictionSettings() {
1538         synchronized (mSettingsLock) {
1539             mRestrictionSettings.reset();
1540         }
1541         initRestrictionStates();
1542     }
1543 
1544     @VisibleForTesting
tearDown()1545     void tearDown() {
1546         DeviceConfig.removeOnPropertiesChangedListener(mConstantsObserver);
1547         unregisterForUidObservers();
1548         unregisterForSystemBroadcasts();
1549         mRestrictionSettings.removeXml();
1550     }
1551 
initBgRestrictionExemptioFromSysConfig()1552     private void initBgRestrictionExemptioFromSysConfig() {
1553         final SystemConfig sysConfig = SystemConfig.getInstance();
1554         mBgRestrictionExemptioFromSysConfig = sysConfig.getBgRestrictionExemption();
1555         if (DEBUG_BG_RESTRICTION_CONTROLLER) {
1556             final ArraySet<String> exemptedPkgs = mBgRestrictionExemptioFromSysConfig;
1557             for (int i = exemptedPkgs.size() - 1; i >= 0; i--) {
1558                 Slog.i(TAG, "bg-restriction-exemption: " + exemptedPkgs.valueAt(i));
1559             }
1560         }
1561         loadAppIdsFromPackageList(sysConfig.getAllowInPowerSaveExceptIdle(),
1562                 mSystemDeviceIdleExceptIdleAllowlist);
1563         loadAppIdsFromPackageList(sysConfig.getAllowInPowerSave(), mSystemDeviceIdleAllowlist);
1564     }
1565 
loadAppIdsFromPackageList(ArraySet<String> packages, ArraySet<Integer> apps)1566     private void loadAppIdsFromPackageList(ArraySet<String> packages, ArraySet<Integer> apps) {
1567         final PackageManager pm = mInjector.getPackageManager();
1568         for (int i = packages.size() - 1; i >= 0; i--) {
1569             final String pkg = packages.valueAt(i);
1570             try {
1571                 final ApplicationInfo ai = pm.getApplicationInfo(pkg,
1572                         PackageManager.MATCH_SYSTEM_ONLY);
1573                 if (ai == null) {
1574                     continue;
1575                 }
1576                 apps.add(UserHandle.getAppId(ai.uid));
1577             } catch (PackageManager.NameNotFoundException e) {
1578             }
1579         }
1580     }
1581 
isExemptedFromSysConfig(String packageName)1582     private boolean isExemptedFromSysConfig(String packageName) {
1583         return mBgRestrictionExemptioFromSysConfig != null
1584                 && mBgRestrictionExemptioFromSysConfig.contains(packageName);
1585     }
1586 
initRestrictionStates()1587     private void initRestrictionStates() {
1588         final int[] allUsers = mInjector.getUserManagerInternal().getUserIds();
1589         for (int userId : allUsers) {
1590             refreshAppRestrictionLevelForUser(userId, REASON_MAIN_FORCED_BY_USER,
1591                     REASON_SUB_FORCED_USER_FLAG_INTERACTION);
1592         }
1593         if (!mInjector.isTest()) {
1594             // Load the previously saved levels and update the current levels if needed.
1595             mRestrictionSettings.scheduleLoadFromXml();
1596             // Also save the current levels right away.
1597             for (int userId : allUsers) {
1598                 mRestrictionSettings.schedulePersistToXml(userId);
1599             }
1600         }
1601     }
1602 
initSystemModuleNames()1603     private void initSystemModuleNames() {
1604         final PackageManager pm = mInjector.getPackageManager();
1605         final List<ModuleInfo> moduleInfos = pm.getInstalledModules(0 /* flags */);
1606         if (moduleInfos == null) {
1607             return;
1608         }
1609         synchronized (mSystemModulesCache) {
1610             for (ModuleInfo info : moduleInfos) {
1611                 mSystemModulesCache.put(info.getPackageName(), Boolean.TRUE);
1612             }
1613         }
1614     }
1615 
isSystemModule(String packageName)1616     private boolean isSystemModule(String packageName) {
1617         synchronized (mSystemModulesCache) {
1618             final Boolean val = mSystemModulesCache.get(packageName);
1619             if (val != null) {
1620                 return val.booleanValue();
1621             }
1622         }
1623 
1624         // Slow path: check if the package is listed among the system modules.
1625         final PackageManager pm = mInjector.getPackageManager();
1626         boolean isSystemModule = false;
1627         try {
1628             isSystemModule = pm.getModuleInfo(packageName, 0 /* flags */) != null;
1629         } catch (PackageManager.NameNotFoundException e) {
1630         }
1631 
1632         if (!isSystemModule) {
1633             try {
1634                 final PackageInfo pkg = pm.getPackageInfo(packageName, 0 /* flags */);
1635                 // Check if the package is contained in an APEX. There is no public API to properly
1636                 // check whether a given APK package comes from an APEX registered as module.
1637                 // Therefore we conservatively assume that any package scanned from an /apex path is
1638                 // a system package.
1639                 isSystemModule = pkg != null && pkg.applicationInfo.sourceDir.startsWith(
1640                         Environment.getApexDirectory().getAbsolutePath());
1641             } catch (PackageManager.NameNotFoundException e) {
1642             }
1643         }
1644         // Update the cache.
1645         synchronized (mSystemModulesCache) {
1646             mSystemModulesCache.put(packageName, isSystemModule);
1647         }
1648         return isSystemModule;
1649     }
1650 
registerForUidObservers()1651     private void registerForUidObservers() {
1652         try {
1653             mInjector.getIActivityManager().registerUidObserver(mUidObserver,
1654                     UID_OBSERVER_ACTIVE | UID_OBSERVER_GONE | UID_OBSERVER_IDLE
1655                     | UID_OBSERVER_PROCSTATE, PROCESS_STATE_FOREGROUND_SERVICE, "android");
1656         } catch (RemoteException e) {
1657             // Intra-process call, it won't happen.
1658         }
1659     }
1660 
unregisterForUidObservers()1661     private void unregisterForUidObservers() {
1662         try {
1663             mInjector.getIActivityManager().unregisterUidObserver(mUidObserver);
1664         } catch (RemoteException e) {
1665             // Intra-process call, it won't happen.
1666         }
1667     }
1668 
1669     /**
1670      * Called when initializing a user.
1671      */
refreshAppRestrictionLevelForUser(@serIdInt int userId, int reason, int subReason)1672     private void refreshAppRestrictionLevelForUser(@UserIdInt int userId, int reason,
1673             int subReason) {
1674         final List<AppStandbyInfo> appStandbyInfos = mInjector.getAppStandbyInternal()
1675                 .getAppStandbyBuckets(userId);
1676         if (ArrayUtils.isEmpty(appStandbyInfos)) {
1677             return;
1678         }
1679 
1680         if (DEBUG_BG_RESTRICTION_CONTROLLER) {
1681             Slog.i(TAG, "Refreshing restriction levels of user " + userId);
1682         }
1683         final PackageManagerInternal pm = mInjector.getPackageManagerInternal();
1684         for (AppStandbyInfo info: appStandbyInfos) {
1685             final int uid = pm.getPackageUid(info.mPackageName, STOCK_PM_FLAGS, userId);
1686             if (uid < 0) {
1687                 // Shouldn't happen.
1688                 Slog.e(TAG, "Unable to find " + info.mPackageName + "/u" + userId);
1689                 continue;
1690             }
1691             final Pair<Integer, TrackerInfo> levelTypePair = calcAppRestrictionLevel(
1692                     userId, uid, info.mPackageName, info.mStandbyBucket, false, false);
1693             if (DEBUG_BG_RESTRICTION_CONTROLLER) {
1694                 Slog.i(TAG, "Proposed restriction level of " + info.mPackageName + "/"
1695                         + UserHandle.formatUid(uid) + ": "
1696                         + ActivityManager.restrictionLevelToName(levelTypePair.first)
1697                         + " " + info.mStandbyBucket);
1698             }
1699             applyRestrictionLevel(info.mPackageName, uid, levelTypePair.first, levelTypePair.second,
1700                     info.mStandbyBucket, true, reason, subReason);
1701         }
1702     }
1703 
refreshAppRestrictionLevelForUid(int uid, int reason, int subReason, boolean allowRequestBgRestricted)1704     void refreshAppRestrictionLevelForUid(int uid, int reason, int subReason,
1705             boolean allowRequestBgRestricted) {
1706         final String[] packages = mInjector.getPackageManager().getPackagesForUid(uid);
1707         if (ArrayUtils.isEmpty(packages)) {
1708             return;
1709         }
1710         final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal();
1711         final int userId = UserHandle.getUserId(uid);
1712         final long now = SystemClock.elapsedRealtime();
1713         for (String pkg: packages) {
1714             final int curBucket = appStandbyInternal.getAppStandbyBucket(pkg, userId, now, false);
1715             final Pair<Integer, TrackerInfo> levelTypePair = calcAppRestrictionLevel(userId, uid,
1716                     pkg, curBucket, allowRequestBgRestricted, true);
1717             if (DEBUG_BG_RESTRICTION_CONTROLLER) {
1718                 Slog.i(TAG, "Proposed restriction level of " + pkg + "/"
1719                         + UserHandle.formatUid(uid) + ": "
1720                         + ActivityManager.restrictionLevelToName(levelTypePair.first));
1721             }
1722             applyRestrictionLevel(pkg, uid, levelTypePair.first, levelTypePair.second,
1723                     curBucket, true, reason, subReason);
1724         }
1725     }
1726 
calcAppRestrictionLevel(@serIdInt int userId, int uid, String packageName, @UsageStatsManager.StandbyBuckets int standbyBucket, boolean allowRequestBgRestricted, boolean calcTrackers)1727     private Pair<Integer, TrackerInfo> calcAppRestrictionLevel(@UserIdInt int userId, int uid,
1728             String packageName, @UsageStatsManager.StandbyBuckets int standbyBucket,
1729             boolean allowRequestBgRestricted, boolean calcTrackers) {
1730         if (mInjector.getAppHibernationInternal().isHibernatingForUser(packageName, userId)) {
1731             return new Pair<>(RESTRICTION_LEVEL_FORCE_STOPPED, mEmptyTrackerInfo);
1732         }
1733         @RestrictionLevel int level;
1734         TrackerInfo trackerInfo = null;
1735         switch (standbyBucket) {
1736             case STANDBY_BUCKET_EXEMPTED:
1737                 level = RESTRICTION_LEVEL_EXEMPTED;
1738                 break;
1739             case STANDBY_BUCKET_NEVER:
1740                 if (!android.app.Flags.appRestrictionsApi()) {
1741                     level = RESTRICTION_LEVEL_BACKGROUND_RESTRICTED;
1742                     break;
1743                 }
1744             case STANDBY_BUCKET_ACTIVE:
1745             case STANDBY_BUCKET_WORKING_SET:
1746             case STANDBY_BUCKET_FREQUENT:
1747             case STANDBY_BUCKET_RARE:
1748             case STANDBY_BUCKET_RESTRICTED:
1749             default:
1750                 if (mInjector.getAppStateTracker()
1751                         .isAppBackgroundRestricted(uid, packageName)) {
1752                     return new Pair<>(RESTRICTION_LEVEL_BACKGROUND_RESTRICTED, mEmptyTrackerInfo);
1753                 }
1754                 level = standbyBucket == STANDBY_BUCKET_RESTRICTED
1755                         ? RESTRICTION_LEVEL_RESTRICTED_BUCKET
1756                         : RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
1757                 if (calcTrackers) {
1758                     Pair<Integer, TrackerInfo> levelTypePair = calcAppRestrictionLevelFromTackers(
1759                             uid, packageName, RESTRICTION_LEVEL_MAX);
1760                     @RestrictionLevel int l = levelTypePair.first;
1761                     if (l == RESTRICTION_LEVEL_EXEMPTED) {
1762                         return new Pair<>(RESTRICTION_LEVEL_EXEMPTED, levelTypePair.second);
1763                     }
1764                     if (l > level) {
1765                         level = l;
1766                         trackerInfo = levelTypePair.second;
1767                     }
1768                     if (level == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
1769                         // This level can't be entered without user consent
1770                         if (allowRequestBgRestricted) {
1771                             mBgHandler.obtainMessage(BgHandler.MSG_REQUEST_BG_RESTRICTED,
1772                                     uid, 0, packageName).sendToTarget();
1773                         }
1774                         // Lower the level.
1775                         levelTypePair = calcAppRestrictionLevelFromTackers(uid, packageName,
1776                                 RESTRICTION_LEVEL_BACKGROUND_RESTRICTED);
1777                         level = levelTypePair.first;
1778                         trackerInfo = levelTypePair.second;
1779                     }
1780                 }
1781                 break;
1782         }
1783         return new Pair<>(level, trackerInfo);
1784     }
1785 
1786     /**
1787      * Ask each of the trackers for their proposed restriction levels for the given uid/package,
1788      * and return the most restrictive level along with the type of tracker and its relevant info
1789      * which applied this restriction level as a {@code Pair<@RestrictionLevel, TrackerInfo>}.
1790      *
1791      * <p>Note, it's different from the {@link #getRestrictionLevel} where it returns the least
1792      * restrictive level. We're returning the most restrictive level here because each tracker
1793      * monitors certain dimensions of the app, the abusive behaviors could be detected in one or
1794      * more of these dimensions, but not necessarily all of them. </p>
1795      */
calcAppRestrictionLevelFromTackers(int uid, String packageName, @RestrictionLevel int maxLevel)1796     private Pair<Integer, TrackerInfo> calcAppRestrictionLevelFromTackers(int uid,
1797             String packageName, @RestrictionLevel int maxLevel) {
1798         @RestrictionLevel int level = RESTRICTION_LEVEL_UNKNOWN;
1799         @RestrictionLevel int prevLevel = level;
1800         BaseAppStateTracker resultTracker = null;
1801         for (int i = mAppStateTrackers.size() - 1; i >= 0; i--) {
1802             @RestrictionLevel int l = mAppStateTrackers.get(i).getPolicy()
1803                     .getProposedRestrictionLevel(packageName, uid, maxLevel);
1804             level = Math.max(level, l);
1805             if (level != prevLevel) {
1806                 resultTracker = mAppStateTrackers.get(i);
1807                 prevLevel = level;
1808             }
1809         }
1810         final TrackerInfo trackerInfo = resultTracker == null
1811                                             ? mEmptyTrackerInfo
1812                                             : new TrackerInfo(resultTracker.getType(),
1813                                                     resultTracker.getTrackerInfoForStatsd(uid));
1814         return new Pair<>(level, trackerInfo);
1815     }
1816 
standbyBucketToRestrictionLevel( @sageStatsManager.StandbyBuckets int standbyBucket)1817     private static @RestrictionLevel int standbyBucketToRestrictionLevel(
1818             @UsageStatsManager.StandbyBuckets int standbyBucket) {
1819         switch (standbyBucket) {
1820             case STANDBY_BUCKET_EXEMPTED:
1821                 return RESTRICTION_LEVEL_EXEMPTED;
1822             case STANDBY_BUCKET_NEVER:
1823                 if (!android.app.Flags.appRestrictionsApi()) {
1824                     return RESTRICTION_LEVEL_BACKGROUND_RESTRICTED;
1825                 }
1826             case STANDBY_BUCKET_ACTIVE:
1827             case STANDBY_BUCKET_WORKING_SET:
1828             case STANDBY_BUCKET_FREQUENT:
1829             case STANDBY_BUCKET_RARE:
1830                 return RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
1831             case STANDBY_BUCKET_RESTRICTED:
1832                 return RESTRICTION_LEVEL_RESTRICTED_BUCKET;
1833             default:
1834                 return RESTRICTION_LEVEL_UNKNOWN;
1835         }
1836     }
1837 
1838     /**
1839      * Get the restriction level of the given UID, if it hosts multiple packages,
1840      * return least restricted one (or if any of them is exempted).
1841      */
getRestrictionLevel(int uid)1842     @RestrictionLevel int getRestrictionLevel(int uid) {
1843         return mRestrictionSettings.getRestrictionLevel(uid);
1844     }
1845 
1846     /**
1847      * Get the restriction level of the given UID and package.
1848      */
getRestrictionLevel(int uid, String packageName)1849     @RestrictionLevel int getRestrictionLevel(int uid, String packageName) {
1850         return mRestrictionSettings.getRestrictionLevel(uid, packageName);
1851     }
1852 
1853     /**
1854      * Get the restriction level of the given package in given user id.
1855      */
getRestrictionLevel(String packageName, @UserIdInt int userId)1856     @RestrictionLevel int getRestrictionLevel(String packageName, @UserIdInt int userId) {
1857         return mRestrictionSettings.getRestrictionLevel(packageName, userId);
1858     }
1859 
1860     /**
1861      * @return Whether or not to move the app to restricted level automatically
1862      * when system detects it's abusive.
1863      */
isAutoRestrictAbusiveAppEnabled()1864     boolean isAutoRestrictAbusiveAppEnabled() {
1865         return mConstantsObserver.mBgAutoRestrictAbusiveApps;
1866     }
1867 
1868     /**
1869      * @return The total foreground service durations for the given package/uid with given
1870      * foreground service type, or the total durations regardless the type if the given type is 0.
1871      */
getForegroundServiceTotalDurations(String packageName, int uid, long now, @ForegroundServiceType int serviceType)1872     long getForegroundServiceTotalDurations(String packageName, int uid, long now,
1873             @ForegroundServiceType int serviceType) {
1874         return mInjector.getAppFGSTracker().getTotalDurations(packageName, uid, now,
1875                 foregroundServiceTypeToIndex(serviceType));
1876     }
1877 
1878     /**
1879      * @return The total foreground service durations for the given uid with given
1880      * foreground service type, or the total durations regardless the type if the given type is 0.
1881      */
getForegroundServiceTotalDurations(int uid, long now, @ForegroundServiceType int serviceType)1882     long getForegroundServiceTotalDurations(int uid, long now,
1883             @ForegroundServiceType int serviceType) {
1884         return mInjector.getAppFGSTracker().getTotalDurations(uid, now,
1885                 foregroundServiceTypeToIndex(serviceType));
1886     }
1887 
1888     /**
1889      * @return The foreground service durations since given timestamp for the given package/uid
1890      * with given foreground service type, or the total durations regardless the type if the given
1891      * type is 0.
1892      */
getForegroundServiceTotalDurationsSince(String packageName, int uid, long since, long now, @ForegroundServiceType int serviceType)1893     long getForegroundServiceTotalDurationsSince(String packageName, int uid, long since, long now,
1894             @ForegroundServiceType int serviceType) {
1895         return mInjector.getAppFGSTracker().getTotalDurationsSince(packageName, uid, since, now,
1896                 foregroundServiceTypeToIndex(serviceType));
1897     }
1898 
1899     /**
1900      * @return The foreground service durations since given timestamp for the given uid with given
1901      * foreground service type, or the total durations regardless the type if the given type is 0.
1902      */
getForegroundServiceTotalDurationsSince(int uid, long since, long now, @ForegroundServiceType int serviceType)1903     long getForegroundServiceTotalDurationsSince(int uid, long since, long now,
1904             @ForegroundServiceType int serviceType) {
1905         return mInjector.getAppFGSTracker().getTotalDurationsSince(uid, since, now,
1906                 foregroundServiceTypeToIndex(serviceType));
1907     }
1908 
1909     /**
1910      * @return The total durations for the given package/uid with active media session.
1911      */
getMediaSessionTotalDurations(String packageName, int uid, long now)1912     long getMediaSessionTotalDurations(String packageName, int uid, long now) {
1913         return mInjector.getAppMediaSessionTracker().getTotalDurations(packageName, uid, now);
1914     }
1915 
1916     /**
1917      * @return The total durations for the given uid with active media session.
1918      */
getMediaSessionTotalDurations(int uid, long now)1919     long getMediaSessionTotalDurations(int uid, long now) {
1920         return mInjector.getAppMediaSessionTracker().getTotalDurations(uid, now);
1921     }
1922 
1923     /**
1924      * @return The durations since given timestamp for the given package/uid with
1925      * active media session.
1926      */
getMediaSessionTotalDurationsSince(String packageName, int uid, long since, long now)1927     long getMediaSessionTotalDurationsSince(String packageName, int uid, long since, long now) {
1928         return mInjector.getAppMediaSessionTracker().getTotalDurationsSince(packageName, uid, since,
1929                 now);
1930     }
1931 
1932     /**
1933      * @return The durations since given timestamp for the given uid with active media session.
1934      */
getMediaSessionTotalDurationsSince(int uid, long since, long now)1935     long getMediaSessionTotalDurationsSince(int uid, long since, long now) {
1936         return mInjector.getAppMediaSessionTracker().getTotalDurationsSince(uid, since, now);
1937     }
1938 
1939     /**
1940      * @return The durations over the given window, where the given package/uid has either
1941      * foreground services with type "mediaPlayback" running, or active media session running.
1942      */
getCompositeMediaPlaybackDurations(String packageName, int uid, long now, long window)1943     long getCompositeMediaPlaybackDurations(String packageName, int uid, long now, long window) {
1944         final long since = Math.max(0, now - window);
1945         final long mediaPlaybackDuration = Math.max(
1946                 getMediaSessionTotalDurationsSince(packageName, uid, since, now),
1947                 getForegroundServiceTotalDurationsSince(packageName, uid, since, now,
1948                         ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK));
1949         return mediaPlaybackDuration;
1950     }
1951 
1952     /**
1953      * @return The durations over the given window, where the given uid has either foreground
1954      * services with type "mediaPlayback" running, or active media session running.
1955      */
getCompositeMediaPlaybackDurations(int uid, long now, long window)1956     long getCompositeMediaPlaybackDurations(int uid, long now, long window) {
1957         final long since = Math.max(0, now - window);
1958         final long mediaPlaybackDuration = Math.max(
1959                 getMediaSessionTotalDurationsSince(uid, since, now),
1960                 getForegroundServiceTotalDurationsSince(uid, since, now,
1961                         ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK));
1962         return mediaPlaybackDuration;
1963     }
1964 
1965     /**
1966      * @return If the given package/uid has an active foreground service running.
1967      */
hasForegroundServices(String packageName, int uid)1968     boolean hasForegroundServices(String packageName, int uid) {
1969         return mInjector.getAppFGSTracker().hasForegroundServices(packageName, uid);
1970     }
1971 
1972     /**
1973      * @return If the given uid has an active foreground service running.
1974      */
hasForegroundServices(int uid)1975     boolean hasForegroundServices(int uid) {
1976         return mInjector.getAppFGSTracker().hasForegroundServices(uid);
1977     }
1978 
1979     /**
1980      * @return If the given package/uid has a foreground service notification or not.
1981      */
hasForegroundServiceNotifications(String packageName, int uid)1982     boolean hasForegroundServiceNotifications(String packageName, int uid) {
1983         return mInjector.getAppFGSTracker().hasForegroundServiceNotifications(packageName, uid);
1984     }
1985 
1986     /**
1987      * @return If the given uid has a foreground service notification or not.
1988      */
hasForegroundServiceNotifications(int uid)1989     boolean hasForegroundServiceNotifications(int uid) {
1990         return mInjector.getAppFGSTracker().hasForegroundServiceNotifications(uid);
1991     }
1992 
1993     /**
1994      * @return The to-be-exempted battery usage of the given UID in the given duration; it could
1995      *         be considered as "exempted" due to various use cases, i.e. media playback.
1996      */
getUidBatteryExemptedUsageSince(int uid, long since, long now, int types)1997     ImmutableBatteryUsage getUidBatteryExemptedUsageSince(int uid, long since, long now,
1998             int types) {
1999         return mInjector.getAppBatteryExemptionTracker()
2000                 .getUidBatteryExemptedUsageSince(uid, since, now, types);
2001     }
2002 
2003     /**
2004      * @return The total battery usage of the given UID since the system boots.
2005      */
getUidBatteryUsage(int uid)2006     @NonNull ImmutableBatteryUsage getUidBatteryUsage(int uid) {
2007         return mInjector.getUidBatteryUsageProvider().getUidBatteryUsage(uid);
2008     }
2009 
2010     interface UidBatteryUsageProvider {
2011         /**
2012          * @return The total battery usage of the given UID since the system boots.
2013          */
getUidBatteryUsage(int uid)2014         @NonNull ImmutableBatteryUsage getUidBatteryUsage(int uid);
2015     }
2016 
dump(PrintWriter pw, String prefix)2017     void dump(PrintWriter pw, String prefix) {
2018         pw.print(prefix);
2019         pw.println("APP BACKGROUND RESTRICTIONS");
2020         prefix = "  " + prefix;
2021         pw.print(prefix);
2022         pw.println("BACKGROUND RESTRICTION LEVEL SETTINGS");
2023         mRestrictionSettings.dump(pw, "  " + prefix);
2024         mConstantsObserver.dump(pw, "  " + prefix);
2025         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
2026             pw.println();
2027             mAppStateTrackers.get(i).dump(pw, prefix);
2028         }
2029     }
2030 
dumpAsProto(ProtoOutputStream proto, int uid)2031     void dumpAsProto(ProtoOutputStream proto, int uid) {
2032         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
2033             mAppStateTrackers.get(i).dumpAsProto(proto, uid);
2034         }
2035     }
2036 
getRestrictionLevelStatsd(@estrictionLevel int level)2037     private int getRestrictionLevelStatsd(@RestrictionLevel int level) {
2038         switch (level) {
2039             case RESTRICTION_LEVEL_UNKNOWN:
2040                 return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN;
2041             case RESTRICTION_LEVEL_UNRESTRICTED:
2042                 return AppBackgroundRestrictionsInfo.LEVEL_UNRESTRICTED;
2043             case RESTRICTION_LEVEL_EXEMPTED:
2044                 return AppBackgroundRestrictionsInfo.LEVEL_EXEMPTED;
2045             case RESTRICTION_LEVEL_ADAPTIVE_BUCKET:
2046                 return AppBackgroundRestrictionsInfo.LEVEL_ADAPTIVE_BUCKET;
2047             case RESTRICTION_LEVEL_RESTRICTED_BUCKET:
2048                 return AppBackgroundRestrictionsInfo.LEVEL_RESTRICTED_BUCKET;
2049             case RESTRICTION_LEVEL_BACKGROUND_RESTRICTED:
2050                 return AppBackgroundRestrictionsInfo.LEVEL_BACKGROUND_RESTRICTED;
2051             case RESTRICTION_LEVEL_FORCE_STOPPED:
2052                 return AppBackgroundRestrictionsInfo.LEVEL_HIBERNATION;
2053             default:
2054                 return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN;
2055         }
2056     }
2057 
getThresholdStatsd(int reason)2058     private int getThresholdStatsd(int reason) {
2059         switch (reason) {
2060             case REASON_MAIN_FORCED_BY_SYSTEM:
2061                 return AppBackgroundRestrictionsInfo.THRESHOLD_RESTRICTED;
2062             case REASON_MAIN_FORCED_BY_USER:
2063                 return AppBackgroundRestrictionsInfo.THRESHOLD_USER;
2064             default:
2065                 return AppBackgroundRestrictionsInfo.THRESHOLD_UNKNOWN;
2066         }
2067     }
2068 
getTrackerTypeStatsd(@rackerType int type)2069     private int getTrackerTypeStatsd(@TrackerType int type) {
2070         switch (type) {
2071             case TRACKER_TYPE_BATTERY:
2072                 return AppBackgroundRestrictionsInfo.BATTERY_TRACKER;
2073             case TRACKER_TYPE_BATTERY_EXEMPTION:
2074                 return AppBackgroundRestrictionsInfo.BATTERY_EXEMPTION_TRACKER;
2075             case TRACKER_TYPE_FGS:
2076                 return AppBackgroundRestrictionsInfo.FGS_TRACKER;
2077             case TRACKER_TYPE_MEDIA_SESSION:
2078                 return AppBackgroundRestrictionsInfo.MEDIA_SESSION_TRACKER;
2079             case TRACKER_TYPE_PERMISSION:
2080                 return AppBackgroundRestrictionsInfo.PERMISSION_TRACKER;
2081             case TRACKER_TYPE_BROADCAST_EVENTS:
2082                 return AppBackgroundRestrictionsInfo.BROADCAST_EVENTS_TRACKER;
2083             case TRACKER_TYPE_BIND_SERVICE_EVENTS:
2084                 return AppBackgroundRestrictionsInfo.BIND_SERVICE_EVENTS_TRACKER;
2085             default:
2086                 return AppBackgroundRestrictionsInfo.UNKNOWN_TRACKER;
2087         }
2088     }
2089 
getExemptionReasonStatsd(int uid, @RestrictionLevel int level)2090     private int getExemptionReasonStatsd(int uid, @RestrictionLevel int level) {
2091         if (level != RESTRICTION_LEVEL_EXEMPTED) {
2092             return AppBackgroundRestrictionsInfo.REASON_DENIED;
2093         }
2094 
2095         @ReasonCode final int reasonCode = getBackgroundRestrictionExemptionReason(uid);
2096         return getExemptionReasonForStatsd(reasonCode);
2097     }
2098 
getOptimizationLevelStatsd(@estrictionLevel int level)2099     private int getOptimizationLevelStatsd(@RestrictionLevel int level) {
2100         switch (level) {
2101             case RESTRICTION_LEVEL_UNKNOWN:
2102                 return AppBackgroundRestrictionsInfo.UNKNOWN;
2103             case RESTRICTION_LEVEL_UNRESTRICTED:
2104                 return AppBackgroundRestrictionsInfo.NOT_OPTIMIZED;
2105             case RESTRICTION_LEVEL_ADAPTIVE_BUCKET:
2106                 return AppBackgroundRestrictionsInfo.OPTIMIZED;
2107             case RESTRICTION_LEVEL_BACKGROUND_RESTRICTED:
2108                 return AppBackgroundRestrictionsInfo.BACKGROUND_RESTRICTED;
2109             default:
2110                 return AppBackgroundRestrictionsInfo.UNKNOWN;
2111         }
2112     }
2113 
2114     @SuppressWarnings("AndroidFrameworkCompatChange")
getTargetSdkStatsd(String packageName)2115     private int getTargetSdkStatsd(String packageName) {
2116         final PackageManager pm = mInjector.getPackageManager();
2117         if (pm == null) {
2118             return AppBackgroundRestrictionsInfo.SDK_UNKNOWN;
2119         }
2120         try {
2121             final PackageInfo pkg = pm.getPackageInfo(packageName, 0 /* flags */);
2122             if (pkg == null || pkg.applicationInfo == null) {
2123                 return AppBackgroundRestrictionsInfo.SDK_UNKNOWN;
2124             }
2125             final int targetSdk = pkg.applicationInfo.targetSdkVersion;
2126             if (targetSdk < Build.VERSION_CODES.S) {
2127                 return AppBackgroundRestrictionsInfo.SDK_PRE_S;
2128             } else if (targetSdk < Build.VERSION_CODES.TIRAMISU) {
2129                 return AppBackgroundRestrictionsInfo.SDK_S;
2130             } else if (targetSdk == Build.VERSION_CODES.TIRAMISU) {
2131                 return AppBackgroundRestrictionsInfo.SDK_T;
2132             } else {
2133                 return AppBackgroundRestrictionsInfo.SDK_UNKNOWN;
2134             }
2135         } catch (PackageManager.NameNotFoundException ignored) {
2136         }
2137         return AppBackgroundRestrictionsInfo.SDK_UNKNOWN;
2138     }
2139 
applyRestrictionLevel(String pkgName, int uid, @RestrictionLevel int level, TrackerInfo trackerInfo, int curBucket, boolean allowUpdateBucket, int reason, int subReason)2140     void applyRestrictionLevel(String pkgName, int uid,
2141             @RestrictionLevel int level, TrackerInfo trackerInfo,
2142             int curBucket, boolean allowUpdateBucket, int reason, int subReason) {
2143         int curLevel;
2144         int prevReason;
2145         final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal();
2146         if (trackerInfo == null) {
2147             trackerInfo = mEmptyTrackerInfo;
2148         }
2149         synchronized (mSettingsLock) {
2150             curLevel = getRestrictionLevel(uid, pkgName);
2151             if (curLevel == level) {
2152                 // Nothing to do.
2153                 return;
2154             }
2155             final int levelOfBucket = standbyBucketToRestrictionLevel(curBucket);
2156             if (levelOfBucket == level) {
2157                 // If the standby bucket yield the same level, use the reason from standby bucket.
2158                 final int bucketReason = appStandbyInternal.getAppStandbyBucketReason(
2159                         pkgName, UserHandle.getUserId(uid), SystemClock.elapsedRealtime());
2160                 if (bucketReason != 0) {
2161                     reason = bucketReason & REASON_MAIN_MASK;
2162                     subReason = bucketReason & REASON_SUB_MASK;
2163                 }
2164             }
2165             if (DEBUG_BG_RESTRICTION_CONTROLLER) {
2166                 Slog.i(TAG, "Updating the restriction level of " + pkgName + "/"
2167                         + UserHandle.formatUid(uid) + " from "
2168                         + ActivityManager.restrictionLevelToName(curLevel) + " to "
2169                         + ActivityManager.restrictionLevelToName(level)
2170                         + " reason=" + reason + ", subReason=" + subReason);
2171             }
2172             prevReason = mRestrictionSettings.getReason(pkgName, uid);
2173             mRestrictionSettings.update(pkgName, uid, level, reason, subReason);
2174         }
2175 
2176         if (!android.app.Flags.appRestrictionsApi()
2177                 && (!allowUpdateBucket || curBucket == STANDBY_BUCKET_EXEMPTED)) {
2178             return;
2179         }
2180 
2181         boolean doItNow = true;
2182         if (level >= RESTRICTION_LEVEL_RESTRICTED_BUCKET
2183                 && curLevel < RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
2184             // Moving the app standby bucket to restricted in the meanwhile.
2185             if (DEBUG_BG_RESTRICTION_CONTROLLER
2186                     && level == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
2187                 Slog.i(TAG, pkgName + "/" + UserHandle.formatUid(uid)
2188                         + " is bg-restricted, moving to restricted standby bucket");
2189             }
2190             if (curBucket != STANDBY_BUCKET_RESTRICTED
2191                     && (mConstantsObserver.mBgAutoRestrictedBucket
2192                     || level == RESTRICTION_LEVEL_RESTRICTED_BUCKET)) {
2193                 // restrict the app if it hasn't done so.
2194                 synchronized (mSettingsLock) {
2195                     final int index = mActiveUids.indexOfKey(uid, pkgName);
2196                     if (index >= 0) {
2197                         // It's currently active, enqueue it.
2198                         final int localReason = reason;
2199                         final int localSubReason = subReason;
2200                         final TrackerInfo localTrackerInfo = trackerInfo;
2201                         mActiveUids.add(uid, pkgName, () -> {
2202                             appStandbyInternal.restrictApp(pkgName, UserHandle.getUserId(uid),
2203                                     localReason, localSubReason);
2204                             logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level,
2205                                     localTrackerInfo, localReason);
2206                         });
2207                         doItNow = false;
2208                     }
2209                 }
2210                 if (doItNow) {
2211                     appStandbyInternal.restrictApp(pkgName, UserHandle.getUserId(uid),
2212                             reason, subReason);
2213                     if (!android.app.Flags.appRestrictionsApi()) {
2214                         logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level, trackerInfo,
2215                                 reason);
2216                     }
2217                 }
2218             }
2219         } else if (curLevel >= RESTRICTION_LEVEL_RESTRICTED_BUCKET
2220                 && level < RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
2221             // Moved out of the background-restricted state.
2222             synchronized (mSettingsLock) {
2223                 final int index = mActiveUids.indexOfKey(uid, pkgName);
2224                 if (index >= 0) {
2225                     mActiveUids.add(uid, pkgName, null);
2226                 }
2227             }
2228             appStandbyInternal.maybeUnrestrictApp(pkgName, UserHandle.getUserId(uid),
2229                     prevReason & REASON_MAIN_MASK, prevReason & REASON_SUB_MASK,
2230                     reason, subReason);
2231             if (!android.app.Flags.appRestrictionsApi()) {
2232                 logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level, trackerInfo,
2233                         reason);
2234             }
2235         }
2236 
2237         if (doItNow && android.app.Flags.appRestrictionsApi()
2238                 && curLevel != RESTRICTION_LEVEL_UNKNOWN) {
2239             logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level, trackerInfo,
2240                     reason);
2241         }
2242     }
2243 
logAppBackgroundRestrictionInfo(String pkgName, int uid, @RestrictionLevel int prevLevel, @RestrictionLevel int level, @NonNull TrackerInfo trackerInfo, int reason)2244     private void logAppBackgroundRestrictionInfo(String pkgName, int uid,
2245             @RestrictionLevel int prevLevel, @RestrictionLevel int level,
2246             @NonNull TrackerInfo trackerInfo, int reason) {
2247         FrameworkStatsLog.write(FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO, uid,
2248                 getRestrictionLevelStatsd(level),
2249                 getThresholdStatsd(reason),
2250                 getTrackerTypeStatsd(trackerInfo.mType),
2251                 trackerInfo.mType == TRACKER_TYPE_FGS ? trackerInfo.mInfo : null,
2252                 trackerInfo.mType == TRACKER_TYPE_BATTERY ? trackerInfo.mInfo : null,
2253                 trackerInfo.mType == TRACKER_TYPE_BROADCAST_EVENTS ? trackerInfo.mInfo : null,
2254                 trackerInfo.mType == TRACKER_TYPE_BIND_SERVICE_EVENTS ? trackerInfo.mInfo : null,
2255                 getExemptionReasonStatsd(uid, level),
2256                 getOptimizationLevelStatsd(level),
2257                 getTargetSdkStatsd(pkgName),
2258                 ActivityManager.isLowRamDeviceStatic(),
2259                 getRestrictionLevelStatsd(prevLevel));
2260     }
2261 
handleBackgroundRestrictionChanged(int uid, String pkgName, boolean restricted)2262     private void handleBackgroundRestrictionChanged(int uid, String pkgName, boolean restricted) {
2263         // Firstly, notify the trackers.
2264         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
2265             mAppStateTrackers.get(i)
2266                     .onBackgroundRestrictionChanged(uid, pkgName, restricted);
2267         }
2268 
2269         final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal();
2270         final int userId = UserHandle.getUserId(uid);
2271         final long now = SystemClock.elapsedRealtime();
2272         final int curBucket = appStandbyInternal.getAppStandbyBucket(pkgName, userId, now, false);
2273         if (restricted) {
2274             // The app could fall into the background restricted with user consent only,
2275             // so set the reason to it.
2276             applyRestrictionLevel(pkgName, uid, RESTRICTION_LEVEL_BACKGROUND_RESTRICTED,
2277                     mEmptyTrackerInfo, curBucket, true, REASON_MAIN_FORCED_BY_USER,
2278                     REASON_SUB_FORCED_USER_FLAG_INTERACTION);
2279             mBgHandler.obtainMessage(BgHandler.MSG_CANCEL_REQUEST_BG_RESTRICTED, uid, 0, pkgName)
2280                     .sendToTarget();
2281         } else {
2282             // Moved out of the background-restricted state, we'd need to check if it should
2283             // stay in the restricted standby bucket.
2284             final @RestrictionLevel int lastLevel =
2285                     mRestrictionSettings.getLastRestrictionLevel(uid, pkgName);
2286             final int tentativeBucket = curBucket == STANDBY_BUCKET_EXEMPTED
2287                     ? STANDBY_BUCKET_EXEMPTED
2288                     : (lastLevel == RESTRICTION_LEVEL_RESTRICTED_BUCKET
2289                             ? STANDBY_BUCKET_RESTRICTED : STANDBY_BUCKET_RARE);
2290             final Pair<Integer, TrackerInfo> levelTypePair = calcAppRestrictionLevel(
2291                     UserHandle.getUserId(uid), uid, pkgName, tentativeBucket, false, true);
2292 
2293             applyRestrictionLevel(pkgName, uid, levelTypePair.first, levelTypePair.second,
2294                     curBucket, true, REASON_MAIN_USAGE, REASON_SUB_USAGE_USER_INTERACTION);
2295         }
2296     }
2297 
dispatchAppRestrictionLevelChanges(int uid, String pkgName, @RestrictionLevel int newLevel)2298     private void dispatchAppRestrictionLevelChanges(int uid, String pkgName,
2299             @RestrictionLevel int newLevel) {
2300         mRestrictionListeners.forEach(
2301                 l -> l.onRestrictionLevelChanged(uid, pkgName, newLevel));
2302     }
2303 
dispatchAutoRestrictedBucketFeatureFlagChanged(boolean newValue)2304     private void dispatchAutoRestrictedBucketFeatureFlagChanged(boolean newValue) {
2305         final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal();
2306         final ArrayList<Runnable> pendingTasks = new ArrayList<>();
2307         synchronized (mSettingsLock) {
2308             mRestrictionSettings.forEachUidLocked(uid -> {
2309                 mRestrictionSettings.forEachPackageInUidLocked(uid, (pkgName, level, reason) -> {
2310                     if (level == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
2311                         pendingTasks.add(newValue
2312                                 ? () -> appStandbyInternal.restrictApp(pkgName,
2313                                 UserHandle.getUserId(uid), reason & REASON_MAIN_MASK,
2314                                 reason & REASON_SUB_MASK)
2315                                 : () -> appStandbyInternal.maybeUnrestrictApp(pkgName,
2316                                 UserHandle.getUserId(uid), reason & REASON_MAIN_MASK,
2317                                 reason & REASON_SUB_MASK, REASON_MAIN_USAGE,
2318                                 REASON_SUB_USAGE_SYSTEM_UPDATE));
2319                     }
2320                 });
2321             });
2322         }
2323         for (int i = 0; i < pendingTasks.size(); i++) {
2324             pendingTasks.get(i).run();
2325         }
2326         mRestrictionListeners.forEach(
2327                 l -> l.onAutoRestrictedBucketFeatureFlagChanged(newValue));
2328     }
2329 
handleAppStandbyBucketChanged(int bucket, String packageName, @UserIdInt int userId)2330     private void handleAppStandbyBucketChanged(int bucket, String packageName,
2331             @UserIdInt int userId) {
2332         // Ignore spurious changes to standby bucket during early boot
2333         if (android.app.Flags.appRestrictionsApi() && !mLockedBootCompleted) return;
2334 
2335         final int uid = mInjector.getPackageManagerInternal().getPackageUid(
2336                 packageName, STOCK_PM_FLAGS, userId);
2337         final Pair<Integer, TrackerInfo> levelTypePair = calcAppRestrictionLevel(
2338                 userId, uid, packageName, bucket, false, false);
2339         applyRestrictionLevel(packageName, uid, levelTypePair.first, levelTypePair.second,
2340                 bucket, false, REASON_MAIN_DEFAULT, REASON_SUB_DEFAULT_UNDEFINED);
2341     }
2342 
handleRequestBgRestricted(String packageName, int uid)2343     void handleRequestBgRestricted(String packageName, int uid) {
2344         if (DEBUG_BG_RESTRICTION_CONTROLLER) {
2345             Slog.i(TAG, "Requesting background restricted " + packageName + " "
2346                     + UserHandle.formatUid(uid));
2347         }
2348         mNotificationHelper.postRequestBgRestrictedIfNecessary(packageName, uid);
2349     }
2350 
handleCancelRequestBgRestricted(String packageName, int uid)2351     void handleCancelRequestBgRestricted(String packageName, int uid) {
2352         if (DEBUG_BG_RESTRICTION_CONTROLLER) {
2353             Slog.i(TAG, "Cancelling requesting background restricted " + packageName + " "
2354                     + UserHandle.formatUid(uid));
2355         }
2356         mNotificationHelper.cancelRequestBgRestrictedIfNecessary(packageName, uid);
2357     }
2358 
handleUidProcStateChanged(int uid, int procState)2359     void handleUidProcStateChanged(int uid, int procState) {
2360         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
2361             mAppStateTrackers.get(i).onUidProcStateChanged(uid, procState);
2362         }
2363     }
2364 
handleUidGone(int uid)2365     void handleUidGone(int uid) {
2366         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
2367             mAppStateTrackers.get(i).onUidGone(uid);
2368         }
2369     }
2370 
2371     /**
2372      * Log a change in restriction state with a reason and threshold.
2373      * @param packageName
2374      * @param uid
2375      * @param restrictionType
2376      * @param enabled
2377      * @param reason
2378      * @param subReason Eg: settings, cli, long_wakelock, crash, binder_spam, cpu, threads
2379      *                  Length should not exceed RESTRICTON_SUBREASON_MAX_LENGTH
2380      * @param threshold
2381      */
noteAppRestrictionEnabled(String packageName, int uid, @RestrictionLevel int restrictionType, boolean enabled, @RestrictionReason int reason, String subReason, @RestrictionSource int source, long threshold)2382     public void noteAppRestrictionEnabled(String packageName, int uid,
2383             @RestrictionLevel int restrictionType, boolean enabled,
2384             @RestrictionReason int reason, String subReason, @RestrictionSource int source,
2385             long threshold) {
2386         if (DEBUG_BG_RESTRICTION_CONTROLLER) {
2387             Slog.i(TAG, (enabled ? "restricted " : "unrestricted ") + packageName + " to "
2388                     + restrictionType + " reason=" + reason + ", subReason=" + subReason
2389                     + ", threshold=" + threshold);
2390         }
2391 
2392         // Limit the length of the free-form subReason string
2393         if (subReason != null && subReason.length() > RESTRICTION_SUBREASON_MAX_LENGTH) {
2394             Slog.e(TAG, "subReason is too long, truncating " + subReason);
2395             subReason = subReason.substring(0, RESTRICTION_SUBREASON_MAX_LENGTH);
2396         }
2397 
2398         // Log the restriction reason
2399         FrameworkStatsLog.write(FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED, uid,
2400                 getRestrictionTypeStatsd(restrictionType),
2401                 enabled,
2402                 getRestrictionChangeReasonStatsd(reason, subReason),
2403                 subReason,
2404                 threshold,
2405                 source);
2406     }
2407 
getRestrictionTypeStatsd(@estrictionLevel int level)2408     private int getRestrictionTypeStatsd(@RestrictionLevel int level) {
2409         return switch (level) {
2410             case RESTRICTION_LEVEL_UNKNOWN ->
2411                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__RESTRICTION_TYPE__TYPE_UNKNOWN;
2412             case RESTRICTION_LEVEL_UNRESTRICTED ->
2413                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__RESTRICTION_TYPE__TYPE_UNRESTRICTED;
2414             case RESTRICTION_LEVEL_EXEMPTED ->
2415                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__RESTRICTION_TYPE__TYPE_EXEMPTED;
2416             case RESTRICTION_LEVEL_ADAPTIVE_BUCKET ->
2417                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__RESTRICTION_TYPE__TYPE_ADAPTIVE;
2418             case RESTRICTION_LEVEL_RESTRICTED_BUCKET ->
2419                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__RESTRICTION_TYPE__TYPE_RESTRICTED_BUCKET;
2420             case RESTRICTION_LEVEL_BACKGROUND_RESTRICTED ->
2421                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__RESTRICTION_TYPE__TYPE_BACKGROUND_RESTRICTED;
2422             case RESTRICTION_LEVEL_FORCE_STOPPED ->
2423                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__RESTRICTION_TYPE__TYPE_FORCE_STOPPED;
2424             case RESTRICTION_LEVEL_USER_LAUNCH_ONLY ->
2425                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__RESTRICTION_TYPE__TYPE_USER_LAUNCH_ONLY;
2426             default ->
2427                 FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__RESTRICTION_TYPE__TYPE_CUSTOM;
2428         };
2429     }
2430 
getRestrictionChangeReasonStatsd(int reason, String subReason)2431     private int getRestrictionChangeReasonStatsd(int reason, String subReason) {
2432         return switch (reason) {
2433             case RESTRICTION_REASON_DEFAULT ->
2434                 FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__MAIN_REASON__REASON_DEFAULT;
2435             case RESTRICTION_REASON_DORMANT ->
2436                 FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__MAIN_REASON__REASON_DORMANT;
2437             case RESTRICTION_REASON_USAGE ->
2438                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__MAIN_REASON__REASON_USAGE;
2439             case RESTRICTION_REASON_USER ->
2440                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__MAIN_REASON__REASON_USER;
2441             case RESTRICTION_REASON_SYSTEM_HEALTH ->
2442                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__MAIN_REASON__REASON_SYSTEM_HEALTH;
2443             case RESTRICTION_REASON_POLICY ->
2444                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__MAIN_REASON__REASON_POLICY;
2445             default ->
2446                     FrameworkStatsLog.APP_RESTRICTION_STATE_CHANGED__MAIN_REASON__REASON_OTHER;
2447         };
2448     }
2449 
2450     static class NotificationHelper {
2451         static final String PACKAGE_SCHEME = "package";
2452         static final String GROUP_KEY = "com.android.app.abusive_bg_apps";
2453 
2454         static final int SUMMARY_NOTIFICATION_ID = SystemMessage.NOTE_ABUSIVE_BG_APPS_BASE;
2455 
2456         static final int NOTIFICATION_TYPE_ABUSIVE_CURRENT_DRAIN = 0;
2457         static final int NOTIFICATION_TYPE_LONG_RUNNING_FGS = 1;
2458         static final int NOTIFICATION_TYPE_LAST = 2;
2459 
2460         static final String ATTR_LAST_BATTERY_NOTIFICATION_TIME = "last_batt_noti_ts";
2461         static final String ATTR_LAST_LONG_FGS_NOTIFICATION_TIME = "last_long_fgs_noti_ts";
2462 
2463         @IntDef(prefix = { "NOTIFICATION_TYPE_"}, value = {
2464             NOTIFICATION_TYPE_ABUSIVE_CURRENT_DRAIN,
2465             NOTIFICATION_TYPE_LONG_RUNNING_FGS,
2466         })
2467         @Retention(RetentionPolicy.SOURCE)
2468         static @interface NotificationType{}
2469 
2470         static final String[] NOTIFICATION_TYPE_STRINGS = {
2471             "Abusive current drain",
2472             "Long-running FGS",
2473         };
2474 
2475         static final String[] NOTIFICATION_TIME_ATTRS = {
2476             ATTR_LAST_BATTERY_NOTIFICATION_TIME,
2477             ATTR_LAST_LONG_FGS_NOTIFICATION_TIME,
2478         };
2479 
2480         static @NotificationType int notificationTimeAttrToType(@NonNull String attr) {
2481             switch (attr) {
2482                 case ATTR_LAST_BATTERY_NOTIFICATION_TIME:
2483                     return NOTIFICATION_TYPE_ABUSIVE_CURRENT_DRAIN;
2484                 case ATTR_LAST_LONG_FGS_NOTIFICATION_TIME:
2485                     return NOTIFICATION_TYPE_LONG_RUNNING_FGS;
2486             }
2487             throw new IllegalArgumentException();
2488         }
2489 
2490         static @NonNull String notificationTypeToTimeAttr(@NotificationType int type) {
2491             return NOTIFICATION_TIME_ATTRS[type];
2492         }
2493 
2494         static final String ACTION_FGS_MANAGER_TRAMPOLINE =
2495                 "com.android.server.am.ACTION_FGS_MANAGER_TRAMPOLINE";
2496 
2497         static String notificationTypeToString(@NotificationType int notificationType) {
2498             return NOTIFICATION_TYPE_STRINGS[notificationType];
2499         }
2500 
2501         private final AppRestrictionController mBgController;
2502         private final NotificationManager mNotificationManager;
2503         private final Injector mInjector;
2504         private final Object mLock;
2505         private final Object mSettingsLock;
2506         private final Context mContext;
2507 
2508         private final BroadcastReceiver mActionButtonReceiver = new BroadcastReceiver() {
2509             @Override
2510             public void onReceive(Context context, Intent intent) {
2511                 final String action = intent.getAction();
2512                 switch (intent.getAction()) {
2513                     case ACTION_FGS_MANAGER_TRAMPOLINE:
2514                         final String packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
2515                         final int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
2516                         cancelRequestBgRestrictedIfNecessary(packageName, uid);
2517                         final Intent newIntent = new Intent(ACTION_SHOW_FOREGROUND_SERVICE_MANAGER);
2518                         newIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
2519                         // Task manager runs in SystemUI, which is SYSTEM user only.
2520                         mContext.sendBroadcastAsUser(newIntent, UserHandle.SYSTEM);
2521                         break;
2522                 }
2523             }
2524         };
2525 
2526         @GuardedBy("mSettingsLock")
2527         private int mNotificationIDStepper = SUMMARY_NOTIFICATION_ID + 1;
2528 
2529         NotificationHelper(AppRestrictionController controller) {
2530             mBgController = controller;
2531             mInjector = controller.mInjector;
2532             mNotificationManager = mInjector.getNotificationManager();
2533             mLock = controller.mLock;
2534             mSettingsLock = controller.mSettingsLock;
2535             mContext = mInjector.getContext();
2536         }
2537 
2538         void onSystemReady() {
2539             mContext.registerReceiverForAllUsers(mActionButtonReceiver,
2540                     new IntentFilter(ACTION_FGS_MANAGER_TRAMPOLINE),
2541                     MANAGE_ACTIVITY_TASKS, mBgController.mBgHandler, Context.RECEIVER_NOT_EXPORTED);
2542         }
2543 
2544         void postRequestBgRestrictedIfNecessary(String packageName, int uid) {
2545             if (!mBgController.mConstantsObserver.mBgPromptAbusiveAppsToBgRestricted) {
2546                 if (DEBUG_BG_RESTRICTION_CONTROLLER) {
2547                     Slog.i(TAG, "Not requesting bg-restriction due to config");
2548                 }
2549                 return;
2550             }
2551 
2552             final Intent intent = new Intent(Settings.ACTION_VIEW_ADVANCED_POWER_USAGE_DETAIL);
2553             intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
2554             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
2555 
2556             final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0,
2557                     intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE, null,
2558                     UserHandle.of(UserHandle.getUserId(uid)));
2559             Notification.Action[] actions = null;
2560             final boolean hasForegroundServices =
2561                     mBgController.hasForegroundServices(packageName, uid);
2562             final boolean hasForegroundServiceNotifications =
2563                     mBgController.hasForegroundServiceNotifications(packageName, uid);
2564             if (!mBgController.mConstantsObserver.mBgPromptFgsWithNotiToBgRestricted) {
2565                 // We're not going to prompt the user if the FGS is active and its notification
2566                 // is still showing (not dismissed/silenced/denied).
2567                 if (hasForegroundServices && hasForegroundServiceNotifications) {
2568                     if (DEBUG_BG_RESTRICTION_CONTROLLER) {
2569                         Slog.i(TAG, "Not requesting bg-restriction due to FGS with notification");
2570                     }
2571                     return;
2572                 }
2573             }
2574             if (ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER
2575                     && ENABLE_SHOW_FGS_MANAGER_ACTION_ON_BG_RESTRICTION
2576                     && hasForegroundServices) {
2577                 final Intent trampoline = new Intent(ACTION_FGS_MANAGER_TRAMPOLINE);
2578                 trampoline.setPackage("android");
2579                 trampoline.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
2580                 trampoline.putExtra(Intent.EXTRA_UID, uid);
2581                 final PendingIntent fgsMgrTrampoline = PendingIntent.getBroadcastAsUser(
2582                         mContext, 0, trampoline,
2583                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE,
2584                         UserHandle.CURRENT);
2585                 actions = new Notification.Action[] {
2586                     new Notification.Action.Builder(null,
2587                             mContext.getString(
2588                             com.android.internal.R.string.notification_action_check_bg_apps),
2589                             fgsMgrTrampoline)
2590                             .build()
2591                 };
2592             }
2593             postNotificationIfNecessary(NOTIFICATION_TYPE_ABUSIVE_CURRENT_DRAIN,
2594                     com.android.internal.R.string.notification_title_abusive_bg_apps,
2595                     com.android.internal.R.string.notification_content_abusive_bg_apps,
2596                     pendingIntent, packageName, uid, actions);
2597         }
2598 
2599         void postLongRunningFgsIfNecessary(String packageName, int uid) {
2600             // Log the event in statsd.
2601             FrameworkStatsLog.write(FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO,
2602                     uid,
2603                     mBgController.getRestrictionLevel(uid),
2604                     AppBackgroundRestrictionsInfo.THRESHOLD_UNKNOWN,
2605                     AppBackgroundRestrictionsInfo.FGS_TRACKER,
2606                     mInjector.getAppFGSTracker().getTrackerInfoForStatsd(uid),
2607                     null, // BatteryTrackerInfo
2608                     null, // BroadcastEventsTrackerInfo
2609                     null, // BindServiceEventsTrackerInfo
2610                     getExemptionReasonForStatsd(
2611                             mBgController.getBackgroundRestrictionExemptionReason(uid)),
2612                     AppBackgroundRestrictionsInfo.UNKNOWN, // OptimizationLevel
2613                     AppBackgroundRestrictionsInfo.SDK_UNKNOWN, // TargetSdk
2614                     ActivityManager.isLowRamDeviceStatic(),
2615                     mBgController.getRestrictionLevel(uid));
2616             PendingIntent pendingIntent;
2617             if (!mBgController.mConstantsObserver.mBgPromptFgsOnLongRunning) {
2618                 if (DEBUG_BG_RESTRICTION_CONTROLLER) {
2619                     Slog.i(TAG, "Long-running FGS prompt is disabled.");
2620                 }
2621                 return;
2622             }
2623             if (!mBgController.mConstantsObserver.mBgPromptFgsWithNotiOnLongRunning
2624                     && mBgController.hasForegroundServiceNotifications(packageName, uid)) {
2625                 if (DEBUG_BG_RESTRICTION_CONTROLLER) {
2626                     Slog.i(TAG, "Not prompt long-running due to FGS with notification");
2627                 }
2628                 return;
2629             }
2630             if (ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER) {
2631                 final Intent intent = new Intent(ACTION_SHOW_FOREGROUND_SERVICE_MANAGER);
2632                 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
2633                 // Task manager runs in SystemUI, which is SYSTEM user only.
2634                 pendingIntent = PendingIntent.getBroadcastAsUser(mContext, 0,
2635                         intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE,
2636                         UserHandle.SYSTEM);
2637             } else {
2638                 final Intent intent = new Intent(Settings.ACTION_VIEW_ADVANCED_POWER_USAGE_DETAIL);
2639                 intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
2640                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
2641                 pendingIntent = PendingIntent.getActivityAsUser(mContext, 0,
2642                         intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE,
2643                         null, UserHandle.of(UserHandle.getUserId(uid)));
2644             }
2645 
2646             postNotificationIfNecessary(NOTIFICATION_TYPE_LONG_RUNNING_FGS,
2647                     com.android.internal.R.string.notification_title_long_running_fgs,
2648                     com.android.internal.R.string.notification_content_long_running_fgs,
2649                     pendingIntent, packageName, uid, null);
2650         }
2651 
2652         long getNotificationMinInterval(@NotificationType int notificationType) {
2653             switch (notificationType) {
2654                 case NOTIFICATION_TYPE_ABUSIVE_CURRENT_DRAIN:
2655                     return mBgController.mConstantsObserver.mBgAbusiveNotificationMinIntervalMs;
2656                 case NOTIFICATION_TYPE_LONG_RUNNING_FGS:
2657                     return mBgController.mConstantsObserver.mBgLongFgsNotificationMinIntervalMs;
2658                 default:
2659                     return 0L;
2660             }
2661         }
2662 
2663         int getNotificationIdIfNecessary(@NotificationType int notificationType,
2664                 String packageName, int uid) {
2665             synchronized (mSettingsLock) {
2666                 final RestrictionSettings.PkgSettings settings = mBgController.mRestrictionSettings
2667                         .getRestrictionSettingsLocked(uid, packageName);
2668                 if (settings == null) {
2669                     return 0;
2670                 }
2671 
2672                 final long now = mInjector.currentTimeMillis();
2673                 final long lastNotificationShownTime =
2674                         settings.getLastNotificationTime(notificationType);
2675                 if (lastNotificationShownTime != 0 && (lastNotificationShownTime
2676                         + getNotificationMinInterval(notificationType) > now)) {
2677                     if (DEBUG_BG_RESTRICTION_CONTROLLER) {
2678                         Slog.i(TAG, "Not showing notification as last notification was shown "
2679                                 + TimeUtils.formatDuration(now - lastNotificationShownTime)
2680                                 + " ago");
2681                     }
2682                     return 0;
2683                 }
2684                 settings.setLastNotificationTime(notificationType, now);
2685                 int notificationId = settings.getNotificationId(notificationType);
2686                 if (notificationId <= 0) {
2687                     notificationId = mNotificationIDStepper++;
2688                     settings.setNotificationId(notificationType, notificationId);
2689                 }
2690                 if (DEBUG_BG_RESTRICTION_CONTROLLER) {
2691                     Slog.i(TAG, "Showing notification for " + packageName
2692                             + "/" + UserHandle.formatUid(uid)
2693                             + ", id=" + notificationId
2694                             + ", now=" + now
2695                             + ", lastShown=" + lastNotificationShownTime);
2696                 }
2697                 return notificationId;
2698             }
2699         }
2700 
2701         void postNotificationIfNecessary(@NotificationType int notificationType, int titleRes,
2702                 int messageRes, PendingIntent pendingIntent, String packageName, int uid,
2703                 @Nullable Notification.Action[] actions) {
2704             int notificationId = getNotificationIdIfNecessary(notificationType, packageName, uid);
2705             if (notificationId <= 0) {
2706                 return;
2707             }
2708 
2709             final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
2710             final PackageManager pm = mInjector.getPackageManager();
2711             final ApplicationInfo ai = pmi.getApplicationInfo(packageName, STOCK_PM_FLAGS,
2712                     SYSTEM_UID, UserHandle.getUserId(uid));
2713             final String title = mContext.getString(titleRes);
2714             final String message = mContext.getString(messageRes,
2715                     ai != null ? ai.loadLabel(pm) : packageName);
2716             final Icon icon = ai != null ? Icon.createWithResource(packageName, ai.icon) : null;
2717 
2718             postNotification(notificationId, packageName, uid, title, message, icon, pendingIntent,
2719                     actions);
2720         }
2721 
2722         void postNotification(int notificationId, String packageName, int uid, String title,
2723                 String message, Icon icon, PendingIntent pendingIntent,
2724                 @Nullable Notification.Action[] actions) {
2725             final UserHandle targetUser = UserHandle.of(UserHandle.getUserId(uid));
2726             postSummaryNotification(targetUser);
2727 
2728             final Notification.Builder notificationBuilder = new Notification.Builder(mContext,
2729                     ABUSIVE_BACKGROUND_APPS)
2730                     .setAutoCancel(true)
2731                     .setGroup(GROUP_KEY)
2732                     .setWhen(mInjector.currentTimeMillis())
2733                     .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
2734                     .setColor(mContext.getColor(
2735                             com.android.internal.R.color.system_notification_accent_color))
2736                     .setContentTitle(title)
2737                     .setContentText(message)
2738                     .setContentIntent(pendingIntent);
2739             if (icon != null) {
2740                 notificationBuilder.setLargeIcon(icon);
2741             }
2742             if (actions != null) {
2743                 for (Notification.Action action : actions) {
2744                     notificationBuilder.addAction(action);
2745                 }
2746             }
2747 
2748             final Notification notification = notificationBuilder.build();
2749             // Remember the package name for testing.
2750             notification.extras.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
2751 
2752             mNotificationManager.notifyAsUser(null, notificationId, notification, targetUser);
2753         }
2754 
2755         private void postSummaryNotification(@NonNull UserHandle targetUser) {
2756             final Notification summary = new Notification.Builder(mContext,
2757                     ABUSIVE_BACKGROUND_APPS)
2758                     .setGroup(GROUP_KEY)
2759                     .setGroupSummary(true)
2760                     .setStyle(new Notification.BigTextStyle())
2761                     .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
2762                     .setColor(mContext.getColor(
2763                             com.android.internal.R.color.system_notification_accent_color))
2764                     .build();
2765             mNotificationManager.notifyAsUser(null, SUMMARY_NOTIFICATION_ID, summary, targetUser);
2766         }
2767 
2768         void cancelRequestBgRestrictedIfNecessary(String packageName, int uid) {
2769             synchronized (mSettingsLock) {
2770                 final RestrictionSettings.PkgSettings settings = mBgController.mRestrictionSettings
2771                         .getRestrictionSettingsLocked(uid, packageName);
2772                 if (settings != null) {
2773                     final int notificationId =
2774                             settings.getNotificationId(NOTIFICATION_TYPE_ABUSIVE_CURRENT_DRAIN);
2775                     if (notificationId > 0) {
2776                         mNotificationManager.cancel(notificationId);
2777                     }
2778                 }
2779             }
2780         }
2781 
2782         void cancelLongRunningFGSNotificationIfNecessary(String packageName, int uid) {
2783             synchronized (mSettingsLock) {
2784                 final RestrictionSettings.PkgSettings settings = mBgController.mRestrictionSettings
2785                         .getRestrictionSettingsLocked(uid, packageName);
2786                 if (settings != null) {
2787                     final int notificationId =
2788                             settings.getNotificationId(NOTIFICATION_TYPE_LONG_RUNNING_FGS);
2789                     if (notificationId > 0) {
2790                         mNotificationManager.cancel(notificationId);
2791                     }
2792                 }
2793             }
2794         }
2795     }
2796 
2797     void handleUidInactive(int uid, boolean disabled) {
2798         final ArrayList<Runnable> pendingTasks = mTmpRunnables;
2799         synchronized (mSettingsLock) {
2800             final int index = mActiveUids.indexOfKey(uid);
2801             if (index < 0) {
2802                 return;
2803             }
2804             final int numPackages = mActiveUids.numElementsForKeyAt(index);
2805             for (int i = 0; i < numPackages; i++) {
2806                 final Runnable pendingTask = mActiveUids.valueAt(index, i);
2807                 if (pendingTask != null) {
2808                     pendingTasks.add(pendingTask);
2809                 }
2810             }
2811             mActiveUids.deleteAt(index);
2812         }
2813         for (int i = 0, size = pendingTasks.size(); i < size; i++) {
2814             pendingTasks.get(i).run();
2815         }
2816         pendingTasks.clear();
2817     }
2818 
2819     void handleUidActive(int uid) {
2820         synchronized (mSettingsLock) {
2821             final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal();
2822             final int userId = UserHandle.getUserId(uid);
2823             mRestrictionSettings.forEachPackageInUidLocked(uid, (pkgName, level, reason) -> {
2824                 if (mConstantsObserver.mBgAutoRestrictedBucket
2825                         && level == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
2826                     mActiveUids.add(uid, pkgName, () -> appStandbyInternal.restrictApp(pkgName,
2827                             userId, reason & REASON_MAIN_MASK, reason & REASON_SUB_MASK));
2828                 } else {
2829                     mActiveUids.add(uid, pkgName, null);
2830                 }
2831             });
2832         }
2833     }
2834 
2835     boolean isOnDeviceIdleAllowlist(int uid) {
2836         final int appId = UserHandle.getAppId(uid);
2837 
2838         return Arrays.binarySearch(mDeviceIdleAllowlist, appId) >= 0
2839                 || Arrays.binarySearch(mDeviceIdleExceptIdleAllowlist, appId) >= 0;
2840     }
2841 
2842     boolean isOnSystemDeviceIdleAllowlist(int uid) {
2843         final int appId = UserHandle.getAppId(uid);
2844 
2845         return mSystemDeviceIdleAllowlist.contains(appId)
2846                 || mSystemDeviceIdleExceptIdleAllowlist.contains(appId);
2847     }
2848 
2849     void setDeviceIdleAllowlist(int[] allAppids, int[] exceptIdleAppids) {
2850         mDeviceIdleAllowlist = allAppids;
2851         mDeviceIdleExceptIdleAllowlist = exceptIdleAppids;
2852     }
2853 
2854     /**
2855      * @return The reason code of whether or not the given UID should be exempted from background
2856      * restrictions here.
2857      *
2858      * <p>
2859      * Note: Call it with caution as it'll try to acquire locks in other services.
2860      * </p>
2861      */
2862     @ReasonCode
2863     int getBackgroundRestrictionExemptionReason(int uid) {
2864         @ReasonCode int reason = getPotentialSystemExemptionReason(uid);
2865         if (reason != REASON_DENIED) {
2866             return reason;
2867         }
2868         final String[] packages = mInjector.getPackageManager().getPackagesForUid(uid);
2869         if (packages != null) {
2870             // Check each packages to see if any of them is in the "fixed" exemption cases.
2871             for (String pkg : packages) {
2872                 reason = getPotentialSystemExemptionReason(uid, pkg);
2873                 if (reason != REASON_DENIED) {
2874                     return reason;
2875                 }
2876             }
2877             // Loop the packages again, and check the user-configurable exemptions.
2878             for (String pkg : packages) {
2879                 reason = getPotentialUserAllowedExemptionReason(uid, pkg);
2880                 if (reason != REASON_DENIED) {
2881                     return reason;
2882                 }
2883             }
2884         }
2885         return REASON_DENIED;
2886     }
2887 
2888     /**
2889      * @param uid The uid to check.
2890      * @return The potential exemption reason of the given uid. The caller must decide
2891      * whether or not it should be exempted.
2892      */
2893     @ReasonCode
2894     int getPotentialSystemExemptionReason(int uid) {
2895         if (UserHandle.isCore(uid)) {
2896             return REASON_SYSTEM_UID;
2897         }
2898         if (isOnSystemDeviceIdleAllowlist(uid)) {
2899             return REASON_SYSTEM_ALLOW_LISTED;
2900         }
2901         if (UserManager.isDeviceInDemoMode(mContext)) {
2902             return REASON_DEVICE_DEMO_MODE;
2903         }
2904         final int userId = UserHandle.getUserId(uid);
2905         if (mInjector.getUserManagerInternal()
2906                 .hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL, userId)) {
2907             return REASON_DISALLOW_APPS_CONTROL;
2908         }
2909         final ActivityManagerInternal am = mInjector.getActivityManagerInternal();
2910         if (am.isDeviceOwner(uid)) {
2911             return REASON_DEVICE_OWNER;
2912         }
2913         if (am.isProfileOwner(uid)) {
2914             return REASON_PROFILE_OWNER;
2915         }
2916         final int uidProcState = am.getUidProcessState(uid);
2917         if (uidProcState <= PROCESS_STATE_PERSISTENT) {
2918             return REASON_PROC_STATE_PERSISTENT;
2919         } else if (uidProcState <= PROCESS_STATE_PERSISTENT_UI) {
2920             return REASON_PROC_STATE_PERSISTENT_UI;
2921         }
2922         return REASON_DENIED;
2923     }
2924 
2925     /**
2926      * @param uid The uid to check.
2927      * @param pkgName The package name to check.
2928      * @return The potential system-fixed exemption reason of the given uid/package. The caller
2929      * must decide whether or not it should be exempted.
2930      */
2931     @ReasonCode
2932     int getPotentialSystemExemptionReason(int uid, String pkg) {
2933         final PackageManagerInternal pm = mInjector.getPackageManagerInternal();
2934         final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal();
2935         final AppOpsManager appOpsManager = mInjector.getAppOpsManager();
2936         final ActivityManagerService activityManagerService = mInjector.getActivityManagerService();
2937         final int userId = UserHandle.getUserId(uid);
2938         if (isSystemModule(pkg)) {
2939             return REASON_SYSTEM_MODULE;
2940         } else if (isCarrierApp(pkg)) {
2941             return REASON_CARRIER_PRIVILEGED_APP;
2942         } else if (isExemptedFromSysConfig(pkg)) {
2943             return REASON_SYSTEM_ALLOW_LISTED;
2944         } else if (mConstantsObserver.mBgRestrictionExemptedPackages.contains(pkg)) {
2945             return REASON_SYSTEM_ALLOW_LISTED;
2946         } else if (pm.isPackageStateProtected(pkg, userId)) {
2947             return REASON_DPO_PROTECTED_APP;
2948         } else if (appStandbyInternal.isActiveDeviceAdmin(pkg, userId)) {
2949             return REASON_ACTIVE_DEVICE_ADMIN;
2950         } else if (activityManagerService.mConstants.mFlagSystemExemptPowerRestrictionsEnabled
2951                 && appOpsManager.checkOpNoThrow(
2952                 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS, uid, pkg)
2953                 == AppOpsManager.MODE_ALLOWED) {
2954             return REASON_SYSTEM_EXEMPT_APP_OP;
2955         }
2956         return REASON_DENIED;
2957     }
2958 
2959     /**
2960      * @param uid The uid to check.
2961      * @param pkgName The package name to check.
2962      * @return The potential user-allowed exemption reason of the given uid/package. The caller
2963      * must decide whether or not it should be exempted.
2964      */
2965     @ReasonCode
2966     int getPotentialUserAllowedExemptionReason(int uid, String pkg) {
2967         final AppOpsManager appOpsManager = mInjector.getAppOpsManager();
2968         if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN,
2969                 uid, pkg) == AppOpsManager.MODE_ALLOWED) {
2970             return REASON_OP_ACTIVATE_VPN;
2971         } else if (appOpsManager.checkOpNoThrow(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN,
2972                 uid, pkg) == AppOpsManager.MODE_ALLOWED) {
2973             return REASON_OP_ACTIVATE_PLATFORM_VPN;
2974         }
2975         if (isRoleHeldByUid(RoleManager.ROLE_DIALER, uid)) {
2976             return REASON_ROLE_DIALER;
2977         }
2978         if (isRoleHeldByUid(RoleManager.ROLE_EMERGENCY, uid)) {
2979             return REASON_ROLE_EMERGENCY;
2980         }
2981         if (isOnDeviceIdleAllowlist(uid)) {
2982             return REASON_ALLOWLISTED_PACKAGE;
2983         }
2984         final ActivityManagerInternal am = mInjector.getActivityManagerInternal();
2985         if (am.isAssociatedCompanionApp(UserHandle.getUserId(uid), uid)) {
2986             return REASON_COMPANION_DEVICE_MANAGER;
2987         }
2988         return REASON_DENIED;
2989     }
2990 
2991     private boolean isCarrierApp(String packageName) {
2992         synchronized (mCarrierPrivilegedLock) {
2993             if (mCarrierPrivilegedApps != null) {
2994                 for (int i = mCarrierPrivilegedApps.size() - 1; i >= 0; i--) {
2995                     if (mCarrierPrivilegedApps.valueAt(i).contains(packageName)) {
2996                         return true;
2997                     }
2998                 }
2999             }
3000             return false;
3001         }
3002     }
3003 
3004     private void registerCarrierPrivilegesCallbacks() {
3005         final TelephonyManager telephonyManager = mInjector.getTelephonyManager();
3006         if (telephonyManager == null) {
3007             return;
3008         }
3009 
3010         final int numPhones = telephonyManager.getActiveModemCount();
3011         final ArrayList<PhoneCarrierPrivilegesCallback> callbacks = new ArrayList<>();
3012         for (int i = 0; i < numPhones; i++) {
3013             final PhoneCarrierPrivilegesCallback callback = new PhoneCarrierPrivilegesCallback(i);
3014             callbacks.add(callback);
3015             telephonyManager.registerCarrierPrivilegesCallback(i, mExecutor, callback);
3016         }
3017         mCarrierPrivilegesCallbacks = callbacks;
3018     }
3019 
3020     private void unregisterCarrierPrivilegesCallbacks() {
3021         final TelephonyManager telephonyManager = mInjector.getTelephonyManager();
3022         if (telephonyManager == null) {
3023             return;
3024         }
3025         final ArrayList<PhoneCarrierPrivilegesCallback> callbacks = mCarrierPrivilegesCallbacks;
3026         if (callbacks != null) {
3027             for (int i = callbacks.size() - 1; i >= 0; i--) {
3028                 telephonyManager.unregisterCarrierPrivilegesCallback(callbacks.get(i));
3029             }
3030             mCarrierPrivilegesCallbacks = null;
3031         }
3032     }
3033 
3034     private class PhoneCarrierPrivilegesCallback implements CarrierPrivilegesCallback {
3035         private final int mPhoneId;
3036 
3037         PhoneCarrierPrivilegesCallback(int phoneId) {
3038             mPhoneId = phoneId;
3039         }
3040 
3041         @Override
3042         public void onCarrierPrivilegesChanged(@NonNull Set<String> privilegedPackageNames,
3043                 @NonNull Set<Integer> privilegedUids) {
3044             synchronized (mCarrierPrivilegedLock) {
3045                 mCarrierPrivilegedApps.put(mPhoneId,
3046                         Collections.unmodifiableSet(privilegedPackageNames));
3047             }
3048         }
3049     }
3050 
3051     private boolean isRoleHeldByUid(@NonNull String roleName, int uid) {
3052         synchronized (mLock) {
3053             final ArrayList<String> roles = mUidRolesMapping.get(uid);
3054             return roles != null && roles.indexOf(roleName) >= 0;
3055         }
3056     }
3057 
3058     private void initRolesInInterest() {
3059         final int[] allUsers = mInjector.getUserManagerInternal().getUserIds();
3060         for (String role : ROLES_IN_INTEREST) {
3061             if (mInjector.getRoleManager().isRoleAvailable(role)) {
3062                 for (int userId : allUsers) {
3063                     final UserHandle user = UserHandle.of(userId);
3064                     onRoleHoldersChanged(role, user);
3065                 }
3066             }
3067         }
3068     }
3069 
3070     private void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
3071         final List<String> rolePkgs = mInjector.getRoleManager().getRoleHoldersAsUser(
3072                 roleName, user);
3073         final ArraySet<Integer> roleUids = new ArraySet<>();
3074         final int userId = user.getIdentifier();
3075         if (rolePkgs != null) {
3076             final PackageManagerInternal pm = mInjector.getPackageManagerInternal();
3077             for (String pkg: rolePkgs) {
3078                 roleUids.add(pm.getPackageUid(pkg, STOCK_PM_FLAGS, userId));
3079             }
3080         }
3081         synchronized (mLock) {
3082             for (int i = mUidRolesMapping.size() - 1; i >= 0; i--) {
3083                 final int uid = mUidRolesMapping.keyAt(i);
3084                 if (UserHandle.getUserId(uid) != userId) {
3085                     continue;
3086                 }
3087                 final ArrayList<String> roles = mUidRolesMapping.valueAt(i);
3088                 final int index = roles.indexOf(roleName);
3089                 final boolean isRole = roleUids.contains(uid);
3090                 if (index >= 0) {
3091                     if (!isRole) { // Not holding this role anymore, remove it.
3092                         roles.remove(index);
3093                         if (roles.isEmpty()) {
3094                             mUidRolesMapping.removeAt(i);
3095                         }
3096                     }
3097                 } else if (isRole) { // Got this new role, add it.
3098                     roles.add(roleName);
3099                     roleUids.remove(uid);
3100                 }
3101             }
3102             for (int i = roleUids.size() - 1; i >= 0; i--) { // Take care of the leftovers.
3103                 final ArrayList<String> roles = new ArrayList<>();
3104                 roles.add(roleName);
3105                 mUidRolesMapping.put(roleUids.valueAt(i), roles);
3106             }
3107         }
3108     }
3109 
3110     /**
3111      * @return The background handler of this controller.
3112      */
3113     Handler getBackgroundHandler() {
3114         return mBgHandler;
3115     }
3116 
3117     /**
3118      * @return The background handler thread of this controller.
3119      */
3120     @VisibleForTesting
3121     HandlerThread getBackgroundHandlerThread() {
3122         return mBgHandlerThread;
3123     }
3124 
3125     /**
3126      * @return The global lock of this controller.
3127      */
3128     Object getLock() {
3129         return mLock;
3130     }
3131 
3132     @VisibleForTesting
3133     void addAppStateTracker(@NonNull BaseAppStateTracker tracker) {
3134         mAppStateTrackers.add(tracker);
3135     }
3136 
3137     /**
3138      * @return The tracker instance of the given class.
3139      */
3140     <T extends BaseAppStateTracker> T getAppStateTracker(Class<T> trackerClass) {
3141         for (BaseAppStateTracker tracker : mAppStateTrackers) {
3142             if (trackerClass.isAssignableFrom(tracker.getClass())) {
3143                 return (T) tracker;
3144             }
3145         }
3146         return null;
3147     }
3148 
3149     void postLongRunningFgsIfNecessary(String packageName, int uid) {
3150         mNotificationHelper.postLongRunningFgsIfNecessary(packageName, uid);
3151     }
3152 
3153     void cancelLongRunningFGSNotificationIfNecessary(String packageName, int uid) {
3154         mNotificationHelper.cancelLongRunningFGSNotificationIfNecessary(packageName, uid);
3155     }
3156 
3157     String getPackageName(int pid) {
3158         return mInjector.getPackageName(pid);
3159     }
3160 
3161     static class BgHandler extends Handler {
3162         static final int MSG_BACKGROUND_RESTRICTION_CHANGED = 0;
3163         static final int MSG_APP_RESTRICTION_LEVEL_CHANGED = 1;
3164         static final int MSG_APP_STANDBY_BUCKET_CHANGED = 2;
3165         static final int MSG_USER_INTERACTION_STARTED = 3;
3166         static final int MSG_REQUEST_BG_RESTRICTED = 4;
3167         static final int MSG_UID_IDLE = 5;
3168         static final int MSG_UID_ACTIVE = 6;
3169         static final int MSG_UID_GONE = 7;
3170         static final int MSG_UID_PROC_STATE_CHANGED = 8;
3171         static final int MSG_CANCEL_REQUEST_BG_RESTRICTED = 9;
3172         static final int MSG_LOAD_RESTRICTION_SETTINGS = 10;
3173         static final int MSG_PERSIST_RESTRICTION_SETTINGS = 11;
3174 
3175         private final Injector mInjector;
3176 
3177         BgHandler(Looper looper, Injector injector) {
3178             super(looper);
3179             mInjector = injector;
3180         }
3181 
3182         @Override
3183         public void handleMessage(Message msg) {
3184             final AppRestrictionController c = mInjector
3185                     .getAppRestrictionController();
3186             switch (msg.what) {
3187                 case MSG_BACKGROUND_RESTRICTION_CHANGED: {
3188                     c.handleBackgroundRestrictionChanged(msg.arg1, (String) msg.obj, msg.arg2 == 1);
3189                 } break;
3190                 case MSG_APP_RESTRICTION_LEVEL_CHANGED: {
3191                     c.dispatchAppRestrictionLevelChanges(msg.arg1, (String) msg.obj, msg.arg2);
3192                 } break;
3193                 case MSG_APP_STANDBY_BUCKET_CHANGED: {
3194                     c.handleAppStandbyBucketChanged(msg.arg2, (String) msg.obj, msg.arg1);
3195                 } break;
3196                 case MSG_USER_INTERACTION_STARTED: {
3197                     c.onUserInteractionStarted((String) msg.obj, msg.arg1);
3198                 } break;
3199                 case MSG_REQUEST_BG_RESTRICTED: {
3200                     c.handleRequestBgRestricted((String) msg.obj, msg.arg1);
3201                 } break;
3202                 case MSG_UID_IDLE: {
3203                     c.handleUidInactive(msg.arg1, msg.arg2 == 1);
3204                 } break;
3205                 case MSG_UID_ACTIVE: {
3206                     c.handleUidActive(msg.arg1);
3207                 } break;
3208                 case MSG_CANCEL_REQUEST_BG_RESTRICTED: {
3209                     c.handleCancelRequestBgRestricted((String) msg.obj, msg.arg1);
3210                 } break;
3211                 case MSG_UID_PROC_STATE_CHANGED: {
3212                     c.handleUidProcStateChanged(msg.arg1, msg.arg2);
3213                 } break;
3214                 case MSG_UID_GONE: {
3215                     // It also means this UID is inactive now.
3216                     c.handleUidInactive(msg.arg1, msg.arg2 == 1);
3217                     c.handleUidGone(msg.arg1);
3218                 } break;
3219                 case MSG_LOAD_RESTRICTION_SETTINGS: {
3220                     c.mRestrictionSettings.loadFromXml(true);
3221                 } break;
3222                 case MSG_PERSIST_RESTRICTION_SETTINGS: {
3223                     c.mRestrictionSettings.persistToXml(msg.arg1);
3224                 } break;
3225             }
3226         }
3227     }
3228 
3229     static class Injector {
3230         private final Context mContext;
3231         private ActivityManagerInternal mActivityManagerInternal;
3232         private AppRestrictionController mAppRestrictionController;
3233         private AppOpsManager mAppOpsManager;
3234         private AppStandbyInternal mAppStandbyInternal;
3235         private AppStateTracker mAppStateTracker;
3236         private AppHibernationManagerInternal mAppHibernationInternal;
3237         private IActivityManager mIActivityManager;
3238         private UserManagerInternal mUserManagerInternal;
3239         private PackageManagerInternal mPackageManagerInternal;
3240         private NotificationManager mNotificationManager;
3241         private RoleManager mRoleManager;
3242         private AppBatteryTracker mAppBatteryTracker;
3243         private AppBatteryExemptionTracker mAppBatteryExemptionTracker;
3244         private AppFGSTracker mAppFGSTracker;
3245         private AppMediaSessionTracker mAppMediaSessionTracker;
3246         private AppPermissionTracker mAppPermissionTracker;
3247         private TelephonyManager mTelephonyManager;
3248 
3249         Injector(Context context) {
3250             mContext = context;
3251         }
3252 
3253         Context getContext() {
3254             return mContext;
3255         }
3256 
3257         void initAppStateTrackers(AppRestrictionController controller) {
3258             mAppRestrictionController = controller;
3259             mAppBatteryTracker = new AppBatteryTracker(mContext, controller);
3260             mAppBatteryExemptionTracker = new AppBatteryExemptionTracker(mContext, controller);
3261             mAppFGSTracker = new AppFGSTracker(mContext, controller);
3262             mAppMediaSessionTracker = new AppMediaSessionTracker(mContext, controller);
3263             mAppPermissionTracker = new AppPermissionTracker(mContext, controller);
3264             controller.mAppStateTrackers.add(mAppBatteryTracker);
3265             controller.mAppStateTrackers.add(mAppBatteryExemptionTracker);
3266             controller.mAppStateTrackers.add(mAppFGSTracker);
3267             controller.mAppStateTrackers.add(mAppMediaSessionTracker);
3268             controller.mAppStateTrackers.add(mAppPermissionTracker);
3269             controller.mAppStateTrackers.add(new AppBroadcastEventsTracker(mContext, controller));
3270             controller.mAppStateTrackers.add(new AppBindServiceEventsTracker(mContext, controller));
3271         }
3272 
3273         ActivityManagerInternal getActivityManagerInternal() {
3274             if (mActivityManagerInternal == null) {
3275                 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
3276             }
3277             return mActivityManagerInternal;
3278         }
3279 
3280         AppRestrictionController getAppRestrictionController() {
3281             return mAppRestrictionController;
3282         }
3283 
3284         AppOpsManager getAppOpsManager() {
3285             if (mAppOpsManager == null) {
3286                 mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
3287             }
3288             return mAppOpsManager;
3289         }
3290 
3291         AppStandbyInternal getAppStandbyInternal() {
3292             if (mAppStandbyInternal == null) {
3293                 mAppStandbyInternal = LocalServices.getService(AppStandbyInternal.class);
3294             }
3295             return mAppStandbyInternal;
3296         }
3297 
3298         AppHibernationManagerInternal getAppHibernationInternal() {
3299             if (mAppHibernationInternal == null) {
3300                 mAppHibernationInternal = LocalServices.getService(
3301                         AppHibernationManagerInternal.class);
3302             }
3303             return mAppHibernationInternal;
3304         }
3305 
3306         AppStateTracker getAppStateTracker() {
3307             if (mAppStateTracker == null) {
3308                 mAppStateTracker = LocalServices.getService(AppStateTracker.class);
3309             }
3310             return mAppStateTracker;
3311         }
3312 
3313         IActivityManager getIActivityManager() {
3314             return ActivityManager.getService();
3315         }
3316 
3317         UserManagerInternal getUserManagerInternal() {
3318             if (mUserManagerInternal == null) {
3319                 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
3320             }
3321             return mUserManagerInternal;
3322         }
3323 
3324         PackageManagerInternal getPackageManagerInternal() {
3325             if (mPackageManagerInternal == null) {
3326                 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
3327             }
3328             return mPackageManagerInternal;
3329         }
3330 
3331         PackageManager getPackageManager() {
3332             return getContext().getPackageManager();
3333         }
3334 
3335         NotificationManager getNotificationManager() {
3336             if (mNotificationManager == null) {
3337                 mNotificationManager = getContext().getSystemService(NotificationManager.class);
3338             }
3339             return mNotificationManager;
3340         }
3341 
3342         RoleManager getRoleManager() {
3343             if (mRoleManager == null) {
3344                 mRoleManager = getContext().getSystemService(RoleManager.class);
3345             }
3346             return mRoleManager;
3347         }
3348 
3349         TelephonyManager getTelephonyManager() {
3350             if (mTelephonyManager == null) {
3351                 mTelephonyManager = getContext().getSystemService(TelephonyManager.class);
3352             }
3353             return mTelephonyManager;
3354         }
3355 
3356         AppFGSTracker getAppFGSTracker() {
3357             return mAppFGSTracker;
3358         }
3359 
3360         AppMediaSessionTracker getAppMediaSessionTracker() {
3361             return mAppMediaSessionTracker;
3362         }
3363 
3364         ActivityManagerService getActivityManagerService() {
3365             return mAppRestrictionController.mActivityManagerService;
3366         }
3367 
3368         UidBatteryUsageProvider getUidBatteryUsageProvider() {
3369             return mAppBatteryTracker;
3370         }
3371 
3372         AppBatteryExemptionTracker getAppBatteryExemptionTracker() {
3373             return mAppBatteryExemptionTracker;
3374         }
3375 
3376         AppPermissionTracker getAppPermissionTracker() {
3377             return mAppPermissionTracker;
3378         }
3379 
3380         String getPackageName(int pid) {
3381             final ActivityManagerService am = getActivityManagerService();
3382             final ProcessRecord app;
3383             synchronized (am.mPidsSelfLocked) {
3384                 app = am.mPidsSelfLocked.get(pid);
3385                 if (app != null) {
3386                     final ApplicationInfo ai = app.info;
3387                     if (ai != null) {
3388                         return ai.packageName;
3389                     }
3390                 }
3391             }
3392             return null;
3393         }
3394 
3395         void scheduleInitTrackers(Handler handler, Runnable initializers) {
3396             handler.post(initializers);
3397         }
3398 
3399         File getDataSystemDeDirectory(@UserIdInt int userId) {
3400             return Environment.getDataSystemDeDirectory(userId);
3401         }
3402 
3403         @CurrentTimeMillisLong long currentTimeMillis() {
3404             return System.currentTimeMillis();
3405         }
3406 
3407         Handler getDefaultHandler() {
3408             return mAppRestrictionController.mActivityManagerService.mHandler;
3409         }
3410 
3411         boolean isTest() {
3412             return false;
3413         }
3414     }
3415 
3416     private void registerForSystemBroadcasts() {
3417         final IntentFilter packageFilter = new IntentFilter();
3418         packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
3419         packageFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
3420         packageFilter.addDataScheme("package");
3421         mContext.registerReceiverForAllUsers(mBroadcastReceiver, packageFilter, null, mBgHandler);
3422         final IntentFilter userFilter = new IntentFilter();
3423         userFilter.addAction(Intent.ACTION_USER_ADDED);
3424         userFilter.addAction(Intent.ACTION_USER_REMOVED);
3425         userFilter.addAction(Intent.ACTION_UID_REMOVED);
3426         mContext.registerReceiverForAllUsers(mBroadcastReceiver, userFilter, null, mBgHandler);
3427         final IntentFilter bootFilter = new IntentFilter();
3428         bootFilter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED);
3429         mContext.registerReceiverAsUser(mBootReceiver, UserHandle.SYSTEM,
3430                 bootFilter, null, mBgHandler);
3431         final IntentFilter telFilter = new IntentFilter(
3432                 TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
3433         mContext.registerReceiverForAllUsers(mBroadcastReceiver, telFilter, null, mBgHandler);
3434     }
3435 
3436     private void unregisterForSystemBroadcasts() {
3437         mContext.unregisterReceiver(mBroadcastReceiver);
3438         mContext.unregisterReceiver(mBootReceiver);
3439     }
3440 
3441     void forEachTracker(Consumer<BaseAppStateTracker> sink) {
3442         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
3443             sink.accept(mAppStateTrackers.get(i));
3444         }
3445     }
3446 
3447     private void onUserAdded(@UserIdInt int userId) {
3448         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
3449             mAppStateTrackers.get(i).onUserAdded(userId);
3450         }
3451     }
3452 
3453     private void onUserStarted(@UserIdInt int userId) {
3454         refreshAppRestrictionLevelForUser(userId, REASON_MAIN_FORCED_BY_USER,
3455                 REASON_SUB_FORCED_USER_FLAG_INTERACTION);
3456         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
3457             mAppStateTrackers.get(i).onUserStarted(userId);
3458         }
3459     }
3460 
3461     private void onUserStopped(@UserIdInt int userId) {
3462         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
3463             mAppStateTrackers.get(i).onUserStopped(userId);
3464         }
3465     }
3466 
3467     private void onUserRemoved(@UserIdInt int userId) {
3468         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
3469             mAppStateTrackers.get(i).onUserRemoved(userId);
3470         }
3471         mRestrictionSettings.removeUser(userId);
3472     }
3473 
3474     private void onUidAdded(int uid) {
3475         refreshAppRestrictionLevelForUid(uid, REASON_MAIN_FORCED_BY_SYSTEM,
3476                 REASON_SUB_FORCED_SYSTEM_FLAG_UNDEFINED, false);
3477         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
3478             mAppStateTrackers.get(i).onUidAdded(uid);
3479         }
3480     }
3481 
3482     private void onPackageRemoved(String pkgName, int uid) {
3483         mRestrictionSettings.removePackage(pkgName, uid);
3484     }
3485 
3486     private void onUidRemoved(int uid) {
3487         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
3488             mAppStateTrackers.get(i).onUidRemoved(uid);
3489         }
3490         mRestrictionSettings.removeUid(uid);
3491     }
3492 
3493     private void onLockedBootCompleted() {
3494         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
3495             mAppStateTrackers.get(i).onLockedBootCompleted();
3496         }
3497         mLockedBootCompleted = true;
3498     }
3499 
3500     boolean isBgAutoRestrictedBucketFeatureFlagEnabled() {
3501         return mConstantsObserver.mBgAutoRestrictedBucket;
3502     }
3503 
3504     private void onPropertiesChanged(String name) {
3505         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
3506             mAppStateTrackers.get(i).onPropertiesChanged(name);
3507         }
3508     }
3509 
3510     private void onUserInteractionStarted(String packageName, @UserIdInt int userId) {
3511         final int uid = mInjector.getPackageManagerInternal()
3512                 .getPackageUid(packageName, STOCK_PM_FLAGS, userId);
3513         for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
3514             mAppStateTrackers.get(i).onUserInteractionStarted(packageName, uid);
3515         }
3516     }
3517 }
3518