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