1 /* 2 * Copyright (C) 2021 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.pm; 18 19 import static android.os.PowerExemptionManager.REASON_LOCKED_BOOT_COMPLETED; 20 import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED; 21 import static android.safetylabel.SafetyLabelConstants.SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED; 22 23 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; 24 import static com.android.server.pm.PackageManagerService.PACKAGE_SCHEME; 25 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; 26 import static com.android.server.pm.PackageManagerService.TAG; 27 28 import android.Manifest; 29 import android.annotation.AppIdInt; 30 import android.annotation.NonNull; 31 import android.annotation.Nullable; 32 import android.app.ActivityManager; 33 import android.app.ActivityManagerInternal; 34 import android.app.BroadcastOptions; 35 import android.app.IActivityManager; 36 import android.content.ComponentName; 37 import android.content.Context; 38 import android.content.IIntentReceiver; 39 import android.content.Intent; 40 import android.content.pm.PackageInstaller; 41 import android.content.pm.PackageManager; 42 import android.net.Uri; 43 import android.os.Bundle; 44 import android.os.PowerExemptionManager; 45 import android.os.RemoteException; 46 import android.os.UserHandle; 47 import android.provider.DeviceConfig; 48 import android.util.IntArray; 49 import android.util.Log; 50 import android.util.Pair; 51 import android.util.Slog; 52 import android.util.SparseArray; 53 54 import com.android.internal.util.ArrayUtils; 55 56 import java.util.ArrayList; 57 import java.util.function.BiFunction; 58 import java.util.function.Supplier; 59 60 /** 61 * Helper class to send broadcasts for various situations. 62 */ 63 public final class BroadcastHelper { 64 private static final boolean DEBUG_BROADCASTS = false; 65 /** 66 * Permissions required in order to receive instant application lifecycle broadcasts. 67 */ 68 private static final String[] INSTANT_APP_BROADCAST_PERMISSION = 69 new String[]{android.Manifest.permission.ACCESS_INSTANT_APPS}; 70 71 private final UserManagerInternal mUmInternal; 72 private final ActivityManagerInternal mAmInternal; 73 private final Context mContext; 74 BroadcastHelper(PackageManagerServiceInjector injector)75 BroadcastHelper(PackageManagerServiceInjector injector) { 76 mUmInternal = injector.getUserManagerInternal(); 77 mAmInternal = injector.getActivityManagerInternal(); 78 mContext = injector.getContext(); 79 } 80 sendPackageBroadcast(final String action, final String pkg, final Bundle extras, final int flags, final String targetPkg, final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds, @Nullable SparseArray<int[]> broadcastAllowList, @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver, @Nullable Bundle bOptions)81 public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras, 82 final int flags, final String targetPkg, final IIntentReceiver finishedReceiver, 83 final int[] userIds, int[] instantUserIds, 84 @Nullable SparseArray<int[]> broadcastAllowList, 85 @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver, 86 @Nullable Bundle bOptions) { 87 try { 88 final IActivityManager am = ActivityManager.getService(); 89 if (am == null) return; 90 final int[] resolvedUserIds; 91 if (userIds == null) { 92 resolvedUserIds = am.getRunningUserIds(); 93 } else { 94 resolvedUserIds = userIds; 95 } 96 97 if (ArrayUtils.isEmpty(instantUserIds)) { 98 doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver, 99 resolvedUserIds, false /* isInstantApp */, broadcastAllowList, 100 filterExtrasForReceiver, bOptions); 101 } else { 102 // send restricted broadcasts for instant apps 103 doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver, 104 instantUserIds, true /* isInstantApp */, null, 105 null /* filterExtrasForReceiver */, bOptions); 106 } 107 } catch (RemoteException ex) { 108 } 109 } 110 111 /** 112 * Sends a broadcast for the given action. 113 * <p>If {@code isInstantApp} is {@code true}, then the broadcast is protected with 114 * the {@link android.Manifest.permission#ACCESS_INSTANT_APPS} permission. This allows 115 * the system and applications allowed to see instant applications to receive package 116 * lifecycle events for instant applications. 117 */ doSendBroadcast(String action, String pkg, Bundle extras, int flags, String targetPkg, IIntentReceiver finishedReceiver, int[] userIds, boolean isInstantApp, @Nullable SparseArray<int[]> broadcastAllowList, @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver, @Nullable Bundle bOptions)118 public void doSendBroadcast(String action, String pkg, Bundle extras, 119 int flags, String targetPkg, IIntentReceiver finishedReceiver, 120 int[] userIds, boolean isInstantApp, @Nullable SparseArray<int[]> broadcastAllowList, 121 @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver, 122 @Nullable Bundle bOptions) { 123 for (int userId : userIds) { 124 final Intent intent = new Intent(action, 125 pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null); 126 final String[] requiredPermissions = 127 isInstantApp ? INSTANT_APP_BROADCAST_PERMISSION : null; 128 if (extras != null) { 129 intent.putExtras(extras); 130 } 131 if (targetPkg != null) { 132 intent.setPackage(targetPkg); 133 } 134 // Modify the UID when posting to other users 135 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 136 if (uid >= 0 && UserHandle.getUserId(uid) != userId) { 137 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid)); 138 intent.putExtra(Intent.EXTRA_UID, uid); 139 } 140 if (broadcastAllowList != null && PLATFORM_PACKAGE_NAME.equals(targetPkg)) { 141 intent.putExtra(Intent.EXTRA_VISIBILITY_ALLOW_LIST, 142 broadcastAllowList.get(userId)); 143 } 144 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); 145 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | flags); 146 if (DEBUG_BROADCASTS) { 147 RuntimeException here = new RuntimeException("here"); 148 here.fillInStackTrace(); 149 Slog.d(TAG, "Sending to user " + userId + ": " 150 + intent.toShortString(false, true, false, false) 151 + " " + intent.getExtras(), here); 152 } 153 final boolean ordered; 154 if (mAmInternal.isModernQueueEnabled()) { 155 // When the modern broadcast stack is enabled, deliver all our 156 // broadcasts as unordered, since the modern stack has better 157 // support for sequencing cold-starts, and it supports 158 // delivering resultTo for non-ordered broadcasts 159 ordered = false; 160 } else { 161 ordered = (finishedReceiver != null); 162 } 163 mAmInternal.broadcastIntent( 164 intent, finishedReceiver, requiredPermissions, ordered, userId, 165 broadcastAllowList == null ? null : broadcastAllowList.get(userId), 166 filterExtrasForReceiver, bOptions); 167 } 168 } 169 sendResourcesChangedBroadcast(@onNull Supplier<Computer> snapshotComputer, boolean mediaStatus, boolean replacing, @NonNull String[] pkgNames, @NonNull int[] uids)170 public void sendResourcesChangedBroadcast(@NonNull Supplier<Computer> snapshotComputer, 171 boolean mediaStatus, boolean replacing, @NonNull String[] pkgNames, 172 @NonNull int[] uids) { 173 if (ArrayUtils.isEmpty(pkgNames) || ArrayUtils.isEmpty(uids)) { 174 return; 175 } 176 Bundle extras = new Bundle(); 177 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgNames); 178 extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uids); 179 if (replacing) { 180 extras.putBoolean(Intent.EXTRA_REPLACING, replacing); 181 } 182 String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE 183 : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; 184 sendPackageBroadcast(action, null /* pkg */, extras, 0 /* flags */, 185 null /* targetPkg */, null /* finishedReceiver */, null /* userIds */, 186 null /* instantUserIds */, null /* broadcastAllowList */, 187 (callingUid, intentExtras) -> filterExtrasChangedPackageList( 188 snapshotComputer.get(), callingUid, intentExtras), 189 null /* bOptions */); 190 } 191 192 /** 193 * The just-installed/enabled app is bundled on the system, so presumed to be able to run 194 * automatically without needing an explicit launch. 195 * Send it a LOCKED_BOOT_COMPLETED/BOOT_COMPLETED if it would ordinarily have gotten ones. 196 */ sendBootCompletedBroadcastToSystemApp( String packageName, boolean includeStopped, int userId)197 public void sendBootCompletedBroadcastToSystemApp( 198 String packageName, boolean includeStopped, int userId) { 199 // If user is not running, the app didn't miss any broadcast 200 if (!mUmInternal.isUserRunning(userId)) { 201 return; 202 } 203 final IActivityManager am = ActivityManager.getService(); 204 try { 205 // Deliver LOCKED_BOOT_COMPLETED first 206 Intent lockedBcIntent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED) 207 .setPackage(packageName); 208 if (includeStopped) { 209 lockedBcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); 210 } 211 final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED}; 212 final BroadcastOptions bOptions = getTemporaryAppAllowlistBroadcastOptions( 213 REASON_LOCKED_BOOT_COMPLETED); 214 am.broadcastIntentWithFeature(null, null, lockedBcIntent, null, null, 0, null, null, 215 requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, 216 bOptions.toBundle(), false, false, userId); 217 218 // Deliver BOOT_COMPLETED only if user is unlocked 219 if (mUmInternal.isUserUnlockingOrUnlocked(userId)) { 220 Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName); 221 if (includeStopped) { 222 bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); 223 } 224 am.broadcastIntentWithFeature(null, null, bcIntent, null, null, 0, null, null, 225 requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, 226 bOptions.toBundle(), false, false, userId); 227 } 228 } catch (RemoteException e) { 229 throw e.rethrowFromSystemServer(); 230 } 231 } 232 getTemporaryAppAllowlistBroadcastOptions( @owerExemptionManager.ReasonCode int reasonCode)233 public @NonNull BroadcastOptions getTemporaryAppAllowlistBroadcastOptions( 234 @PowerExemptionManager.ReasonCode int reasonCode) { 235 long duration = 10_000; 236 if (mAmInternal != null) { 237 duration = mAmInternal.getBootTimeTempAllowListDuration(); 238 } 239 final BroadcastOptions bOptions = BroadcastOptions.makeBasic(); 240 bOptions.setTemporaryAppAllowlist(duration, 241 TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, 242 reasonCode, ""); 243 return bOptions; 244 } 245 sendPackageChangedBroadcast(String packageName, boolean dontKillApp, ArrayList<String> componentNames, int packageUid, String reason, int[] userIds, int[] instantUserIds, SparseArray<int[]> broadcastAllowList)246 public void sendPackageChangedBroadcast(String packageName, boolean dontKillApp, 247 ArrayList<String> componentNames, int packageUid, String reason, 248 int[] userIds, int[] instantUserIds, SparseArray<int[]> broadcastAllowList) { 249 if (DEBUG_INSTALL) { 250 Log.v(TAG, "Sending package changed: package=" + packageName + " components=" 251 + componentNames); 252 } 253 Bundle extras = new Bundle(4); 254 extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0)); 255 String[] nameList = new String[componentNames.size()]; 256 componentNames.toArray(nameList); 257 extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList); 258 extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, dontKillApp); 259 extras.putInt(Intent.EXTRA_UID, packageUid); 260 if (reason != null) { 261 extras.putString(Intent.EXTRA_REASON, reason); 262 } 263 // If this is not reporting a change of the overall package, then only send it 264 // to registered receivers. We don't want to launch a swath of apps for every 265 // little component state change. 266 final int flags = !componentNames.contains(packageName) 267 ? Intent.FLAG_RECEIVER_REGISTERED_ONLY : 0; 268 sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, flags, null, null, 269 userIds, instantUserIds, broadcastAllowList, null /* filterExtrasForReceiver */, 270 null /* bOptions */); 271 } 272 sendDeviceCustomizationReadyBroadcast()273 public static void sendDeviceCustomizationReadyBroadcast() { 274 final Intent intent = new Intent(Intent.ACTION_DEVICE_CUSTOMIZATION_READY); 275 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 276 final IActivityManager am = ActivityManager.getService(); 277 final String[] requiredPermissions = { 278 Manifest.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY, 279 }; 280 try { 281 am.broadcastIntentWithFeature(null, null, intent, null, null, 0, null, null, 282 requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, null, false, 283 false, UserHandle.USER_ALL); 284 } catch (RemoteException e) { 285 throw e.rethrowFromSystemServer(); 286 } 287 } 288 sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId, int launcherUid, @Nullable ComponentName launcherComponent, @Nullable String appPredictionServicePackage)289 public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId, 290 int launcherUid, @Nullable ComponentName launcherComponent, 291 @Nullable String appPredictionServicePackage) { 292 if (launcherComponent != null) { 293 Intent launcherIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED) 294 .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo) 295 .putExtra(Intent.EXTRA_USER, UserHandle.of(userId)) 296 .setPackage(launcherComponent.getPackageName()); 297 mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid)); 298 } 299 // TODO(b/122900055) Change/Remove this and replace with new permission role. 300 if (appPredictionServicePackage != null) { 301 Intent predictorIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED) 302 .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo) 303 .putExtra(Intent.EXTRA_USER, UserHandle.of(userId)) 304 .setPackage(appPredictionServicePackage); 305 mContext.sendBroadcastAsUser(predictorIntent, UserHandle.of(launcherUid)); 306 } 307 } 308 sendPreferredActivityChangedBroadcast(int userId)309 public void sendPreferredActivityChangedBroadcast(int userId) { 310 final IActivityManager am = ActivityManager.getService(); 311 if (am == null) { 312 return; 313 } 314 315 final Intent intent = new Intent(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED); 316 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); 317 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 318 try { 319 am.broadcastIntentWithFeature(null, null, intent, null, null, 320 0, null, null, null, null, null, android.app.AppOpsManager.OP_NONE, 321 null, false, false, userId); 322 } catch (RemoteException e) { 323 } 324 } 325 sendPackageAddedForNewUsers(String packageName, @AppIdInt int appId, int[] userIds, int[] instantUserIds, int dataLoaderType, SparseArray<int[]> broadcastAllowlist)326 public void sendPackageAddedForNewUsers(String packageName, 327 @AppIdInt int appId, int[] userIds, int[] instantUserIds, 328 int dataLoaderType, SparseArray<int[]> broadcastAllowlist) { 329 Bundle extras = new Bundle(1); 330 // Set to UID of the first user, EXTRA_UID is automatically updated in sendPackageBroadcast 331 final int uid = UserHandle.getUid( 332 (ArrayUtils.isEmpty(userIds) ? instantUserIds[0] : userIds[0]), appId); 333 extras.putInt(Intent.EXTRA_UID, uid); 334 extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType); 335 336 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, 337 packageName, extras, 0, null, null, userIds, instantUserIds, 338 broadcastAllowlist, null /* filterExtrasForReceiver */, null); 339 // Send to PermissionController for all new users, even if it may not be running for some 340 // users 341 if (isPrivacySafetyLabelChangeNotificationsEnabled(mContext)) { 342 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, 343 packageName, extras, 0, 344 mContext.getPackageManager().getPermissionControllerPackageName(), 345 null, userIds, instantUserIds, 346 broadcastAllowlist, null /* filterExtrasForReceiver */, null); 347 } 348 } 349 sendFirstLaunchBroadcast(String pkgName, String installerPkg, int[] userIds, int[] instantUserIds)350 public void sendFirstLaunchBroadcast(String pkgName, String installerPkg, 351 int[] userIds, int[] instantUserIds) { 352 sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0, 353 installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */, 354 null /* filterExtrasForReceiver */, null); 355 } 356 357 /** 358 * Filter package names for the intent extras {@link Intent#EXTRA_CHANGED_PACKAGE_LIST} and 359 * {@link Intent#EXTRA_CHANGED_UID_LIST} by using the rules of the package visibility. 360 * 361 * @param callingUid The uid that is going to access the intent extras. 362 * @param extras The intent extras to filter 363 * @return An extras that have been filtered, or {@code null} if the given uid is unable to 364 * access all the packages in the extras. 365 */ 366 @Nullable filterExtrasChangedPackageList(@onNull Computer snapshot, int callingUid, @NonNull Bundle extras)367 public static Bundle filterExtrasChangedPackageList(@NonNull Computer snapshot, int callingUid, 368 @NonNull Bundle extras) { 369 if (UserHandle.isCore(callingUid)) { 370 // see all 371 return extras; 372 } 373 final String[] pkgs = extras.getStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST); 374 if (ArrayUtils.isEmpty(pkgs)) { 375 return extras; 376 } 377 final int userId = extras.getInt( 378 Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(callingUid)); 379 final int[] uids = extras.getIntArray(Intent.EXTRA_CHANGED_UID_LIST); 380 final Pair<String[], int[]> filteredPkgs = 381 filterPackages(snapshot, pkgs, uids, callingUid, userId); 382 if (ArrayUtils.isEmpty(filteredPkgs.first)) { 383 // caller is unable to access this intent 384 return null; 385 } 386 final Bundle filteredExtras = new Bundle(extras); 387 filteredExtras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, filteredPkgs.first); 388 filteredExtras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, filteredPkgs.second); 389 return filteredExtras; 390 } 391 392 /** Returns whether the Safety Label Change notification, a privacy feature, is enabled. */ isPrivacySafetyLabelChangeNotificationsEnabled(Context context)393 public static boolean isPrivacySafetyLabelChangeNotificationsEnabled(Context context) { 394 PackageManager packageManager = context.getPackageManager(); 395 return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, 396 SAFETY_LABEL_CHANGE_NOTIFICATIONS_ENABLED, true) 397 && !packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) 398 && !packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) 399 && !packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH); 400 } 401 402 @NonNull filterPackages(@onNull Computer snapshot, @NonNull String[] pkgs, @Nullable int[] uids, int callingUid, int userId)403 private static Pair<String[], int[]> filterPackages(@NonNull Computer snapshot, 404 @NonNull String[] pkgs, @Nullable int[] uids, int callingUid, int userId) { 405 final int pkgSize = pkgs.length; 406 final int uidSize = !ArrayUtils.isEmpty(uids) ? uids.length : 0; 407 408 final ArrayList<String> pkgList = new ArrayList<>(pkgSize); 409 final IntArray uidList = uidSize > 0 ? new IntArray(uidSize) : null; 410 for (int i = 0; i < pkgSize; i++) { 411 final String packageName = pkgs[i]; 412 if (snapshot.shouldFilterApplication( 413 snapshot.getPackageStateInternal(packageName), callingUid, userId)) { 414 continue; 415 } 416 pkgList.add(packageName); 417 if (uidList != null && i < uidSize) { 418 uidList.add(uids[i]); 419 } 420 } 421 return new Pair<>( 422 pkgList.size() > 0 ? pkgList.toArray(new String[pkgList.size()]) : null, 423 uidList != null && uidList.size() > 0 ? uidList.toArray() : null); 424 } 425 } 426