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