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