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 22 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; 23 import static com.android.server.pm.PackageManagerService.PACKAGE_SCHEME; 24 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; 25 import static com.android.server.pm.PackageManagerService.TAG; 26 27 import android.Manifest; 28 import android.annotation.AppIdInt; 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.app.ActivityManager; 32 import android.app.ActivityManagerInternal; 33 import android.app.BroadcastOptions; 34 import android.app.IActivityManager; 35 import android.content.ComponentName; 36 import android.content.Context; 37 import android.content.IIntentReceiver; 38 import android.content.Intent; 39 import android.content.pm.PackageInstaller; 40 import android.net.Uri; 41 import android.os.Bundle; 42 import android.os.PowerExemptionManager; 43 import android.os.RemoteException; 44 import android.os.UserHandle; 45 import android.util.Log; 46 import android.util.Slog; 47 import android.util.SparseArray; 48 49 import com.android.internal.util.ArrayUtils; 50 51 import java.util.ArrayList; 52 53 /** 54 * Helper class to send broadcasts for various situations. 55 */ 56 public final class BroadcastHelper { 57 private static final boolean DEBUG_BROADCASTS = false; 58 /** 59 * Permissions required in order to receive instant application lifecycle broadcasts. 60 */ 61 private static final String[] INSTANT_APP_BROADCAST_PERMISSION = 62 new String[]{android.Manifest.permission.ACCESS_INSTANT_APPS}; 63 64 private final UserManagerInternal mUmInternal; 65 private final ActivityManagerInternal mAmInternal; 66 private final Context mContext; 67 BroadcastHelper(PackageManagerServiceInjector injector)68 BroadcastHelper(PackageManagerServiceInjector injector) { 69 mUmInternal = injector.getUserManagerInternal(); 70 mAmInternal = injector.getActivityManagerInternal(); 71 mContext = injector.getContext(); 72 } 73 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 Bundle bOptions)74 public void sendPackageBroadcast(final String action, final String pkg, final Bundle extras, 75 final int flags, final String targetPkg, final IIntentReceiver finishedReceiver, 76 final int[] userIds, int[] instantUserIds, 77 @Nullable SparseArray<int[]> broadcastAllowList, 78 @Nullable Bundle bOptions) { 79 try { 80 final IActivityManager am = ActivityManager.getService(); 81 if (am == null) return; 82 final int[] resolvedUserIds; 83 if (userIds == null) { 84 resolvedUserIds = am.getRunningUserIds(); 85 } else { 86 resolvedUserIds = userIds; 87 } 88 89 if (ArrayUtils.isEmpty(instantUserIds)) { 90 doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver, 91 resolvedUserIds, false /* isInstantApp */, broadcastAllowList, bOptions); 92 } else { 93 // send restricted broadcasts for instant apps 94 doSendBroadcast(action, pkg, extras, flags, targetPkg, finishedReceiver, 95 instantUserIds, true /* isInstantApp */, null, bOptions); 96 } 97 } catch (RemoteException ex) { 98 } 99 } 100 101 /** 102 * Sends a broadcast for the given action. 103 * <p>If {@code isInstantApp} is {@code true}, then the broadcast is protected with 104 * the {@link android.Manifest.permission#ACCESS_INSTANT_APPS} permission. This allows 105 * the system and applications allowed to see instant applications to receive package 106 * lifecycle events for instant applications. 107 */ doSendBroadcast(String action, String pkg, Bundle extras, int flags, String targetPkg, IIntentReceiver finishedReceiver, int[] userIds, boolean isInstantApp, @Nullable SparseArray<int[]> broadcastAllowList, @Nullable Bundle bOptions)108 public void doSendBroadcast(String action, String pkg, Bundle extras, 109 int flags, String targetPkg, IIntentReceiver finishedReceiver, 110 int[] userIds, boolean isInstantApp, @Nullable SparseArray<int[]> broadcastAllowList, 111 @Nullable Bundle bOptions) { 112 for (int userId : userIds) { 113 final Intent intent = new Intent(action, 114 pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null); 115 final String[] requiredPermissions = 116 isInstantApp ? INSTANT_APP_BROADCAST_PERMISSION : null; 117 if (extras != null) { 118 intent.putExtras(extras); 119 } 120 if (targetPkg != null) { 121 intent.setPackage(targetPkg); 122 } 123 // Modify the UID when posting to other users 124 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 125 if (uid >= 0 && UserHandle.getUserId(uid) != userId) { 126 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid)); 127 intent.putExtra(Intent.EXTRA_UID, uid); 128 } 129 if (broadcastAllowList != null && PLATFORM_PACKAGE_NAME.equals(targetPkg)) { 130 intent.putExtra(Intent.EXTRA_VISIBILITY_ALLOW_LIST, 131 broadcastAllowList.get(userId)); 132 } 133 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); 134 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | flags); 135 if (DEBUG_BROADCASTS) { 136 RuntimeException here = new RuntimeException("here"); 137 here.fillInStackTrace(); 138 Slog.d(TAG, "Sending to user " + userId + ": " 139 + intent.toShortString(false, true, false, false) 140 + " " + intent.getExtras(), here); 141 } 142 mAmInternal.broadcastIntent( 143 intent, finishedReceiver, requiredPermissions, 144 finishedReceiver != null, userId, 145 broadcastAllowList == null ? null : broadcastAllowList.get(userId), 146 bOptions); 147 } 148 } 149 sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, ArrayList<String> pkgList, int[] uidArr, IIntentReceiver finishedReceiver)150 public void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, 151 ArrayList<String> pkgList, int[] uidArr, IIntentReceiver finishedReceiver) { 152 sendResourcesChangedBroadcast(mediaStatus, replacing, 153 pkgList.toArray(new String[pkgList.size()]), uidArr, finishedReceiver); 154 } 155 sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, String[] pkgList, int[] uidArr, IIntentReceiver finishedReceiver)156 public void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, 157 String[] pkgList, int[] uidArr, IIntentReceiver finishedReceiver) { 158 int size = pkgList.length; 159 if (size > 0) { 160 // Send broadcasts here 161 Bundle extras = new Bundle(); 162 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList); 163 if (uidArr != null) { 164 extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr); 165 } 166 if (replacing) { 167 extras.putBoolean(Intent.EXTRA_REPLACING, replacing); 168 } 169 String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE 170 : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; 171 // TODO: not sure how to handle this one. 172 sendPackageBroadcast(action, null, extras, 0, null, finishedReceiver, 173 null, null, null, null); 174 } 175 } 176 177 /** 178 * The just-installed/enabled app is bundled on the system, so presumed to be able to run 179 * automatically without needing an explicit launch. 180 * Send it a LOCKED_BOOT_COMPLETED/BOOT_COMPLETED if it would ordinarily have gotten ones. 181 */ sendBootCompletedBroadcastToSystemApp( String packageName, boolean includeStopped, int userId)182 public void sendBootCompletedBroadcastToSystemApp( 183 String packageName, boolean includeStopped, int userId) { 184 // If user is not running, the app didn't miss any broadcast 185 if (!mUmInternal.isUserRunning(userId)) { 186 return; 187 } 188 final IActivityManager am = ActivityManager.getService(); 189 try { 190 // Deliver LOCKED_BOOT_COMPLETED first 191 Intent lockedBcIntent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED) 192 .setPackage(packageName); 193 if (includeStopped) { 194 lockedBcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); 195 } 196 final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED}; 197 final BroadcastOptions bOptions = getTemporaryAppAllowlistBroadcastOptions( 198 REASON_LOCKED_BOOT_COMPLETED); 199 am.broadcastIntentWithFeature(null, null, lockedBcIntent, null, null, 0, null, null, 200 requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, 201 bOptions.toBundle(), false, false, userId); 202 203 // Deliver BOOT_COMPLETED only if user is unlocked 204 if (mUmInternal.isUserUnlockingOrUnlocked(userId)) { 205 Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName); 206 if (includeStopped) { 207 bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); 208 } 209 am.broadcastIntentWithFeature(null, null, bcIntent, null, null, 0, null, null, 210 requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, 211 bOptions.toBundle(), false, false, userId); 212 } 213 } catch (RemoteException e) { 214 throw e.rethrowFromSystemServer(); 215 } 216 } 217 getTemporaryAppAllowlistBroadcastOptions( @owerExemptionManager.ReasonCode int reasonCode)218 public @NonNull BroadcastOptions getTemporaryAppAllowlistBroadcastOptions( 219 @PowerExemptionManager.ReasonCode int reasonCode) { 220 long duration = 10_000; 221 if (mAmInternal != null) { 222 duration = mAmInternal.getBootTimeTempAllowListDuration(); 223 } 224 final BroadcastOptions bOptions = BroadcastOptions.makeBasic(); 225 bOptions.setTemporaryAppAllowlist(duration, 226 TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, 227 reasonCode, ""); 228 return bOptions; 229 } 230 sendPackageChangedBroadcast(String packageName, boolean dontKillApp, ArrayList<String> componentNames, int packageUid, String reason, int[] userIds, int[] instantUserIds, SparseArray<int[]> broadcastAllowList)231 public void sendPackageChangedBroadcast(String packageName, boolean dontKillApp, 232 ArrayList<String> componentNames, int packageUid, String reason, 233 int[] userIds, int[] instantUserIds, SparseArray<int[]> broadcastAllowList) { 234 if (DEBUG_INSTALL) { 235 Log.v(TAG, "Sending package changed: package=" + packageName + " components=" 236 + componentNames); 237 } 238 Bundle extras = new Bundle(4); 239 extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0)); 240 String[] nameList = new String[componentNames.size()]; 241 componentNames.toArray(nameList); 242 extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList); 243 extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, dontKillApp); 244 extras.putInt(Intent.EXTRA_UID, packageUid); 245 if (reason != null) { 246 extras.putString(Intent.EXTRA_REASON, reason); 247 } 248 // If this is not reporting a change of the overall package, then only send it 249 // to registered receivers. We don't want to launch a swath of apps for every 250 // little component state change. 251 final int flags = !componentNames.contains(packageName) 252 ? Intent.FLAG_RECEIVER_REGISTERED_ONLY : 0; 253 sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, flags, null, null, 254 userIds, instantUserIds, broadcastAllowList, null); 255 } 256 sendDeviceCustomizationReadyBroadcast()257 public static void sendDeviceCustomizationReadyBroadcast() { 258 final Intent intent = new Intent(Intent.ACTION_DEVICE_CUSTOMIZATION_READY); 259 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 260 final IActivityManager am = ActivityManager.getService(); 261 final String[] requiredPermissions = { 262 Manifest.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY, 263 }; 264 try { 265 am.broadcastIntentWithFeature(null, null, intent, null, null, 0, null, null, 266 requiredPermissions, null, null, android.app.AppOpsManager.OP_NONE, null, false, 267 false, UserHandle.USER_ALL); 268 } catch (RemoteException e) { 269 throw e.rethrowFromSystemServer(); 270 } 271 } 272 sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId, int launcherUid, @Nullable ComponentName launcherComponent, @Nullable String appPredictionServicePackage)273 public void sendSessionCommitBroadcast(PackageInstaller.SessionInfo sessionInfo, int userId, 274 int launcherUid, @Nullable ComponentName launcherComponent, 275 @Nullable String appPredictionServicePackage) { 276 if (launcherComponent != null) { 277 Intent launcherIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED) 278 .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo) 279 .putExtra(Intent.EXTRA_USER, UserHandle.of(userId)) 280 .setPackage(launcherComponent.getPackageName()); 281 mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid)); 282 } 283 // TODO(b/122900055) Change/Remove this and replace with new permission role. 284 if (appPredictionServicePackage != null) { 285 Intent predictorIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED) 286 .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo) 287 .putExtra(Intent.EXTRA_USER, UserHandle.of(userId)) 288 .setPackage(appPredictionServicePackage); 289 mContext.sendBroadcastAsUser(predictorIntent, UserHandle.of(launcherUid)); 290 } 291 } 292 sendPreferredActivityChangedBroadcast(int userId)293 public void sendPreferredActivityChangedBroadcast(int userId) { 294 final IActivityManager am = ActivityManager.getService(); 295 if (am == null) { 296 return; 297 } 298 299 final Intent intent = new Intent(Intent.ACTION_PREFERRED_ACTIVITY_CHANGED); 300 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); 301 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 302 try { 303 am.broadcastIntentWithFeature(null, null, intent, null, null, 304 0, null, null, null, null, null, android.app.AppOpsManager.OP_NONE, 305 null, false, false, userId); 306 } catch (RemoteException e) { 307 } 308 } 309 sendPackageAddedForNewUsers(String packageName, @AppIdInt int appId, int[] userIds, int[] instantUserIds, int dataLoaderType, SparseArray<int[]> broadcastAllowlist)310 public void sendPackageAddedForNewUsers(String packageName, 311 @AppIdInt int appId, int[] userIds, int[] instantUserIds, 312 int dataLoaderType, SparseArray<int[]> broadcastAllowlist) { 313 Bundle extras = new Bundle(1); 314 // Set to UID of the first user, EXTRA_UID is automatically updated in sendPackageBroadcast 315 final int uid = UserHandle.getUid( 316 (ArrayUtils.isEmpty(userIds) ? instantUserIds[0] : userIds[0]), appId); 317 extras.putInt(Intent.EXTRA_UID, uid); 318 extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType); 319 320 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, 321 packageName, extras, 0, null, null, userIds, instantUserIds, 322 broadcastAllowlist, null); 323 } 324 sendFirstLaunchBroadcast(String pkgName, String installerPkg, int[] userIds, int[] instantUserIds)325 public void sendFirstLaunchBroadcast(String pkgName, String installerPkg, 326 int[] userIds, int[] instantUserIds) { 327 sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0, 328 installerPkg, null, userIds, instantUserIds, null /* broadcastAllowList */, null); 329 } 330 } 331