• 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.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