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.Trace.TRACE_TAG_PACKAGE_MANAGER; 20 21 import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH; 22 import static com.android.server.pm.PackageManagerService.DEBUG_INSTANT; 23 import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING; 24 import static com.android.server.pm.PackageManagerService.TAG; 25 26 import android.annotation.NonNull; 27 import android.annotation.UserIdInt; 28 import android.app.ActivityManager; 29 import android.app.ActivityManagerInternal; 30 import android.app.IUnsafeIntentStrictModeCallback; 31 import android.app.PendingIntent; 32 import android.content.ComponentName; 33 import android.content.ContentResolver; 34 import android.content.Context; 35 import android.content.IIntentSender; 36 import android.content.Intent; 37 import android.content.IntentFilter; 38 import android.content.IntentSender; 39 import android.content.pm.ActivityInfo; 40 import android.content.pm.ApplicationInfo; 41 import android.content.pm.AuxiliaryResolveInfo; 42 import android.content.pm.PackageManager; 43 import android.content.pm.PackageManagerInternal; 44 import android.content.pm.ProviderInfo; 45 import android.content.pm.ResolveInfo; 46 import android.os.Binder; 47 import android.os.Bundle; 48 import android.os.Handler; 49 import android.os.Process; 50 import android.os.RemoteException; 51 import android.os.Trace; 52 import android.os.UserHandle; 53 import android.text.TextUtils; 54 import android.util.Log; 55 import android.util.Slog; 56 57 import com.android.internal.app.ResolverActivity; 58 import com.android.internal.util.ArrayUtils; 59 import com.android.server.LocalServices; 60 import com.android.server.am.ActivityManagerService; 61 import com.android.server.am.ActivityManagerUtils; 62 import com.android.server.compat.PlatformCompat; 63 import com.android.server.pm.pkg.AndroidPackage; 64 import com.android.server.pm.pkg.PackageStateInternal; 65 import com.android.server.pm.resolution.ComponentResolverApi; 66 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal; 67 68 import java.util.ArrayList; 69 import java.util.Collections; 70 import java.util.Iterator; 71 import java.util.List; 72 import java.util.Objects; 73 import java.util.function.Supplier; 74 75 final class ResolveIntentHelper { 76 @NonNull 77 private final Context mContext; 78 @NonNull 79 private final PlatformCompat mPlatformCompat; 80 @NonNull 81 private final UserManagerService mUserManager; 82 @NonNull 83 private final PreferredActivityHelper mPreferredActivityHelper; 84 @NonNull 85 private final DomainVerificationManagerInternal mDomainVerificationManager; 86 @NonNull 87 private final UserNeedsBadgingCache mUserNeedsBadging; 88 @NonNull 89 private final Supplier<ResolveInfo> mResolveInfoSupplier; 90 @NonNull 91 private final Supplier<ActivityInfo> mInstantAppInstallerActivitySupplier; 92 @NonNull 93 private final Handler mHandler; 94 ResolveIntentHelper(@onNull Context context, @NonNull PreferredActivityHelper preferredActivityHelper, @NonNull PlatformCompat platformCompat, @NonNull UserManagerService userManager, @NonNull DomainVerificationManagerInternal domainVerificationManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache, @NonNull Supplier<ResolveInfo> resolveInfoSupplier, @NonNull Supplier<ActivityInfo> instantAppInstallerActivitySupplier, @NonNull Handler handler)95 ResolveIntentHelper(@NonNull Context context, 96 @NonNull PreferredActivityHelper preferredActivityHelper, 97 @NonNull PlatformCompat platformCompat, @NonNull UserManagerService userManager, 98 @NonNull DomainVerificationManagerInternal domainVerificationManager, 99 @NonNull UserNeedsBadgingCache userNeedsBadgingCache, 100 @NonNull Supplier<ResolveInfo> resolveInfoSupplier, 101 @NonNull Supplier<ActivityInfo> instantAppInstallerActivitySupplier, 102 @NonNull Handler handler) { 103 mContext = context; 104 mPreferredActivityHelper = preferredActivityHelper; 105 mPlatformCompat = platformCompat; 106 mUserManager = userManager; 107 mDomainVerificationManager = domainVerificationManager; 108 mUserNeedsBadging = userNeedsBadgingCache; 109 mResolveInfoSupplier = resolveInfoSupplier; 110 mInstantAppInstallerActivitySupplier = instantAppInstallerActivitySupplier; 111 mHandler = handler; 112 } 113 filterNonExportedComponents(Intent intent, int filterCallingUid, int callingPid, List<ResolveInfo> query, PlatformCompat platformCompat, String resolvedType, Computer computer, Handler handler)114 private static void filterNonExportedComponents(Intent intent, int filterCallingUid, 115 int callingPid, List<ResolveInfo> query, PlatformCompat platformCompat, 116 String resolvedType, Computer computer, Handler handler) { 117 if (query == null 118 || intent.getPackage() != null 119 || intent.getComponent() != null 120 || ActivityManager.canAccessUnexportedComponents(filterCallingUid)) { 121 return; 122 } 123 AndroidPackage caller = computer.getPackage(filterCallingUid); 124 String callerPackage = caller == null ? "Not specified" : caller.getPackageName(); 125 ActivityManagerInternal activityManagerInternal = LocalServices 126 .getService(ActivityManagerInternal.class); 127 final IUnsafeIntentStrictModeCallback callback = activityManagerInternal 128 .getRegisteredStrictModeCallback(callingPid); 129 for (int i = query.size() - 1; i >= 0; i--) { 130 if (!query.get(i).getComponentInfo().exported) { 131 boolean hasToBeExportedToMatch = platformCompat.isChangeEnabledByUid( 132 ActivityManagerService.IMPLICIT_INTENTS_ONLY_MATCH_EXPORTED_COMPONENTS, 133 filterCallingUid); 134 ActivityManagerUtils.logUnsafeIntentEvent( 135 UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH, 136 filterCallingUid, intent, resolvedType, hasToBeExportedToMatch); 137 if (callback != null) { 138 handler.post(() -> { 139 try { 140 callback.onImplicitIntentMatchedInternalComponent(intent.cloneFilter()); 141 } catch (RemoteException e) { 142 activityManagerInternal.unregisterStrictModeCallback(callingPid); 143 } 144 }); 145 } 146 if (!hasToBeExportedToMatch) { 147 return; 148 } 149 query.remove(i); 150 } 151 } 152 } 153 154 /** 155 * Normally instant apps can only be resolved when they're visible to the caller. 156 * However, if {@code resolveForStart} is {@code true}, all instant apps are visible 157 * since we need to allow the system to start any installed application. 158 */ resolveIntentInternal(Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart, int filterCallingUid)159 public ResolveInfo resolveIntentInternal(Computer computer, Intent intent, String resolvedType, 160 @PackageManager.ResolveInfoFlagsBits long flags, 161 @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, 162 boolean resolveForStart, int filterCallingUid) { 163 return resolveIntentInternal(computer, intent, resolvedType, flags, 164 privateResolveFlags, userId, resolveForStart, filterCallingUid, false, 0); 165 } 166 167 /** 168 * Normally instant apps can only be resolved when they're visible to the caller. 169 * However, if {@code resolveForStart} is {@code true}, all instant apps are visible 170 * since we need to allow the system to start any installed application. 171 * Allows picking exported components only. 172 */ resolveIntentInternal(Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, boolean resolveForStart, int filterCallingUid, boolean exportedComponentsOnly, int callingPid)173 public ResolveInfo resolveIntentInternal(Computer computer, Intent intent, String resolvedType, 174 @PackageManager.ResolveInfoFlagsBits long flags, 175 @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId, 176 boolean resolveForStart, int filterCallingUid, boolean exportedComponentsOnly, 177 int callingPid) { 178 try { 179 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent"); 180 181 if (!mUserManager.exists(userId)) return null; 182 final int callingUid = Binder.getCallingUid(); 183 flags = computer.updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart, 184 computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, 185 resolvedType, flags)); 186 computer.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, 187 false /*checkShell*/, "resolve intent"); 188 189 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities"); 190 final List<ResolveInfo> query = computer.queryIntentActivitiesInternal(intent, 191 resolvedType, flags, privateResolveFlags, filterCallingUid, userId, 192 resolveForStart, true /*allowDynamicSplits*/); 193 if (exportedComponentsOnly) { 194 filterNonExportedComponents(intent, filterCallingUid, callingPid, query, 195 mPlatformCompat, resolvedType, computer, mHandler); 196 } 197 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 198 199 final boolean queryMayBeFiltered = 200 UserHandle.getAppId(filterCallingUid) >= Process.FIRST_APPLICATION_UID 201 && !resolveForStart; 202 203 final ResolveInfo bestChoice = chooseBestActivity(computer, intent, resolvedType, flags, 204 privateResolveFlags, query, userId, queryMayBeFiltered); 205 final boolean nonBrowserOnly = 206 (privateResolveFlags & PackageManagerInternal.RESOLVE_NON_BROWSER_ONLY) != 0; 207 if (nonBrowserOnly && bestChoice != null && bestChoice.handleAllWebDataURI) { 208 return null; 209 } 210 return bestChoice; 211 } finally { 212 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 213 } 214 } 215 chooseBestActivity(Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, List<ResolveInfo> query, int userId, boolean queryMayBeFiltered)216 private ResolveInfo chooseBestActivity(Computer computer, Intent intent, String resolvedType, 217 @PackageManager.ResolveInfoFlagsBits long flags, 218 @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, 219 List<ResolveInfo> query, int userId, boolean queryMayBeFiltered) { 220 if (query != null) { 221 final int n = query.size(); 222 if (n == 1) { 223 return query.get(0); 224 } else if (n > 1) { 225 final boolean debug = ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0); 226 // If there is more than one activity with the same priority, 227 // then let the user decide between them. 228 ResolveInfo r0 = query.get(0); 229 ResolveInfo r1 = query.get(1); 230 if (DEBUG_INTENT_MATCHING || debug) { 231 Slog.v(TAG, r0.activityInfo.name + "=" + r0.priority + " vs " 232 + r1.activityInfo.name + "=" + r1.priority); 233 } 234 // If the first activity has a higher priority, or a different 235 // default, then it is always desirable to pick it. 236 if (r0.priority != r1.priority 237 || r0.preferredOrder != r1.preferredOrder 238 || r0.isDefault != r1.isDefault) { 239 return query.get(0); 240 } 241 // If we have saved a preference for a preferred activity for 242 // this Intent, use that. 243 ResolveInfo ri = mPreferredActivityHelper.findPreferredActivityNotLocked(computer, 244 intent, resolvedType, flags, query, true, false, debug, 245 userId, queryMayBeFiltered); 246 if (ri != null) { 247 return ri; 248 } 249 int browserCount = 0; 250 for (int i = 0; i < n; i++) { 251 ri = query.get(i); 252 if (ri.handleAllWebDataURI) { 253 browserCount++; 254 } 255 // If we have an ephemeral app, use it 256 if (ri.activityInfo.applicationInfo.isInstantApp()) { 257 final String packageName = ri.activityInfo.packageName; 258 final PackageStateInternal ps = 259 computer.getPackageStateInternal(packageName); 260 if (ps != null && PackageManagerServiceUtils.hasAnyDomainApproval( 261 mDomainVerificationManager, ps, intent, flags, userId)) { 262 return ri; 263 } 264 } 265 } 266 if ((privateResolveFlags 267 & PackageManagerInternal.RESOLVE_NON_RESOLVER_ONLY) != 0) { 268 return null; 269 } 270 ri = new ResolveInfo(mResolveInfoSupplier.get()); 271 // if all resolve options are browsers, mark the resolver's info as if it were 272 // also a browser. 273 ri.handleAllWebDataURI = browserCount == n; 274 ri.activityInfo = new ActivityInfo(ri.activityInfo); 275 ri.activityInfo.labelRes = ResolverActivity.getLabelRes(intent.getAction()); 276 if (ri.userHandle == null) ri.userHandle = UserHandle.of(userId); 277 // If all of the options come from the same package, show the application's 278 // label and icon instead of the generic resolver's. 279 // Some calls like Intent.resolveActivityInfo query the ResolveInfo from here 280 // and then throw away the ResolveInfo itself, meaning that the caller loses 281 // the resolvePackageName. Therefore the activityInfo.labelRes above provides 282 // a fallback for this case; we only set the target package's resources on 283 // the ResolveInfo, not the ActivityInfo. 284 final String intentPackage = intent.getPackage(); 285 if (!TextUtils.isEmpty(intentPackage) && allHavePackage(query, intentPackage)) { 286 final ApplicationInfo appi = query.get(0).activityInfo.applicationInfo; 287 ri.resolvePackageName = intentPackage; 288 if (mUserNeedsBadging.get(userId)) { 289 ri.noResourceId = true; 290 } else { 291 ri.icon = appi.icon; 292 } 293 ri.iconResourceId = appi.icon; 294 ri.labelRes = appi.labelRes; 295 } 296 ri.activityInfo.applicationInfo = new ApplicationInfo( 297 ri.activityInfo.applicationInfo); 298 if (userId != 0) { 299 ri.activityInfo.applicationInfo.uid = UserHandle.getUid(userId, 300 UserHandle.getAppId(ri.activityInfo.applicationInfo.uid)); 301 } 302 // Make sure that the resolver is displayable in car mode 303 if (ri.activityInfo.metaData == null) ri.activityInfo.metaData = new Bundle(); 304 ri.activityInfo.metaData.putBoolean(Intent.METADATA_DOCK_HOME, true); 305 return ri; 306 } 307 } 308 return null; 309 } 310 311 /** 312 * Return true if the given list is not empty and all of its contents have 313 * an activityInfo with the given package name. 314 */ allHavePackage(List<ResolveInfo> list, String packageName)315 private boolean allHavePackage(List<ResolveInfo> list, String packageName) { 316 if (ArrayUtils.isEmpty(list)) { 317 return false; 318 } 319 for (int i = 0, n = list.size(); i < n; i++) { 320 final ResolveInfo ri = list.get(i); 321 final ActivityInfo ai = ri != null ? ri.activityInfo : null; 322 if (ai == null || !packageName.equals(ai.packageName)) { 323 return false; 324 } 325 } 326 return true; 327 } 328 getLaunchIntentSenderForPackage(@onNull Computer computer, String packageName, String callingPackage, String featureId, int userId)329 public IntentSender getLaunchIntentSenderForPackage(@NonNull Computer computer, 330 String packageName, String callingPackage, String featureId, int userId) 331 throws RemoteException { 332 Objects.requireNonNull(packageName); 333 final int callingUid = Binder.getCallingUid(); 334 computer.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, 335 false /* checkShell */, "get launch intent sender for package"); 336 final int packageUid = computer.getPackageUid(callingPackage, 0 /* flags */, userId); 337 if (!UserHandle.isSameApp(callingUid, packageUid)) { 338 throw new SecurityException("getLaunchIntentSenderForPackage() from calling uid: " 339 + callingUid + " does not own package: " + callingPackage); 340 } 341 342 // Using the same implementation with the #getLaunchIntentForPackage to get the ResolveInfo. 343 // Pass the resolveForStart as true in queryIntentActivities to skip the app filtering. 344 final Intent intentToResolve = new Intent(Intent.ACTION_MAIN); 345 intentToResolve.addCategory(Intent.CATEGORY_INFO); 346 intentToResolve.setPackage(packageName); 347 final ContentResolver contentResolver = mContext.getContentResolver(); 348 String resolvedType = intentToResolve.resolveTypeIfNeeded(contentResolver); 349 List<ResolveInfo> ris = computer.queryIntentActivitiesInternal(intentToResolve, resolvedType, 350 0 /* flags */, 0 /* privateResolveFlags */, callingUid, userId, 351 true /* resolveForStart */, false /* allowDynamicSplits */); 352 if (ris == null || ris.size() <= 0) { 353 intentToResolve.removeCategory(Intent.CATEGORY_INFO); 354 intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER); 355 intentToResolve.setPackage(packageName); 356 resolvedType = intentToResolve.resolveTypeIfNeeded(contentResolver); 357 ris = computer.queryIntentActivitiesInternal(intentToResolve, resolvedType, 358 0 /* flags */, 0 /* privateResolveFlags */, callingUid, userId, 359 true /* resolveForStart */, false /* allowDynamicSplits */); 360 } 361 362 final Intent intent = new Intent(intentToResolve); 363 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 364 // For the case of empty result, no component name is assigned into the intent. A 365 // non-launchable IntentSender which contains the failed intent is created. The 366 // SendIntentException is thrown if the IntentSender#sendIntent is invoked. 367 if (ris != null && !ris.isEmpty()) { 368 // am#isIntentSenderTargetedToPackage returns false if both package name and component 369 // name are set in the intent. Clear the package name to have the api return true and 370 // prevent the package existence info from side channel leaks by the api. 371 intent.setPackage(null); 372 intent.setClassName(ris.get(0).activityInfo.packageName, 373 ris.get(0).activityInfo.name); 374 } 375 final IIntentSender target = ActivityManager.getService().getIntentSenderWithFeature( 376 ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, 377 featureId, null /* token */, null /* resultWho */, 378 1 /* requestCode */, new Intent[]{intent}, 379 resolvedType != null ? new String[]{resolvedType} : null, 380 PendingIntent.FLAG_IMMUTABLE, null /* bOptions */, userId); 381 return new IntentSender(target); 382 } 383 384 /** 385 * Retrieve all receivers that can handle a broadcast of the given intent. 386 * @param queryingUid the results will be filtered in the context of this UID instead. 387 */ 388 @NonNull queryIntentReceiversInternal(Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, int queryingUid)389 public List<ResolveInfo> queryIntentReceiversInternal(Computer computer, Intent intent, 390 String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, 391 int queryingUid) { 392 return queryIntentReceiversInternal(computer, intent, resolvedType, flags, userId, 393 queryingUid, false); 394 } 395 396 /** 397 * @see PackageManagerInternal#queryIntentReceivers(Intent, String, long, int, int, boolean) 398 */ 399 @NonNull queryIntentReceiversInternal(Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, int filterCallingUid, boolean forSend)400 public List<ResolveInfo> queryIntentReceiversInternal(Computer computer, Intent intent, 401 String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, 402 int filterCallingUid, boolean forSend) { 403 if (!mUserManager.exists(userId)) return Collections.emptyList(); 404 // The identity used to filter the receiver components 405 final int queryingUid = forSend ? Process.SYSTEM_UID : filterCallingUid; 406 computer.enforceCrossUserPermission(queryingUid, userId, 407 false /*requireFullPermission*/, false /*checkShell*/, "query intent receivers"); 408 final String instantAppPkgName = computer.getInstantAppPackageName(queryingUid); 409 flags = computer.updateFlagsForResolve(flags, userId, queryingUid, 410 false /*includeInstantApps*/, 411 computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, 412 resolvedType, flags)); 413 Intent originalIntent = null; 414 ComponentName comp = intent.getComponent(); 415 if (comp == null) { 416 if (intent.getSelector() != null) { 417 originalIntent = intent; 418 intent = intent.getSelector(); 419 comp = intent.getComponent(); 420 } 421 } 422 final ComponentResolverApi componentResolver = computer.getComponentResolver(); 423 List<ResolveInfo> list = Collections.emptyList(); 424 if (comp != null) { 425 final ActivityInfo ai = computer.getReceiverInfo(comp, flags, userId); 426 if (ai != null) { 427 // When specifying an explicit component, we prevent the activity from being 428 // used when either 1) the calling package is normal and the activity is within 429 // an instant application or 2) the calling package is ephemeral and the 430 // activity is not visible to instant applications. 431 final boolean matchInstantApp = 432 (flags & PackageManager.MATCH_INSTANT) != 0; 433 final boolean matchVisibleToInstantAppOnly = 434 (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; 435 final boolean matchExplicitlyVisibleOnly = 436 (flags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0; 437 final boolean isCallerInstantApp = 438 instantAppPkgName != null; 439 final boolean isTargetSameInstantApp = 440 comp.getPackageName().equals(instantAppPkgName); 441 final boolean isTargetInstantApp = 442 (ai.applicationInfo.privateFlags 443 & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; 444 final boolean isTargetVisibleToInstantApp = 445 (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; 446 final boolean isTargetExplicitlyVisibleToInstantApp = isTargetVisibleToInstantApp 447 && (ai.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; 448 final boolean isTargetHiddenFromInstantApp = !isTargetVisibleToInstantApp 449 || (matchExplicitlyVisibleOnly && !isTargetExplicitlyVisibleToInstantApp); 450 final boolean blockResolution = 451 !isTargetSameInstantApp 452 && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp) 453 || (matchVisibleToInstantAppOnly && isCallerInstantApp 454 && isTargetHiddenFromInstantApp)); 455 if (!blockResolution) { 456 ResolveInfo ri = new ResolveInfo(); 457 ri.activityInfo = ai; 458 list = new ArrayList<>(1); 459 list.add(ri); 460 PackageManagerServiceUtils.applyEnforceIntentFilterMatching( 461 mPlatformCompat, componentResolver, list, true, intent, 462 resolvedType, filterCallingUid); 463 } 464 } 465 } else { 466 String pkgName = intent.getPackage(); 467 if (pkgName == null) { 468 final List<ResolveInfo> result = componentResolver 469 .queryReceivers(computer, intent, resolvedType, flags, userId); 470 if (result != null) { 471 list = result; 472 } 473 } 474 final AndroidPackage pkg = computer.getPackage(pkgName); 475 if (pkg != null) { 476 final List<ResolveInfo> result = componentResolver.queryReceivers(computer, 477 intent, resolvedType, flags, pkg.getReceivers(), userId); 478 if (result != null) { 479 list = result; 480 } 481 } 482 } 483 484 if (originalIntent != null) { 485 // We also have to ensure all components match the original intent 486 PackageManagerServiceUtils.applyEnforceIntentFilterMatching( 487 mPlatformCompat, componentResolver, 488 list, true, originalIntent, resolvedType, filterCallingUid); 489 } 490 491 return computer.applyPostResolutionFilter(list, instantAppPkgName, false, queryingUid, 492 false, userId, intent); 493 } 494 495 resolveServiceInternal(@onNull Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid)496 public ResolveInfo resolveServiceInternal(@NonNull Computer computer, Intent intent, 497 String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId, 498 int callingUid) { 499 if (!mUserManager.exists(userId)) return null; 500 flags = computer.updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/, 501 false /* isImplicitImageCaptureIntentAndNotSetByDpc */); 502 List<ResolveInfo> query = computer.queryIntentServicesInternal( 503 intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/); 504 if (query != null) { 505 if (query.size() >= 1) { 506 // If there is more than one service with the same priority, 507 // just arbitrarily pick the first one. 508 return query.get(0); 509 } 510 } 511 return null; 512 } 513 queryIntentContentProvidersInternal( @onNull Computer computer, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId)514 public @NonNull List<ResolveInfo> queryIntentContentProvidersInternal( 515 @NonNull Computer computer, Intent intent, String resolvedType, 516 @PackageManager.ResolveInfoFlagsBits long flags, int userId) { 517 if (!mUserManager.exists(userId)) return Collections.emptyList(); 518 final int callingUid = Binder.getCallingUid(); 519 final String instantAppPkgName = computer.getInstantAppPackageName(callingUid); 520 flags = computer.updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/, 521 false /* isImplicitImageCaptureIntentAndNotSetByDpc */); 522 ComponentName comp = intent.getComponent(); 523 if (comp == null) { 524 if (intent.getSelector() != null) { 525 intent = intent.getSelector(); 526 comp = intent.getComponent(); 527 } 528 } 529 if (comp != null) { 530 final List<ResolveInfo> list = new ArrayList<>(1); 531 final ProviderInfo pi = computer.getProviderInfo(comp, flags, userId); 532 if (pi != null) { 533 // When specifying an explicit component, we prevent the provider from being 534 // used when either 1) the provider is in an instant application and the 535 // caller is not the same instant application or 2) the calling package is an 536 // instant application and the provider is not visible to instant applications. 537 final boolean matchInstantApp = 538 (flags & PackageManager.MATCH_INSTANT) != 0; 539 final boolean matchVisibleToInstantAppOnly = 540 (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; 541 final boolean isCallerInstantApp = 542 instantAppPkgName != null; 543 final boolean isTargetSameInstantApp = 544 comp.getPackageName().equals(instantAppPkgName); 545 final boolean isTargetInstantApp = 546 (pi.applicationInfo.privateFlags 547 & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; 548 final boolean isTargetHiddenFromInstantApp = 549 (pi.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0; 550 final boolean blockResolution = 551 !isTargetSameInstantApp 552 && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp) 553 || (matchVisibleToInstantAppOnly && isCallerInstantApp 554 && isTargetHiddenFromInstantApp)); 555 final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp 556 && computer.shouldFilterApplication( 557 computer.getPackageStateInternal(pi.applicationInfo.packageName, 558 Process.SYSTEM_UID), callingUid, userId); 559 if (!blockResolution && !blockNormalResolution) { 560 final ResolveInfo ri = new ResolveInfo(); 561 ri.providerInfo = pi; 562 list.add(ri); 563 } 564 } 565 return list; 566 } 567 568 final ComponentResolverApi componentResolver = computer.getComponentResolver(); 569 String pkgName = intent.getPackage(); 570 if (pkgName == null) { 571 final List<ResolveInfo> resolveInfos = componentResolver.queryProviders(computer, 572 intent, resolvedType, flags, userId); 573 if (resolveInfos == null) { 574 return Collections.emptyList(); 575 } 576 return applyPostContentProviderResolutionFilter(computer, resolveInfos, 577 instantAppPkgName, userId, callingUid); 578 } 579 final AndroidPackage pkg = computer.getPackage(pkgName); 580 if (pkg != null) { 581 final List<ResolveInfo> resolveInfos = componentResolver.queryProviders(computer, 582 intent, resolvedType, flags, pkg.getProviders(), userId); 583 if (resolveInfos == null) { 584 return Collections.emptyList(); 585 } 586 return applyPostContentProviderResolutionFilter(computer, resolveInfos, 587 instantAppPkgName, userId, callingUid); 588 } 589 return Collections.emptyList(); 590 } 591 applyPostContentProviderResolutionFilter(@onNull Computer computer, List<ResolveInfo> resolveInfos, String instantAppPkgName, @UserIdInt int userId, int callingUid)592 private List<ResolveInfo> applyPostContentProviderResolutionFilter(@NonNull Computer computer, 593 List<ResolveInfo> resolveInfos, String instantAppPkgName, 594 @UserIdInt int userId, int callingUid) { 595 for (int i = resolveInfos.size() - 1; i >= 0; i--) { 596 final ResolveInfo info = resolveInfos.get(i); 597 598 if (instantAppPkgName == null) { 599 PackageStateInternal resolvedSetting = computer.getPackageStateInternal( 600 info.providerInfo.packageName, 0); 601 if (!computer.shouldFilterApplication(resolvedSetting, callingUid, userId)) { 602 continue; 603 } 604 } 605 606 final boolean isEphemeralApp = info.providerInfo.applicationInfo.isInstantApp(); 607 // allow providers that are defined in the provided package 608 if (isEphemeralApp && instantAppPkgName.equals(info.providerInfo.packageName)) { 609 if (info.providerInfo.splitName != null 610 && !ArrayUtils.contains(info.providerInfo.applicationInfo.splitNames, 611 info.providerInfo.splitName)) { 612 if (mInstantAppInstallerActivitySupplier.get() == null) { 613 if (DEBUG_INSTANT) { 614 Slog.v(TAG, "No installer - not adding it to the ResolveInfo list"); 615 } 616 resolveInfos.remove(i); 617 continue; 618 } 619 // requested provider is defined in a split that hasn't been installed yet. 620 // add the installer to the resolve list 621 if (DEBUG_INSTANT) { 622 Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list"); 623 } 624 final ResolveInfo installerInfo = new ResolveInfo( 625 computer.getInstantAppInstallerInfo()); 626 installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo( 627 null /*failureActivity*/, 628 info.providerInfo.packageName, 629 info.providerInfo.applicationInfo.longVersionCode, 630 info.providerInfo.splitName); 631 // add a non-generic filter 632 installerInfo.filter = new IntentFilter(); 633 // load resources from the correct package 634 installerInfo.resolvePackageName = info.getComponentInfo().packageName; 635 resolveInfos.set(i, installerInfo); 636 } 637 continue; 638 } 639 // allow providers that have been explicitly exposed to instant applications 640 if (!isEphemeralApp && ( 641 (info.providerInfo.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0)) { 642 continue; 643 } 644 resolveInfos.remove(i); 645 } 646 return resolveInfos; 647 } 648 queryIntentActivityOptionsInternal(Computer computer, ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId)649 public @NonNull List<ResolveInfo> queryIntentActivityOptionsInternal(Computer computer, 650 ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent, 651 String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) { 652 if (!mUserManager.exists(userId)) return Collections.emptyList(); 653 final int callingUid = Binder.getCallingUid(); 654 flags = computer.updateFlagsForResolve(flags, userId, callingUid, 655 false /*includeInstantApps*/, 656 computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, 657 resolvedType, flags)); 658 computer.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, 659 false /*checkShell*/, "query intent activity options"); 660 final String resultsAction = intent.getAction(); 661 662 final List<ResolveInfo> results = computer.queryIntentActivitiesInternal(intent, 663 resolvedType, flags | PackageManager.GET_RESOLVED_FILTER, userId); 664 665 if (DEBUG_INTENT_MATCHING) { 666 Log.v(TAG, "Query " + intent + ": " + results); 667 } 668 669 int specificsPos = 0; 670 int N; 671 672 // todo: note that the algorithm used here is O(N^2). This 673 // isn't a problem in our current environment, but if we start running 674 // into situations where we have more than 5 or 10 matches then this 675 // should probably be changed to something smarter... 676 677 // First we go through and resolve each of the specific items 678 // that were supplied, taking care of removing any corresponding 679 // duplicate items in the generic resolve list. 680 if (specifics != null) { 681 for (int i = 0; i < specifics.length; i++) { 682 final Intent sintent = specifics[i]; 683 if (sintent == null) { 684 continue; 685 } 686 687 if (DEBUG_INTENT_MATCHING) { 688 Log.v(TAG, "Specific #" + i + ": " + sintent); 689 } 690 691 String action = sintent.getAction(); 692 if (resultsAction != null && resultsAction.equals(action)) { 693 // If this action was explicitly requested, then don't 694 // remove things that have it. 695 action = null; 696 } 697 698 ResolveInfo ri = null; 699 ActivityInfo ai = null; 700 701 ComponentName comp = sintent.getComponent(); 702 if (comp == null) { 703 ri = resolveIntentInternal(computer, sintent, 704 specificTypes != null ? specificTypes[i] : null, flags, 705 0 /*privateResolveFlags*/, userId, false, Binder.getCallingUid()); 706 if (ri == null) { 707 continue; 708 } 709 if (ri == mResolveInfoSupplier.get()) { 710 // ACK! Must do something better with this. 711 } 712 ai = ri.activityInfo; 713 comp = new ComponentName(ai.applicationInfo.packageName, 714 ai.name); 715 } else { 716 ai = computer.getActivityInfo(comp, flags, userId); 717 if (ai == null) { 718 continue; 719 } 720 } 721 722 // Look for any generic query activities that are duplicates 723 // of this specific one, and remove them from the results. 724 if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Specific #" + i + ": " + ai); 725 N = results.size(); 726 int j; 727 for (j = specificsPos; j < N; j++) { 728 ResolveInfo sri = results.get(j); 729 if ((sri.activityInfo.name.equals(comp.getClassName()) 730 && sri.activityInfo.applicationInfo.packageName.equals( 731 comp.getPackageName())) 732 || (action != null && sri.filter.matchAction(action))) { 733 results.remove(j); 734 if (DEBUG_INTENT_MATCHING) { 735 Log.v( 736 TAG, "Removing duplicate item from " + j 737 + " due to specific " + specificsPos); 738 } 739 if (ri == null) { 740 ri = sri; 741 } 742 j--; 743 N--; 744 } 745 } 746 747 // Add this specific item to its proper place. 748 if (ri == null) { 749 ri = new ResolveInfo(); 750 ri.activityInfo = ai; 751 } 752 results.add(specificsPos, ri); 753 ri.specificIndex = i; 754 specificsPos++; 755 } 756 } 757 758 // Now we go through the remaining generic results and remove any 759 // duplicate actions that are found here. 760 N = results.size(); 761 for (int i = specificsPos; i < N - 1; i++) { 762 final ResolveInfo rii = results.get(i); 763 if (rii.filter == null) { 764 continue; 765 } 766 767 // Iterate over all of the actions of this result's intent 768 // filter... typically this should be just one. 769 final Iterator<String> it = rii.filter.actionsIterator(); 770 if (it == null) { 771 continue; 772 } 773 while (it.hasNext()) { 774 final String action = it.next(); 775 if (resultsAction != null && resultsAction.equals(action)) { 776 // If this action was explicitly requested, then don't 777 // remove things that have it. 778 continue; 779 } 780 for (int j = i + 1; j < N; j++) { 781 final ResolveInfo rij = results.get(j); 782 if (rij.filter != null && rij.filter.hasAction(action)) { 783 results.remove(j); 784 if (DEBUG_INTENT_MATCHING) { 785 Log.v( 786 TAG, "Removing duplicate item from " + j 787 + " due to action " + action + " at " + i); 788 } 789 j--; 790 N--; 791 } 792 } 793 } 794 795 // If the caller didn't request filter information, drop it now 796 // so we don't have to marshall/unmarshall it. 797 if ((flags & PackageManager.GET_RESOLVED_FILTER) == 0) { 798 rii.filter = null; 799 } 800 } 801 802 // Filter out the caller activity if so requested. 803 if (caller != null) { 804 N = results.size(); 805 for (int i = 0; i < N; i++) { 806 ActivityInfo ainfo = results.get(i).activityInfo; 807 if (caller.getPackageName().equals(ainfo.applicationInfo.packageName) 808 && caller.getClassName().equals(ainfo.name)) { 809 results.remove(i); 810 break; 811 } 812 } 813 } 814 815 // If the caller didn't request filter information, 816 // drop them now so we don't have to 817 // marshall/unmarshall it. 818 if ((flags & PackageManager.GET_RESOLVED_FILTER) == 0) { 819 N = results.size(); 820 for (int i = 0; i < N; i++) { 821 results.get(i).filter = null; 822 } 823 } 824 825 if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Result: " + results); 826 return results; 827 } 828 829 } 830