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