• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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