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