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