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