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