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