1 /*
2  * Copyright (C) 2022 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.resolution;
18 
19 import static android.content.pm.PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER;
20 
21 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
22 import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.UserIdInt;
27 import android.content.ComponentName;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.content.pm.ActivityInfo;
31 import android.content.pm.ApplicationInfo;
32 import android.content.pm.AuxiliaryResolveInfo;
33 import android.content.pm.InstantAppResolveInfo;
34 import android.content.pm.PackageManager;
35 import android.content.pm.ProviderInfo;
36 import android.content.pm.ResolveInfo;
37 import android.content.pm.ServiceInfo;
38 import android.os.UserHandle;
39 import android.util.ArrayMap;
40 import android.util.ArraySet;
41 import android.util.DebugUtils;
42 import android.util.Log;
43 import android.util.LogPrinter;
44 import android.util.Pair;
45 import android.util.Slog;
46 
47 import com.android.internal.annotations.GuardedBy;
48 import com.android.internal.util.ArrayUtils;
49 import com.android.server.IntentResolver;
50 import com.android.server.pm.Computer;
51 import com.android.server.pm.PackageManagerException;
52 import com.android.server.pm.UserManagerService;
53 import com.android.server.pm.UserNeedsBadgingCache;
54 import com.android.server.pm.parsing.PackageInfoUtils;
55 import com.android.server.pm.pkg.AndroidPackage;
56 import com.android.server.pm.pkg.PackageStateInternal;
57 import com.android.server.pm.pkg.PackageStateUtils;
58 import com.android.server.pm.pkg.PackageUserStateInternal;
59 import com.android.server.pm.pkg.component.ComponentMutateUtils;
60 import com.android.server.pm.pkg.component.ParsedActivity;
61 import com.android.server.pm.pkg.component.ParsedComponent;
62 import com.android.server.pm.pkg.component.ParsedIntentInfo;
63 import com.android.server.pm.pkg.component.ParsedMainComponent;
64 import com.android.server.pm.pkg.component.ParsedProvider;
65 import com.android.server.pm.pkg.component.ParsedProviderImpl;
66 import com.android.server.pm.pkg.component.ParsedService;
67 import com.android.server.pm.snapshot.PackageDataSnapshot;
68 import com.android.server.utils.Snappable;
69 import com.android.server.utils.SnapshotCache;
70 
71 import java.io.PrintWriter;
72 import java.util.ArrayList;
73 import java.util.Collection;
74 import java.util.Collections;
75 import java.util.Comparator;
76 import java.util.Iterator;
77 import java.util.List;
78 import java.util.Objects;
79 import java.util.Set;
80 import java.util.function.Function;
81 
82 /** Resolves all Android component types [activities, services, providers and receivers]. */
83 public class ComponentResolver extends ComponentResolverLocked implements
84         Snappable<ComponentResolverApi> {
85     private static final boolean DEBUG = false;
86     private static final String TAG = "PackageManager";
87     private static final boolean DEBUG_FILTERS = false;
88     private static final boolean DEBUG_SHOW_INFO = false;
89 
90     // Convenience function to report that this object has changed.
onChanged()91     private void onChanged() {
92         dispatchChange(this);
93     }
94 
95     /**
96      * The set of all protected actions [i.e. those actions for which a high priority
97      * intent filter is disallowed].
98      */
99     private static final Set<String> PROTECTED_ACTIONS = new ArraySet<>();
100     static {
101         PROTECTED_ACTIONS.add(Intent.ACTION_SEND);
102         PROTECTED_ACTIONS.add(Intent.ACTION_SENDTO);
103         PROTECTED_ACTIONS.add(Intent.ACTION_SEND_MULTIPLE);
104         PROTECTED_ACTIONS.add(Intent.ACTION_VIEW);
105     }
106 
107     public static final Comparator<ResolveInfo> RESOLVE_PRIORITY_SORTER = (r1, r2) -> {
108         int v1 = r1.priority;
109         int v2 = r2.priority;
110         //System.out.println("Comparing: q1=" + q1 + " q2=" + q2);
111         if (v1 != v2) {
112             return (v1 > v2) ? -1 : 1;
113         }
114         v1 = r1.preferredOrder;
115         v2 = r2.preferredOrder;
116         if (v1 != v2) {
117             return (v1 > v2) ? -1 : 1;
118         }
119         if (r1.isDefault != r2.isDefault) {
120             return r1.isDefault ? -1 : 1;
121         }
122         v1 = r1.match;
123         v2 = r2.match;
124         //System.out.println("Comparing: m1=" + m1 + " m2=" + m2);
125         if (v1 != v2) {
126             return (v1 > v2) ? -1 : 1;
127         }
128         if (r1.system != r2.system) {
129             return r1.system ? -1 : 1;
130         }
131         if (r1.activityInfo != null) {
132             return r1.activityInfo.packageName.compareTo(r2.activityInfo.packageName);
133         }
134         if (r1.serviceInfo != null) {
135             return r1.serviceInfo.packageName.compareTo(r2.serviceInfo.packageName);
136         }
137         if (r1.providerInfo != null) {
138             return r1.providerInfo.packageName.compareTo(r2.providerInfo.packageName);
139         }
140         return 0;
141     };
142 
143     /** Whether or not processing protected filters should be deferred. */
144     boolean mDeferProtectedFilters = true;
145 
146     /**
147      * Tracks high priority intent filters for protected actions. During boot, certain
148      * filter actions are protected and should never be allowed to have a high priority
149      * intent filter for them. However, there is one, and only one exception -- the
150      * setup wizard. It must be able to define a high priority intent filter for these
151      * actions to ensure there are no escapes from the wizard. We need to delay processing
152      * of these during boot as we need to inspect at all of the intent filters on the
153      * /system partition in order to know which component is the setup wizard. This can
154      * only ever be non-empty if {@link #mDeferProtectedFilters} is {@code true}.
155      *
156      * This is a pair of component package name to actual filter, because we don't store the
157      * name inside the filter. It's technically independent of the component it's contained in.
158      */
159     List<Pair<ParsedMainComponent, ParsedIntentInfo>> mProtectedFilters;
160 
ComponentResolver(@onNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)161     public ComponentResolver(@NonNull UserManagerService userManager,
162             @NonNull UserNeedsBadgingCache userNeedsBadgingCache) {
163         super(userManager);
164         mActivities = new ActivityIntentResolver(userManager, userNeedsBadgingCache);
165         mProviders = new ProviderIntentResolver(userManager);
166         mReceivers = new ReceiverIntentResolver(userManager, userNeedsBadgingCache);
167         mServices = new ServiceIntentResolver(userManager);
168         mProvidersByAuthority = new ArrayMap<>();
169         mDeferProtectedFilters = true;
170 
171         mSnapshot = new SnapshotCache<>(this, this) {
172                 @Override
173                 public ComponentResolverApi createSnapshot() {
174                     synchronized (mLock) {
175                         return new ComponentResolverSnapshot(ComponentResolver.this,
176                                 userNeedsBadgingCache);
177                     }
178                 }};
179     }
180 
181     final SnapshotCache<ComponentResolverApi> mSnapshot;
182 
183     /**
184      * Create a snapshot.
185      */
snapshot()186     public ComponentResolverApi snapshot() {
187         return mSnapshot.snapshot();
188     }
189 
190     /** Add all components defined in the given package to the internal structures. */
addAllComponents(AndroidPackage pkg, boolean chatty, @Nullable String setupWizardPackage, @NonNull Computer computer)191     public void addAllComponents(AndroidPackage pkg, boolean chatty,
192             @Nullable String setupWizardPackage, @NonNull Computer computer) {
193         final ArrayList<Pair<ParsedActivity, ParsedIntentInfo>> newIntents = new ArrayList<>();
194         synchronized (mLock) {
195             addActivitiesLocked(computer, pkg, newIntents, chatty);
196             addReceiversLocked(computer, pkg, chatty);
197             addProvidersLocked(computer, pkg, chatty);
198             addServicesLocked(computer, pkg, chatty);
199             onChanged();
200         }
201 
202         for (int i = newIntents.size() - 1; i >= 0; --i) {
203             final Pair<ParsedActivity, ParsedIntentInfo> pair = newIntents.get(i);
204             final PackageStateInternal disabledPkgSetting = computer
205                     .getDisabledSystemPackage(pair.first.getPackageName());
206             final AndroidPackage disabledPkg =
207                     disabledPkgSetting == null ? null : disabledPkgSetting.getPkg();
208             final List<ParsedActivity> systemActivities =
209                     disabledPkg != null ? disabledPkg.getActivities() : null;
210             adjustPriority(computer, systemActivities, pair.first, pair.second, setupWizardPackage);
211             onChanged();
212         }
213     }
214 
215     /** Removes all components defined in the given package from the internal structures. */
removeAllComponents(AndroidPackage pkg, boolean chatty)216     public void removeAllComponents(AndroidPackage pkg, boolean chatty) {
217         synchronized (mLock) {
218             removeAllComponentsLocked(pkg, chatty);
219             onChanged();
220         }
221     }
222 
223     /**
224      * Reprocess any protected filters that have been deferred. At this point, we've scanned
225      * all of the filters defined on the /system partition and know the special components.
226      */
fixProtectedFilterPriorities(@ullable String setupWizardPackage)227     public void fixProtectedFilterPriorities(@Nullable String setupWizardPackage) {
228         synchronized (mLock) {
229             if (!mDeferProtectedFilters) {
230                 return;
231             }
232             mDeferProtectedFilters = false;
233 
234             if (mProtectedFilters == null || mProtectedFilters.size() == 0) {
235                 return;
236             }
237             final List<Pair<ParsedMainComponent, ParsedIntentInfo>> protectedFilters =
238                     mProtectedFilters;
239             mProtectedFilters = null;
240 
241             if (DEBUG_FILTERS && setupWizardPackage == null) {
242                 Slog.i(TAG, "No setup wizard;"
243                         + " All protected intents capped to priority 0");
244             }
245             for (int i = protectedFilters.size() - 1; i >= 0; --i) {
246                 final Pair<ParsedMainComponent, ParsedIntentInfo> pair = protectedFilters.get(i);
247                 ParsedMainComponent component = pair.first;
248                 ParsedIntentInfo intentInfo = pair.second;
249                 IntentFilter filter = intentInfo.getIntentFilter();
250                 String packageName = component.getPackageName();
251                 String className = component.getClassName();
252                 if (packageName.equals(setupWizardPackage)) {
253                     if (DEBUG_FILTERS) {
254                         Slog.i(TAG, "Found setup wizard;"
255                                 + " allow priority " + filter.getPriority() + ";"
256                                 + " package: " + packageName
257                                 + " activity: " + className
258                                 + " priority: " + filter.getPriority());
259                     }
260                     // skip setup wizard; allow it to keep the high priority filter
261                     continue;
262                 }
263                 if (DEBUG_FILTERS) {
264                     Slog.i(TAG, "Protected action; cap priority to 0;"
265                             + " package: " + packageName
266                             + " activity: " + className
267                             + " origPrio: " + filter.getPriority());
268                 }
269                 filter.setPriority(0);
270             }
271             onChanged();
272         }
273     }
274 
275     @GuardedBy("mLock")
addActivitiesLocked(@onNull Computer computer, AndroidPackage pkg, List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty)276     private void addActivitiesLocked(@NonNull Computer computer, AndroidPackage pkg,
277             List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty) {
278         final int activitiesSize = ArrayUtils.size(pkg.getActivities());
279         StringBuilder r = null;
280         for (int i = 0; i < activitiesSize; i++) {
281             ParsedActivity a = pkg.getActivities().get(i);
282             mActivities.addActivity(computer, a, "activity", newIntents);
283             if (DEBUG_PACKAGE_SCANNING && chatty) {
284                 if (r == null) {
285                     r = new StringBuilder(256);
286                 } else {
287                     r.append(' ');
288                 }
289                 r.append(a.getName());
290             }
291         }
292         if (DEBUG_PACKAGE_SCANNING && chatty) {
293             Log.d(TAG, "  Activities: " + (r == null ? "<NONE>" : r));
294         }
295     }
296 
297     @GuardedBy("mLock")
addProvidersLocked(@onNull Computer computer, AndroidPackage pkg, boolean chatty)298     private void addProvidersLocked(@NonNull Computer computer, AndroidPackage pkg, boolean chatty) {
299         final int providersSize = ArrayUtils.size(pkg.getProviders());
300         StringBuilder r = null;
301         for (int i = 0; i < providersSize; i++) {
302             ParsedProvider p = pkg.getProviders().get(i);
303             mProviders.addProvider(computer, p);
304             if (p.getAuthority() != null) {
305                 String[] names = p.getAuthority().split(";");
306 
307                 // TODO(b/135203078): Remove this mutation
308                 ComponentMutateUtils.setAuthority(p, null);
309                 for (int j = 0; j < names.length; j++) {
310                     if (j == 1 && p.isSyncable()) {
311                         // We only want the first authority for a provider to possibly be
312                         // syncable, so if we already added this provider using a different
313                         // authority clear the syncable flag. We copy the provider before
314                         // changing it because the mProviders object contains a reference
315                         // to a provider that we don't want to change.
316                         // Only do this for the second authority since the resulting provider
317                         // object can be the same for all future authorities for this provider.
318                         p = new ParsedProviderImpl(p);
319                         ComponentMutateUtils.setSyncable(p, false);
320                     }
321                     if (!mProvidersByAuthority.containsKey(names[j])) {
322                         mProvidersByAuthority.put(names[j], p);
323                         if (p.getAuthority() == null) {
324                             ComponentMutateUtils.setAuthority(p, names[j]);
325                         } else {
326                             ComponentMutateUtils.setAuthority(p, p.getAuthority() + ";" + names[j]);
327                         }
328                         if (DEBUG_PACKAGE_SCANNING && chatty) {
329                             Log.d(TAG, "Registered content provider: " + names[j]
330                                     + ", className = " + p.getName()
331                                     + ", isSyncable = " + p.isSyncable());
332                         }
333                     } else {
334                         final ParsedProvider other =
335                                 mProvidersByAuthority.get(names[j]);
336                         final ComponentName component =
337                                 (other != null && other.getComponentName() != null)
338                                         ? other.getComponentName() : null;
339                         final String packageName =
340                                 component != null ? component.getPackageName() : "?";
341                         Slog.w(TAG, "Skipping provider name " + names[j]
342                                 + " (in package " + pkg.getPackageName() + ")"
343                                 + ": name already used by " + packageName);
344                     }
345                 }
346             }
347             if (DEBUG_PACKAGE_SCANNING && chatty) {
348                 if (r == null) {
349                     r = new StringBuilder(256);
350                 } else {
351                     r.append(' ');
352                 }
353                 r.append(p.getName());
354             }
355         }
356         if (DEBUG_PACKAGE_SCANNING && chatty) {
357             Log.d(TAG, "  Providers: " + (r == null ? "<NONE>" : r));
358         }
359     }
360 
361     @GuardedBy("mLock")
addReceiversLocked(@onNull Computer computer, AndroidPackage pkg, boolean chatty)362     private void addReceiversLocked(@NonNull Computer computer, AndroidPackage pkg, boolean chatty) {
363         final int receiversSize = ArrayUtils.size(pkg.getReceivers());
364         StringBuilder r = null;
365         for (int i = 0; i < receiversSize; i++) {
366             ParsedActivity a = pkg.getReceivers().get(i);
367             mReceivers.addActivity(computer, a, "receiver", null);
368             if (DEBUG_PACKAGE_SCANNING && chatty) {
369                 if (r == null) {
370                     r = new StringBuilder(256);
371                 } else {
372                     r.append(' ');
373                 }
374                 r.append(a.getName());
375             }
376         }
377         if (DEBUG_PACKAGE_SCANNING && chatty) {
378             Log.d(TAG, "  Receivers: " + (r == null ? "<NONE>" : r));
379         }
380     }
381 
382     @GuardedBy("mLock")
addServicesLocked(@onNull Computer computer, AndroidPackage pkg, boolean chatty)383     private void addServicesLocked(@NonNull Computer computer, AndroidPackage pkg, boolean chatty) {
384         final int servicesSize = ArrayUtils.size(pkg.getServices());
385         StringBuilder r = null;
386         for (int i = 0; i < servicesSize; i++) {
387             ParsedService s = pkg.getServices().get(i);
388             mServices.addService(computer, s);
389             if (DEBUG_PACKAGE_SCANNING && chatty) {
390                 if (r == null) {
391                     r = new StringBuilder(256);
392                 } else {
393                     r.append(' ');
394                 }
395                 r.append(s.getName());
396             }
397         }
398         if (DEBUG_PACKAGE_SCANNING && chatty) {
399             Log.d(TAG, "  Services: " + (r == null ? "<NONE>" : r));
400         }
401     }
402 
403     /**
404      * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE
405      * MODIFIED. Do not pass in a list that should not be changed.
406      */
getIntentListSubset(List<ParsedIntentInfo> intentList, Function<IntentFilter, Iterator<T>> generator, Iterator<T> searchIterator)407     private static <T> void getIntentListSubset(List<ParsedIntentInfo> intentList,
408             Function<IntentFilter, Iterator<T>> generator, Iterator<T> searchIterator) {
409         // loop through the set of actions; every one must be found in the intent filter
410         while (searchIterator.hasNext()) {
411             // we must have at least one filter in the list to consider a match
412             if (intentList.size() == 0) {
413                 break;
414             }
415 
416             final T searchAction = searchIterator.next();
417 
418             // loop through the set of intent filters
419             final Iterator<ParsedIntentInfo> intentIter = intentList.iterator();
420             while (intentIter.hasNext()) {
421                 final ParsedIntentInfo intentInfo = intentIter.next();
422                 boolean selectionFound = false;
423 
424                 // loop through the intent filter's selection criteria; at least one
425                 // of them must match the searched criteria
426                 final Iterator<T> intentSelectionIter =
427                         generator.apply(intentInfo.getIntentFilter());
428                 while (intentSelectionIter != null && intentSelectionIter.hasNext()) {
429                     final T intentSelection = intentSelectionIter.next();
430                     if (intentSelection != null && intentSelection.equals(searchAction)) {
431                         selectionFound = true;
432                         break;
433                     }
434                 }
435 
436                 // the selection criteria wasn't found in this filter's set; this filter
437                 // is not a potential match
438                 if (!selectionFound) {
439                     intentIter.remove();
440                 }
441             }
442         }
443     }
444 
isProtectedAction(IntentFilter filter)445     private static boolean isProtectedAction(IntentFilter filter) {
446         final Iterator<String> actionsIter = filter.actionsIterator();
447         while (actionsIter != null && actionsIter.hasNext()) {
448             final String filterAction = actionsIter.next();
449             if (PROTECTED_ACTIONS.contains(filterAction)) {
450                 return true;
451             }
452         }
453         return false;
454     }
455 
456     /**
457      * Finds a privileged activity that matches the specified activity names.
458      */
findMatchingActivity( List<ParsedActivity> activityList, ParsedActivity activityInfo)459     private static ParsedActivity findMatchingActivity(
460             List<ParsedActivity> activityList, ParsedActivity activityInfo) {
461         for (ParsedActivity sysActivity : activityList) {
462             if (sysActivity.getName().equals(activityInfo.getName())) {
463                 return sysActivity;
464             }
465             if (sysActivity.getName().equals(activityInfo.getTargetActivity())) {
466                 return sysActivity;
467             }
468             if (sysActivity.getTargetActivity() != null) {
469                 if (sysActivity.getTargetActivity().equals(activityInfo.getName())) {
470                     return sysActivity;
471                 }
472                 if (sysActivity.getTargetActivity().equals(activityInfo.getTargetActivity())) {
473                     return sysActivity;
474                 }
475             }
476         }
477         return null;
478     }
479 
480     /**
481      * Adjusts the priority of the given intent filter according to policy.
482      * <p>
483      * <ul>
484      * <li>The priority for non privileged applications is capped to '0'</li>
485      * <li>The priority for protected actions on privileged applications is capped to '0'</li>
486      * <li>The priority for unbundled updates to privileged applications is capped to the
487      *      priority defined on the system partition</li>
488      * </ul>
489      * <p>
490      * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
491      * allowed to obtain any priority on any action.
492      */
adjustPriority(@onNull Computer computer, List<ParsedActivity> systemActivities, ParsedActivity activity, ParsedIntentInfo intentInfo, String setupWizardPackage)493     private void adjustPriority(@NonNull Computer computer, List<ParsedActivity> systemActivities,
494             ParsedActivity activity, ParsedIntentInfo intentInfo, String setupWizardPackage) {
495         // nothing to do; priority is fine as-is
496         IntentFilter intentFilter = intentInfo.getIntentFilter();
497         if (intentFilter.getPriority() <= 0) {
498             return;
499         }
500 
501         String packageName = activity.getPackageName();
502         var packageState = computer.getPackageStateInternal(packageName);
503 
504         final boolean privilegedApp = packageState.isPrivileged();
505         String className = activity.getClassName();
506         if (!privilegedApp) {
507             // non-privileged applications can never define a priority >0
508             if (DEBUG_FILTERS) {
509                 Slog.i(TAG, "Non-privileged app; cap priority to 0;"
510                         + " package: " + packageName
511                         + " activity: " + className
512                         + " origPrio: " + intentFilter.getPriority());
513             }
514             intentFilter.setPriority(0);
515             return;
516         }
517 
518         if (isProtectedAction(intentFilter)) {
519             if (mDeferProtectedFilters) {
520                 // We can't deal with these just yet. No component should ever obtain a
521                 // >0 priority for a protected actions, with ONE exception -- the setup
522                 // wizard. The setup wizard, however, cannot be known until we're able to
523                 // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
524                 // until all intent filters have been processed. Chicken, meet egg.
525                 // Let the filter temporarily have a high priority and rectify the
526                 // priorities after all system packages have been scanned.
527                 if (mProtectedFilters == null) {
528                     mProtectedFilters = new ArrayList<>();
529                 }
530                 mProtectedFilters.add(Pair.create(activity, intentInfo));
531                 if (DEBUG_FILTERS) {
532                     Slog.i(TAG, "Protected action; save for later;"
533                             + " package: " + packageName
534                             + " activity: " + className
535                             + " origPrio: " + intentFilter.getPriority());
536                 }
537             } else {
538                 if (DEBUG_FILTERS && setupWizardPackage == null) {
539                     Slog.i(TAG, "No setup wizard;"
540                             + " All protected intents capped to priority 0");
541                 }
542                 if (packageName.equals(setupWizardPackage)) {
543                     if (DEBUG_FILTERS) {
544                         Slog.i(TAG, "Found setup wizard;"
545                                 + " allow priority " + intentFilter.getPriority() + ";"
546                                 + " package: " + packageName
547                                 + " activity: " + className
548                                 + " priority: " + intentFilter.getPriority());
549                     }
550                     // setup wizard gets whatever it wants
551                     return;
552                 }
553                 if (DEBUG_FILTERS) {
554                     Slog.i(TAG, "Protected action; cap priority to 0;"
555                             + " package: " + packageName
556                             + " activity: " + className
557                             + " origPrio: " + intentFilter.getPriority());
558                 }
559                 intentFilter.setPriority(0);
560             }
561             return;
562         }
563 
564         if (systemActivities == null) {
565             // the system package is not disabled; we're parsing the system partition
566 
567             // privileged apps on the system image get whatever priority they request
568             return;
569         }
570 
571         // privileged app unbundled update ... try to find the same activity
572 
573         ParsedActivity foundActivity = findMatchingActivity(systemActivities, activity);
574         if (foundActivity == null) {
575             // this is a new activity; it cannot obtain >0 priority
576             if (DEBUG_FILTERS) {
577                 Slog.i(TAG, "New activity; cap priority to 0;"
578                         + " package: " + packageName
579                         + " activity: " + className
580                         + " origPrio: " + intentFilter.getPriority());
581             }
582             intentFilter.setPriority(0);
583             return;
584         }
585 
586         // found activity, now check for filter equivalence
587 
588         // a shallow copy is enough; we modify the list, not its contents
589         final List<ParsedIntentInfo> intentListCopy =
590                 new ArrayList<>(foundActivity.getIntents());
591 
592         // find matching action subsets
593         final Iterator<String> actionsIterator = intentFilter.actionsIterator();
594         if (actionsIterator != null) {
595             getIntentListSubset(intentListCopy, IntentFilter::actionsIterator, actionsIterator);
596             if (intentListCopy.size() == 0) {
597                 // no more intents to match; we're not equivalent
598                 if (DEBUG_FILTERS) {
599                     Slog.i(TAG, "Mismatched action; cap priority to 0;"
600                             + " package: " + packageName
601                             + " activity: " + className
602                             + " origPrio: " + intentFilter.getPriority());
603                 }
604                 intentFilter.setPriority(0);
605                 return;
606             }
607         }
608 
609         // find matching category subsets
610         final Iterator<String> categoriesIterator = intentFilter.categoriesIterator();
611         if (categoriesIterator != null) {
612             getIntentListSubset(intentListCopy, IntentFilter::categoriesIterator,
613                     categoriesIterator);
614             if (intentListCopy.size() == 0) {
615                 // no more intents to match; we're not equivalent
616                 if (DEBUG_FILTERS) {
617                     Slog.i(TAG, "Mismatched category; cap priority to 0;"
618                             + " package: " + packageName
619                             + " activity: " + className
620                             + " origPrio: " + intentFilter.getPriority());
621                 }
622                 intentFilter.setPriority(0);
623                 return;
624             }
625         }
626 
627         // find matching schemes subsets
628         final Iterator<String> schemesIterator = intentFilter.schemesIterator();
629         if (schemesIterator != null) {
630             getIntentListSubset(intentListCopy, IntentFilter::schemesIterator, schemesIterator);
631             if (intentListCopy.size() == 0) {
632                 // no more intents to match; we're not equivalent
633                 if (DEBUG_FILTERS) {
634                     Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
635                             + " package: " + packageName
636                             + " activity: " + className
637                             + " origPrio: " + intentFilter.getPriority());
638                 }
639                 intentFilter.setPriority(0);
640                 return;
641             }
642         }
643 
644         // find matching authorities subsets
645         final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator =
646                 intentFilter.authoritiesIterator();
647         if (authoritiesIterator != null) {
648             getIntentListSubset(intentListCopy, IntentFilter::authoritiesIterator,
649                     authoritiesIterator);
650             if (intentListCopy.size() == 0) {
651                 // no more intents to match; we're not equivalent
652                 if (DEBUG_FILTERS) {
653                     Slog.i(TAG, "Mismatched authority; cap priority to 0;"
654                             + " package: " + packageName
655                             + " activity: " + className
656                             + " origPrio: " + intentFilter.getPriority());
657                 }
658                 intentFilter.setPriority(0);
659                 return;
660             }
661         }
662 
663         // we found matching filter(s); app gets the max priority of all intents
664         int cappedPriority = 0;
665         for (int i = intentListCopy.size() - 1; i >= 0; --i) {
666             cappedPriority = Math.max(cappedPriority,
667                     intentListCopy.get(i).getIntentFilter().getPriority());
668         }
669         if (intentFilter.getPriority() > cappedPriority) {
670             if (DEBUG_FILTERS) {
671                 Slog.i(TAG, "Found matching filter(s);"
672                         + " cap priority to " + cappedPriority + ";"
673                         + " package: " + packageName
674                         + " activity: " + className
675                         + " origPrio: " + intentFilter.getPriority());
676             }
677             intentFilter.setPriority(cappedPriority);
678             return;
679         }
680         // all this for nothing; the requested priority was <= what was on the system
681     }
682 
683     @GuardedBy("mLock")
removeAllComponentsLocked(AndroidPackage pkg, boolean chatty)684     private void removeAllComponentsLocked(AndroidPackage pkg, boolean chatty) {
685         int componentSize;
686         StringBuilder r;
687         int i;
688 
689         componentSize = ArrayUtils.size(pkg.getActivities());
690         r = null;
691         for (i = 0; i < componentSize; i++) {
692             ParsedActivity a = pkg.getActivities().get(i);
693             mActivities.removeActivity(a, "activity");
694             if (DEBUG_REMOVE && chatty) {
695                 if (r == null) {
696                     r = new StringBuilder(256);
697                 } else {
698                     r.append(' ');
699                 }
700                 r.append(a.getName());
701             }
702         }
703         if (DEBUG_REMOVE && chatty) {
704             Log.d(TAG, "  Activities: " + (r == null ? "<NONE>" : r));
705         }
706 
707         componentSize = ArrayUtils.size(pkg.getProviders());
708         r = null;
709         for (i = 0; i < componentSize; i++) {
710             ParsedProvider p = pkg.getProviders().get(i);
711             mProviders.removeProvider(p);
712             if (p.getAuthority() == null) {
713                 // Another content provider with this authority existed when this app was
714                 // installed, so this authority is null. Ignore it as we don't have to
715                 // unregister the provider.
716                 continue;
717             }
718             String[] names = p.getAuthority().split(";");
719             for (int j = 0; j < names.length; j++) {
720                 if (mProvidersByAuthority.get(names[j]) == p) {
721                     mProvidersByAuthority.remove(names[j]);
722                     if (DEBUG_REMOVE && chatty) {
723                         Log.d(TAG, "Unregistered content provider: " + names[j]
724                                 + ", className = " + p.getName() + ", isSyncable = "
725                                 + p.isSyncable());
726                     }
727                 }
728             }
729             if (DEBUG_REMOVE && chatty) {
730                 if (r == null) {
731                     r = new StringBuilder(256);
732                 } else {
733                     r.append(' ');
734                 }
735                 r.append(p.getName());
736             }
737         }
738         if (DEBUG_REMOVE && chatty) {
739             Log.d(TAG, "  Providers: " + (r == null ? "<NONE>" : r));
740         }
741 
742         componentSize = ArrayUtils.size(pkg.getReceivers());
743         r = null;
744         for (i = 0; i < componentSize; i++) {
745             ParsedActivity a = pkg.getReceivers().get(i);
746             mReceivers.removeActivity(a, "receiver");
747             if (DEBUG_REMOVE && chatty) {
748                 if (r == null) {
749                     r = new StringBuilder(256);
750                 } else {
751                     r.append(' ');
752                 }
753                 r.append(a.getName());
754             }
755         }
756         if (DEBUG_REMOVE && chatty) {
757             Log.d(TAG, "  Receivers: " + (r == null ? "<NONE>" : r));
758         }
759 
760         componentSize = ArrayUtils.size(pkg.getServices());
761         r = null;
762         for (i = 0; i < componentSize; i++) {
763             ParsedService s = pkg.getServices().get(i);
764             mServices.removeService(s);
765             if (DEBUG_REMOVE && chatty) {
766                 if (r == null) {
767                     r = new StringBuilder(256);
768                 } else {
769                     r.append(' ');
770                 }
771                 r.append(s.getName());
772             }
773         }
774         if (DEBUG_REMOVE && chatty) {
775             Log.d(TAG, "  Services: " + (r == null ? "<NONE>" : r));
776         }
777     }
778 
779     /** Asserts none of the providers defined in the given package haven't already been defined. */
assertProvidersNotDefined(@onNull AndroidPackage pkg)780     public void assertProvidersNotDefined(@NonNull AndroidPackage pkg)
781             throws PackageManagerException {
782         synchronized (mLock) {
783             final int providersSize = ArrayUtils.size(pkg.getProviders());
784             int i;
785             for (i = 0; i < providersSize; i++) {
786                 ParsedProvider p = pkg.getProviders().get(i);
787                 if (p.getAuthority() != null) {
788                     final String[] names = p.getAuthority().split(";");
789                     for (int j = 0; j < names.length; j++) {
790                         if (mProvidersByAuthority.containsKey(names[j])) {
791                             final ParsedProvider other = mProvidersByAuthority.get(names[j]);
792                             final String otherPackageName =
793                                     (other != null && other.getComponentName() != null)
794                                             ? other.getComponentName().getPackageName() : "?";
795                             // if installing over the same already-installed package,this is ok
796                             if (!otherPackageName.equals(pkg.getPackageName())) {
797                                 throw new PackageManagerException(
798                                         INSTALL_FAILED_CONFLICTING_PROVIDER,
799                                         "Can't install because provider name " + names[j]
800                                                 + " (in package " + pkg.getPackageName()
801                                                 + ") is already used by " + otherPackageName);
802                             }
803                         }
804                     }
805                 }
806             }
807         }
808     }
809 
810     private abstract static class MimeGroupsAwareIntentResolver<F extends Pair<?
811             extends ParsedComponent, ParsedIntentInfo>, R>
812             extends IntentResolver<F, R> {
813         private final ArrayMap<String, F[]> mMimeGroupToFilter = new ArrayMap<>();
814         private boolean mIsUpdatingMimeGroup = false;
815 
816         @NonNull
817         protected final UserManagerService mUserManager;
818 
819         // Default constructor
MimeGroupsAwareIntentResolver(@onNull UserManagerService userManager)820         MimeGroupsAwareIntentResolver(@NonNull UserManagerService userManager) {
821             mUserManager = userManager;
822         }
823 
824         // Copy constructor used in creating snapshots
MimeGroupsAwareIntentResolver(MimeGroupsAwareIntentResolver<F, R> orig, @NonNull UserManagerService userManager)825         MimeGroupsAwareIntentResolver(MimeGroupsAwareIntentResolver<F, R> orig,
826                 @NonNull UserManagerService userManager) {
827             mUserManager = userManager;
828             copyFrom(orig);
829             copyInto(mMimeGroupToFilter, orig.mMimeGroupToFilter);
830             mIsUpdatingMimeGroup = orig.mIsUpdatingMimeGroup;
831         }
832 
833         @Override
addFilter(@ullable PackageDataSnapshot snapshot, F f)834         public void addFilter(@Nullable PackageDataSnapshot snapshot, F f) {
835             IntentFilter intentFilter = getIntentFilter(f);
836             // We assume Computer is available for this class and all subclasses. Because this class
837             // uses subclass method override to handle logic, the Computer parameter must be in the
838             // base, leading to this odd nullability.
839             applyMimeGroups((Computer) snapshot, f);
840             super.addFilter(snapshot, f);
841 
842             if (!mIsUpdatingMimeGroup) {
843                 register_intent_filter(f, intentFilter.mimeGroupsIterator(), mMimeGroupToFilter,
844                         "      MimeGroup: ");
845             }
846         }
847 
848         @Override
removeFilterInternal(F f)849         protected void removeFilterInternal(F f) {
850             IntentFilter intentFilter = getIntentFilter(f);
851             if (!mIsUpdatingMimeGroup) {
852                 unregister_intent_filter(f, intentFilter.mimeGroupsIterator(), mMimeGroupToFilter,
853                         "      MimeGroup: ");
854             }
855 
856             super.removeFilterInternal(f);
857             intentFilter.clearDynamicDataTypes();
858         }
859 
860         /**
861          * Updates MIME group by applying changes to all IntentFilters
862          * that contain the group and repopulating m*ToFilter maps accordingly
863          *
864          * @param packageName package to which MIME group belongs
865          * @param mimeGroup MIME group to update
866          * @return true, if any intent filters were changed due to this update
867          */
updateMimeGroup(@onNull Computer computer, String packageName, String mimeGroup)868         public boolean updateMimeGroup(@NonNull Computer computer, String packageName,
869                 String mimeGroup) {
870             F[] filters = mMimeGroupToFilter.get(mimeGroup);
871             int n = filters != null ? filters.length : 0;
872 
873             mIsUpdatingMimeGroup = true;
874             boolean hasChanges = false;
875             F filter;
876             for (int i = 0; i < n && (filter = filters[i]) != null; i++) {
877                 if (isPackageForFilter(packageName, filter)) {
878                     hasChanges |= updateFilter(computer, filter);
879                 }
880             }
881             mIsUpdatingMimeGroup = false;
882             return hasChanges;
883         }
884 
updateFilter(@onNull Computer computer, F f)885         private boolean updateFilter(@NonNull Computer computer, F f) {
886             IntentFilter filter = getIntentFilter(f);
887             List<String> oldTypes = filter.dataTypes();
888             removeFilter(f);
889             addFilter(computer, f);
890             List<String> newTypes = filter.dataTypes();
891             return !equalLists(oldTypes, newTypes);
892         }
893 
equalLists(List<String> first, List<String> second)894         private boolean equalLists(List<String> first, List<String> second) {
895             if (first == null) {
896                 return second == null;
897             } else if (second == null) {
898                 return false;
899             }
900 
901             if (first.size() != second.size()) {
902                 return false;
903             }
904 
905             Collections.sort(first);
906             Collections.sort(second);
907             return first.equals(second);
908         }
909 
applyMimeGroups(@onNull Computer computer, F f)910         private void applyMimeGroups(@NonNull Computer computer, F f) {
911             IntentFilter filter = getIntentFilter(f);
912 
913             for (int i = filter.countMimeGroups() - 1; i >= 0; i--) {
914                 final PackageStateInternal packageState = computer.getPackageStateInternal(
915                         f.first.getPackageName());
916 
917                 Collection<String> mimeTypes = packageState == null
918                         ? Collections.emptyList() : packageState.getMimeGroups()
919                         .get(filter.getMimeGroup(i));
920 
921                 for (String mimeType : mimeTypes) {
922                     try {
923                         filter.addDynamicDataType(mimeType);
924                     } catch (IntentFilter.MalformedMimeTypeException e) {
925                         if (DEBUG) {
926                             Slog.w(TAG, "Malformed mime type: " + mimeType, e);
927                         }
928                     }
929                 }
930             }
931         }
932 
933         @Override
isFilterStopped(@onNull Computer computer, F filter, @UserIdInt int userId)934         protected boolean isFilterStopped(@NonNull Computer computer, F filter,
935                 @UserIdInt int userId) {
936             if (!mUserManager.exists(userId)) {
937                 return true;
938             }
939 
940             final PackageStateInternal packageState = computer.getPackageStateInternal(
941                     filter.first.getPackageName());
942             if (packageState == null || packageState.getPkg() == null) {
943                 return false;
944             }
945 
946             return packageState.getUserStateOrDefault(userId).isStopped();
947         }
948     }
949 
950     public static class ActivityIntentResolver
951             extends MimeGroupsAwareIntentResolver<Pair<ParsedActivity, ParsedIntentInfo>, ResolveInfo> {
952 
953         @NonNull
954         private UserNeedsBadgingCache mUserNeedsBadging;
955 
956         // Default constructor
ActivityIntentResolver(@onNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)957         ActivityIntentResolver(@NonNull UserManagerService userManager,
958                 @NonNull UserNeedsBadgingCache userNeedsBadgingCache) {
959             super(userManager);
960             mUserNeedsBadging = userNeedsBadgingCache;
961         }
962 
963         // Copy constructor used in creating snapshots
ActivityIntentResolver(@onNull ActivityIntentResolver orig, @NonNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)964         ActivityIntentResolver(@NonNull ActivityIntentResolver orig,
965                 @NonNull UserManagerService userManager,
966                 @NonNull UserNeedsBadgingCache userNeedsBadgingCache) {
967             super(orig, userManager);
968             mActivities.putAll(orig.mActivities);
969             mUserNeedsBadging = userNeedsBadgingCache;
970         }
971 
972         @Override
queryIntent(@onNull PackageDataSnapshot snapshot, Intent intent, String resolvedType, boolean defaultOnly, @UserIdInt int userId)973         public List<ResolveInfo> queryIntent(@NonNull PackageDataSnapshot snapshot, Intent intent,
974                 String resolvedType, boolean defaultOnly, @UserIdInt int userId) {
975             if (!mUserManager.exists(userId)) return null;
976             long flags = (defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0);
977             return super.queryIntent(snapshot, intent, resolvedType, defaultOnly, userId, flags);
978         }
979 
queryIntent(@onNull Computer computer, Intent intent, String resolvedType, long flags, int userId)980         List<ResolveInfo> queryIntent(@NonNull Computer computer, Intent intent,
981                 String resolvedType, long flags, int userId) {
982             if (!mUserManager.exists(userId)) {
983                 return null;
984             }
985             return super.queryIntent(computer, intent, resolvedType,
986                     (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId, flags);
987         }
988 
queryIntentForPackage(@onNull Computer computer, Intent intent, String resolvedType, long flags, List<ParsedActivity> packageActivities, int userId)989         List<ResolveInfo> queryIntentForPackage(@NonNull Computer computer, Intent intent,
990                 String resolvedType, long flags, List<ParsedActivity> packageActivities,
991                 int userId) {
992             if (!mUserManager.exists(userId)) {
993                 return null;
994             }
995             if (packageActivities == null) {
996                 return Collections.emptyList();
997             }
998             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
999             final int activitiesSize = packageActivities.size();
1000             ArrayList<Pair<ParsedActivity, ParsedIntentInfo>[]> listCut =
1001                     new ArrayList<>(activitiesSize);
1002 
1003             List<ParsedIntentInfo> intentFilters;
1004             for (int i = 0; i < activitiesSize; ++i) {
1005                 ParsedActivity activity = packageActivities.get(i);
1006                 intentFilters = activity.getIntents();
1007                 if (!intentFilters.isEmpty()) {
1008                     Pair<ParsedActivity, ParsedIntentInfo>[] array = newArray(intentFilters.size());
1009                     for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) {
1010                         array[arrayIndex] = Pair.create(activity, intentFilters.get(arrayIndex));
1011                     }
1012                     listCut.add(array);
1013                 }
1014             }
1015             return super.queryIntentFromList(computer, intent, resolvedType,
1016                     defaultOnly, listCut, userId, flags);
1017         }
1018 
addActivity(@onNull Computer computer, ParsedActivity a, String type, List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents)1019         protected void addActivity(@NonNull Computer computer, ParsedActivity a, String type,
1020                 List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents) {
1021             mActivities.put(a.getComponentName(), a);
1022             if (DEBUG_SHOW_INFO) {
1023                 Log.v(TAG, "  " + type + ":");
1024                 Log.v(TAG, "    Class=" + a.getName());
1025             }
1026             final int intentsSize = a.getIntents().size();
1027             for (int j = 0; j < intentsSize; j++) {
1028                 ParsedIntentInfo intent = a.getIntents().get(j);
1029                 IntentFilter intentFilter = intent.getIntentFilter();
1030                 if (newIntents != null && "activity".equals(type)) {
1031                     newIntents.add(Pair.create(a, intent));
1032                 }
1033                 if (DEBUG_SHOW_INFO) {
1034                     Log.v(TAG, "    IntentFilter:");
1035                     intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
1036                 }
1037                 if (!intentFilter.debugCheck()) {
1038                     Log.w(TAG, "==> For Activity " + a.getName());
1039                 }
1040                 addFilter(computer, Pair.create(a, intent));
1041             }
1042         }
1043 
removeActivity(ParsedActivity a, String type)1044         protected void removeActivity(ParsedActivity a, String type) {
1045             mActivities.remove(a.getComponentName());
1046             if (DEBUG_SHOW_INFO) {
1047                 Log.v(TAG, "  " + type + ":");
1048                 Log.v(TAG, "    Class=" + a.getName());
1049             }
1050             final int intentsSize = a.getIntents().size();
1051             for (int j = 0; j < intentsSize; j++) {
1052                 ParsedIntentInfo intent = a.getIntents().get(j);
1053                 IntentFilter intentFilter = intent.getIntentFilter();
1054                 if (DEBUG_SHOW_INFO) {
1055                     Log.v(TAG, "    IntentFilter:");
1056                     intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
1057                 }
1058                 removeFilter(Pair.create(a, intent));
1059             }
1060         }
1061 
1062         @Override
allowFilterResult(Pair<ParsedActivity, ParsedIntentInfo> filter, List<ResolveInfo> dest)1063         protected boolean allowFilterResult(Pair<ParsedActivity, ParsedIntentInfo> filter,
1064                 List<ResolveInfo> dest) {
1065             for (int i = dest.size() - 1; i >= 0; --i) {
1066                 ActivityInfo destAi = dest.get(i).activityInfo;
1067                 if (Objects.equals(destAi.name, filter.first.getName())
1068                         && Objects.equals(destAi.packageName, filter.first.getPackageName())) {
1069                     return false;
1070                 }
1071             }
1072             return true;
1073         }
1074 
1075         @Override
newArray(int size)1076         protected Pair<ParsedActivity, ParsedIntentInfo>[] newArray(int size) {
1077             //noinspection unchecked
1078             return (Pair<ParsedActivity, ParsedIntentInfo>[]) new Pair<?, ?>[size];
1079         }
1080 
1081         @Override
isPackageForFilter(String packageName, Pair<ParsedActivity, ParsedIntentInfo> info)1082         protected boolean isPackageForFilter(String packageName,
1083                 Pair<ParsedActivity, ParsedIntentInfo> info) {
1084             return packageName.equals(info.first.getPackageName());
1085         }
1086 
log(String reason, ParsedIntentInfo info, int match, int userId)1087         private void log(String reason, ParsedIntentInfo info, int match,
1088                 int userId) {
1089             Slog.w(TAG, reason
1090                     + "; match: "
1091                     + DebugUtils.flagsToString(IntentFilter.class, "MATCH_", match)
1092                     + "; userId: " + userId
1093                     + "; intent info: " + info);
1094         }
1095 
1096         @Override
newResult(@onNull Computer computer, Pair<ParsedActivity, ParsedIntentInfo> pair, int match, int userId, long customFlags)1097         protected ResolveInfo newResult(@NonNull Computer computer,
1098                 Pair<ParsedActivity, ParsedIntentInfo> pair, int match, int userId,
1099                 long customFlags) {
1100             ParsedActivity activity = pair.first;
1101             ParsedIntentInfo info = pair.second;
1102             IntentFilter intentFilter = info.getIntentFilter();
1103 
1104             if (!mUserManager.exists(userId)) {
1105                 if (DEBUG) {
1106                     log("User doesn't exist", info, match, userId);
1107                 }
1108                 return null;
1109             }
1110 
1111             final PackageStateInternal packageState =
1112                     computer.getPackageStateInternal(activity.getPackageName());
1113             if (packageState == null || packageState.getPkg() == null
1114                     || !PackageStateUtils.isEnabledAndMatches(packageState, activity, customFlags,
1115                     userId)) {
1116                 if (DEBUG) {
1117                     log("!PackageManagerInternal.isEnabledAndMatches; flags="
1118                             + DebugUtils.flagsToString(PackageManager.class, "MATCH_", customFlags),
1119                             info, match, userId);
1120                 }
1121                 return null;
1122             }
1123             final PackageUserStateInternal userState = packageState.getUserStateOrDefault(userId);
1124             ActivityInfo ai = PackageInfoUtils.generateActivityInfo(packageState.getPkg(), activity,
1125                     customFlags, userState, userId, packageState);
1126             if (ai == null) {
1127                 if (DEBUG) {
1128                     log("Failed to create ActivityInfo based on " + activity, info, match,
1129                             userId);
1130                 }
1131                 return null;
1132             }
1133             final boolean matchExplicitlyVisibleOnly =
1134                     (customFlags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0;
1135             final boolean matchVisibleToInstantApp =
1136                     (customFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
1137             final boolean componentVisible =
1138                     matchVisibleToInstantApp
1139                     && intentFilter.isVisibleToInstantApp()
1140                     && (!matchExplicitlyVisibleOnly
1141                             || intentFilter.isExplicitlyVisibleToInstantApp());
1142             final boolean matchInstantApp = (customFlags & PackageManager.MATCH_INSTANT) != 0;
1143             // throw out filters that aren't visible to ephemeral apps
1144             if (matchVisibleToInstantApp && !(componentVisible || userState.isInstantApp())) {
1145                 if (DEBUG) {
1146                     log("Filter(s) not visible to ephemeral apps"
1147                             + "; matchVisibleToInstantApp=" + matchVisibleToInstantApp
1148                             + "; matchInstantApp=" + matchInstantApp
1149                             + "; info.isVisibleToInstantApp()="
1150                                     + intentFilter.isVisibleToInstantApp()
1151                             + "; matchExplicitlyVisibleOnly=" + matchExplicitlyVisibleOnly
1152                             + "; info.isExplicitlyVisibleToInstantApp()="
1153                                     + intentFilter.isExplicitlyVisibleToInstantApp(),
1154                             info, match, userId);
1155                 }
1156                 return null;
1157             }
1158             // throw out instant app filters if we're not explicitly requesting them
1159             if (!matchInstantApp && userState.isInstantApp()) {
1160                 if (DEBUG) {
1161                     log("Instant app filter is not explicitly requested", info, match, userId);
1162                 }
1163                 return null;
1164             }
1165             // throw out instant app filters if updates are available; will trigger
1166             // instant app resolution
1167             if (userState.isInstantApp() && packageState.isUpdateAvailable()) {
1168                 if (DEBUG) {
1169                     log("Instant app update is available", info, match, userId);
1170                 }
1171                 return null;
1172             }
1173             final ResolveInfo res =
1174                     new ResolveInfo(intentFilter.hasCategory(Intent.CATEGORY_BROWSABLE));
1175             res.activityInfo = ai;
1176             if ((customFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
1177                 res.filter = intentFilter;
1178             }
1179             res.handleAllWebDataURI = intentFilter.handleAllWebDataURI();
1180             res.priority = intentFilter.getPriority();
1181             // TODO(b/135203078): This field was unwritten and does nothing
1182 //            res.preferredOrder = pkg.getPreferredOrder();
1183             //System.out.println("Result: " + res.activityInfo.className +
1184             //                   " = " + res.priority);
1185             res.match = match;
1186             res.isDefault = info.isHasDefault();
1187             res.labelRes = info.getLabelRes();
1188             res.nonLocalizedLabel = info.getNonLocalizedLabel();
1189             if (mUserNeedsBadging.get(userId)) {
1190                 res.noResourceId = true;
1191             } else {
1192                 res.icon = info.getIcon();
1193             }
1194             res.iconResourceId = info.getIcon();
1195             res.system = res.activityInfo.applicationInfo.isSystemApp();
1196             res.isInstantAppAvailable = userState.isInstantApp();
1197             res.userHandle = UserHandle.of(userId);
1198             return res;
1199         }
1200 
1201         @Override
sortResults(List<ResolveInfo> results)1202         protected void sortResults(List<ResolveInfo> results) {
1203             results.sort(RESOLVE_PRIORITY_SORTER);
1204         }
1205 
1206         @Override
dumpFilter(PrintWriter out, String prefix, Pair<ParsedActivity, ParsedIntentInfo> pair)1207         protected void dumpFilter(PrintWriter out, String prefix,
1208                 Pair<ParsedActivity, ParsedIntentInfo> pair) {
1209             ParsedActivity activity = pair.first;
1210             ParsedIntentInfo filter = pair.second;
1211 
1212             out.print(prefix);
1213             out.print(Integer.toHexString(System.identityHashCode(activity)));
1214             out.print(' ');
1215             ComponentName.printShortString(out, activity.getPackageName(),
1216                     activity.getClassName());
1217             out.print(" filter ");
1218             out.println(Integer.toHexString(System.identityHashCode(filter)));
1219         }
1220 
1221         @Override
filterToLabel(Pair<ParsedActivity, ParsedIntentInfo> filter)1222         protected Object filterToLabel(Pair<ParsedActivity, ParsedIntentInfo> filter) {
1223             return filter;
1224         }
1225 
dumpFilterLabel(PrintWriter out, String prefix, Object label, int count)1226         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
1227             @SuppressWarnings("unchecked") Pair<ParsedActivity, ParsedIntentInfo> pair =
1228                     (Pair<ParsedActivity, ParsedIntentInfo>) label;
1229             out.print(prefix);
1230             out.print(Integer.toHexString(System.identityHashCode(pair.first)));
1231             out.print(' ');
1232             ComponentName.printShortString(out, pair.first.getPackageName(),
1233                     pair.first.getClassName());
1234             if (count > 1) {
1235                 out.print(" ("); out.print(count); out.print(" filters)");
1236             }
1237             out.println();
1238         }
1239 
1240         @Override
getIntentFilter( @onNull Pair<ParsedActivity, ParsedIntentInfo> input)1241         protected IntentFilter getIntentFilter(
1242                 @NonNull Pair<ParsedActivity, ParsedIntentInfo> input) {
1243             return input.second.getIntentFilter();
1244         }
1245 
getResolveList(AndroidPackage pkg)1246         protected List<ParsedActivity> getResolveList(AndroidPackage pkg) {
1247             return pkg.getActivities();
1248         }
1249 
1250         // Keys are String (activity class name), values are Activity.  This attribute is
1251         // protected because it is accessed directly from ComponentResolver.  That works
1252         // even if the attribute is private, but fails for subclasses of
1253         // ActivityIntentResolver.
1254         protected final ArrayMap<ComponentName, ParsedActivity> mActivities =
1255                 new ArrayMap<>();
1256     }
1257 
1258     // Both receivers and activities share a class, but point to different get methods
1259     public static final class ReceiverIntentResolver extends ActivityIntentResolver {
1260 
1261         // Default constructor
ReceiverIntentResolver(@onNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)1262         ReceiverIntentResolver(@NonNull UserManagerService userManager,
1263                 @NonNull UserNeedsBadgingCache userNeedsBadgingCache) {
1264             super(userManager, userNeedsBadgingCache);
1265         }
1266 
1267         // Copy constructor used in creating snapshots
ReceiverIntentResolver(@onNull ReceiverIntentResolver orig, @NonNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)1268         ReceiverIntentResolver(@NonNull ReceiverIntentResolver orig,
1269                 @NonNull UserManagerService userManager,
1270                 @NonNull UserNeedsBadgingCache userNeedsBadgingCache) {
1271             super(orig, userManager, userNeedsBadgingCache);
1272         }
1273 
1274         @Override
getResolveList(AndroidPackage pkg)1275         protected List<ParsedActivity> getResolveList(AndroidPackage pkg) {
1276             return pkg.getReceivers();
1277         }
1278     }
1279 
1280     public static final class ProviderIntentResolver
1281             extends MimeGroupsAwareIntentResolver<Pair<ParsedProvider, ParsedIntentInfo>, ResolveInfo> {
1282         // Default constructor
ProviderIntentResolver(@onNull UserManagerService userManager)1283         ProviderIntentResolver(@NonNull UserManagerService userManager) {
1284             super(userManager);
1285         }
1286 
1287         // Copy constructor used in creating snapshots
ProviderIntentResolver(@onNull ProviderIntentResolver orig, @NonNull UserManagerService userManager)1288         ProviderIntentResolver(@NonNull ProviderIntentResolver orig,
1289                 @NonNull UserManagerService userManager) {
1290             super(orig, userManager);
1291             mProviders.putAll(orig.mProviders);
1292         }
1293 
1294         @Override
queryIntent(@onNull PackageDataSnapshot snapshot, Intent intent, String resolvedType, boolean defaultOnly, @UserIdInt int userId)1295         public List<ResolveInfo> queryIntent(@NonNull PackageDataSnapshot snapshot, Intent intent,
1296                 String resolvedType, boolean defaultOnly, @UserIdInt int userId) {
1297             if (!mUserManager.exists(userId)) {
1298                 return null;
1299             }
1300             long flags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
1301             return super.queryIntent(snapshot, intent, resolvedType, defaultOnly, userId, flags);
1302         }
1303 
1304         @Nullable
queryIntent(@onNull Computer computer, Intent intent, String resolvedType, long flags, int userId)1305         List<ResolveInfo> queryIntent(@NonNull Computer computer, Intent intent,
1306                 String resolvedType, long flags, int userId) {
1307             if (!mUserManager.exists(userId)) {
1308                 return null;
1309             }
1310             return super.queryIntent(computer, intent, resolvedType,
1311                     (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId, flags);
1312         }
1313 
1314         @Nullable
queryIntentForPackage(@onNull Computer computer, Intent intent, String resolvedType, long flags, List<ParsedProvider> packageProviders, int userId)1315         List<ResolveInfo> queryIntentForPackage(@NonNull Computer computer, Intent intent,
1316                 String resolvedType, long flags, List<ParsedProvider> packageProviders,
1317                 int userId) {
1318             if (!mUserManager.exists(userId)) {
1319                 return null;
1320             }
1321             if (packageProviders == null) {
1322                 return Collections.emptyList();
1323             }
1324             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
1325             final int providersSize = packageProviders.size();
1326             ArrayList<Pair<ParsedProvider, ParsedIntentInfo>[]> listCut =
1327                     new ArrayList<>(providersSize);
1328 
1329             List<ParsedIntentInfo> intentFilters;
1330             for (int i = 0; i < providersSize; ++i) {
1331                 ParsedProvider provider = packageProviders.get(i);
1332                 intentFilters = provider.getIntents();
1333                 if (!intentFilters.isEmpty()) {
1334                     Pair<ParsedProvider, ParsedIntentInfo>[] array = newArray(intentFilters.size());
1335                     for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) {
1336                         array[arrayIndex] = Pair.create(provider, intentFilters.get(arrayIndex));
1337                     }
1338                     listCut.add(array);
1339                 }
1340             }
1341             return super.queryIntentFromList(computer, intent, resolvedType,
1342                     defaultOnly, listCut, userId, flags);
1343         }
1344 
addProvider(@onNull Computer computer, ParsedProvider p)1345         void addProvider(@NonNull Computer computer, ParsedProvider p) {
1346             if (mProviders.containsKey(p.getComponentName())) {
1347                 Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring");
1348                 return;
1349             }
1350 
1351             mProviders.put(p.getComponentName(), p);
1352             if (DEBUG_SHOW_INFO) {
1353                 Log.v(TAG, "  provider:");
1354                 Log.v(TAG, "    Class=" + p.getName());
1355             }
1356             final int intentsSize = p.getIntents().size();
1357             int j;
1358             for (j = 0; j < intentsSize; j++) {
1359                 ParsedIntentInfo intent = p.getIntents().get(j);
1360                 IntentFilter intentFilter = intent.getIntentFilter();
1361                 if (DEBUG_SHOW_INFO) {
1362                     Log.v(TAG, "    IntentFilter:");
1363                     intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
1364                 }
1365                 if (!intentFilter.debugCheck()) {
1366                     Log.w(TAG, "==> For Provider " + p.getName());
1367                 }
1368                 addFilter(computer, Pair.create(p, intent));
1369             }
1370         }
1371 
removeProvider(ParsedProvider p)1372         void removeProvider(ParsedProvider p) {
1373             mProviders.remove(p.getComponentName());
1374             if (DEBUG_SHOW_INFO) {
1375                 Log.v(TAG, "  provider:");
1376                 Log.v(TAG, "    Class=" + p.getName());
1377             }
1378             final int intentsSize = p.getIntents().size();
1379             int j;
1380             for (j = 0; j < intentsSize; j++) {
1381                 ParsedIntentInfo intent = p.getIntents().get(j);
1382                 IntentFilter intentFilter = intent.getIntentFilter();
1383                 if (DEBUG_SHOW_INFO) {
1384                     Log.v(TAG, "    IntentFilter:");
1385                     intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
1386                 }
1387                 removeFilter(Pair.create(p, intent));
1388             }
1389         }
1390 
1391         @Override
allowFilterResult(Pair<ParsedProvider, ParsedIntentInfo> filter, List<ResolveInfo> dest)1392         protected boolean allowFilterResult(Pair<ParsedProvider, ParsedIntentInfo> filter,
1393                 List<ResolveInfo> dest) {
1394             for (int i = dest.size() - 1; i >= 0; i--) {
1395                 ProviderInfo destPi = dest.get(i).providerInfo;
1396                 if (Objects.equals(destPi.name, filter.first.getClassName())
1397                         && Objects.equals(destPi.packageName, filter.first.getPackageName())) {
1398                     return false;
1399                 }
1400             }
1401             return true;
1402         }
1403 
1404         @Override
newArray(int size)1405         protected Pair<ParsedProvider, ParsedIntentInfo>[] newArray(int size) {
1406             //noinspection unchecked
1407             return (Pair<ParsedProvider, ParsedIntentInfo>[]) new Pair<?, ?>[size];
1408         }
1409 
1410         @Override
isPackageForFilter(String packageName, Pair<ParsedProvider, ParsedIntentInfo> info)1411         protected boolean isPackageForFilter(String packageName,
1412                 Pair<ParsedProvider, ParsedIntentInfo> info) {
1413             return packageName.equals(info.first.getPackageName());
1414         }
1415 
1416         @Override
newResult(@onNull Computer computer, Pair<ParsedProvider, ParsedIntentInfo> pair, int match, int userId, long customFlags)1417         protected ResolveInfo newResult(@NonNull Computer computer,
1418                 Pair<ParsedProvider, ParsedIntentInfo> pair, int match, int userId,
1419                 long customFlags) {
1420             if (!mUserManager.exists(userId)) {
1421                 return null;
1422             }
1423 
1424             ParsedProvider provider = pair.first;
1425             ParsedIntentInfo intentInfo = pair.second;
1426             IntentFilter filter = intentInfo.getIntentFilter();
1427 
1428             PackageStateInternal packageState =
1429                     computer.getPackageStateInternal(provider.getPackageName());
1430             if (packageState == null || packageState.getPkg() == null
1431                     || !PackageStateUtils.isEnabledAndMatches(packageState, provider, customFlags,
1432                     userId)) {
1433                 return null;
1434             }
1435 
1436             final PackageUserStateInternal userState = packageState.getUserStateOrDefault(userId);
1437             final boolean matchVisibleToInstantApp = (customFlags
1438                     & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
1439             final boolean isInstantApp = (customFlags & PackageManager.MATCH_INSTANT) != 0;
1440             // throw out filters that aren't visible to instant applications
1441             if (matchVisibleToInstantApp
1442                     && !(filter.isVisibleToInstantApp() || userState.isInstantApp())) {
1443                 return null;
1444             }
1445             // throw out instant application filters if we're not explicitly requesting them
1446             if (!isInstantApp && userState.isInstantApp()) {
1447                 return null;
1448             }
1449             // throw out instant application filters if updates are available; will trigger
1450             // instant application resolution
1451             if (userState.isInstantApp() && packageState.isUpdateAvailable()) {
1452                 return null;
1453             }
1454             final ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(
1455                     packageState.getPkg(), customFlags, userState, userId, packageState);
1456             if (appInfo == null) {
1457                 return null;
1458             }
1459             ProviderInfo pi = PackageInfoUtils.generateProviderInfo(packageState.getPkg(), provider,
1460                     customFlags, userState, appInfo, userId, packageState);
1461             if (pi == null) {
1462                 return null;
1463             }
1464             final ResolveInfo res = new ResolveInfo();
1465             res.providerInfo = pi;
1466             if ((customFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
1467                 res.filter = filter;
1468             }
1469             res.priority = filter.getPriority();
1470             // TODO(b/135203078): This field was unwritten and does nothing
1471 //            res.preferredOrder = pkg.getPreferredOrder();
1472             res.match = match;
1473             res.isDefault = intentInfo.isHasDefault();
1474             res.labelRes = intentInfo.getLabelRes();
1475             res.nonLocalizedLabel = intentInfo.getNonLocalizedLabel();
1476             res.icon = intentInfo.getIcon();
1477             res.system = res.providerInfo.applicationInfo.isSystemApp();
1478             return res;
1479         }
1480 
1481         @Override
sortResults(List<ResolveInfo> results)1482         protected void sortResults(List<ResolveInfo> results) {
1483             results.sort(RESOLVE_PRIORITY_SORTER);
1484         }
1485 
1486         @Override
dumpFilter(PrintWriter out, String prefix, Pair<ParsedProvider, ParsedIntentInfo> pair)1487         protected void dumpFilter(PrintWriter out, String prefix,
1488                 Pair<ParsedProvider, ParsedIntentInfo> pair) {
1489             ParsedProvider provider = pair.first;
1490             ParsedIntentInfo filter = pair.second;
1491 
1492             out.print(prefix);
1493             out.print(Integer.toHexString(System.identityHashCode(provider)));
1494             out.print(' ');
1495             ComponentName.printShortString(out, provider.getPackageName(), provider.getClassName());
1496             out.print(" filter ");
1497             out.println(Integer.toHexString(System.identityHashCode(filter)));
1498         }
1499 
1500         @Override
filterToLabel(Pair<ParsedProvider, ParsedIntentInfo> filter)1501         protected Object filterToLabel(Pair<ParsedProvider, ParsedIntentInfo> filter) {
1502             return filter;
1503         }
1504 
dumpFilterLabel(PrintWriter out, String prefix, Object label, int count)1505         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
1506             @SuppressWarnings("unchecked") final Pair<ParsedProvider, ParsedIntentInfo> pair =
1507                     (Pair<ParsedProvider, ParsedIntentInfo>) label;
1508             out.print(prefix);
1509             out.print(Integer.toHexString(System.identityHashCode(pair.first)));
1510             out.print(' ');
1511             ComponentName.printShortString(out, pair.first.getPackageName(),
1512                     pair.first.getClassName());
1513             if (count > 1) {
1514                 out.print(" (");
1515                 out.print(count);
1516                 out.print(" filters)");
1517             }
1518             out.println();
1519         }
1520 
1521         @Override
getIntentFilter( @onNull Pair<ParsedProvider, ParsedIntentInfo> input)1522         protected IntentFilter getIntentFilter(
1523                 @NonNull Pair<ParsedProvider, ParsedIntentInfo> input) {
1524             return input.second.getIntentFilter();
1525         }
1526 
1527         final ArrayMap<ComponentName, ParsedProvider> mProviders = new ArrayMap<>();
1528     }
1529 
1530     public static final class ServiceIntentResolver
1531             extends MimeGroupsAwareIntentResolver<Pair<ParsedService, ParsedIntentInfo>, ResolveInfo> {
1532         // Default constructor
ServiceIntentResolver(@onNull UserManagerService userManager)1533         ServiceIntentResolver(@NonNull UserManagerService userManager) {
1534             super(userManager);
1535         }
1536 
1537         // Copy constructor used in creating snapshots
ServiceIntentResolver(@onNull ServiceIntentResolver orig, @NonNull UserManagerService userManager)1538         ServiceIntentResolver(@NonNull ServiceIntentResolver orig,
1539                 @NonNull UserManagerService userManager) {
1540             super(orig, userManager);
1541             mServices.putAll(orig.mServices);
1542         }
1543 
1544         @Override
queryIntent(@onNull PackageDataSnapshot snapshot, Intent intent, String resolvedType, boolean defaultOnly, @UserIdInt int userId)1545         public List<ResolveInfo> queryIntent(@NonNull PackageDataSnapshot snapshot, Intent intent,
1546                 String resolvedType, boolean defaultOnly, @UserIdInt int userId) {
1547             if (!mUserManager.exists(userId)) {
1548                 return null;
1549             }
1550             long flags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
1551             return super.queryIntent(snapshot, intent, resolvedType, defaultOnly, userId, flags);
1552         }
1553 
queryIntent(@onNull Computer computer, Intent intent, String resolvedType, long flags, int userId)1554         List<ResolveInfo> queryIntent(@NonNull Computer computer, Intent intent,
1555                 String resolvedType, long flags, int userId) {
1556             if (!mUserManager.exists(userId)) return null;
1557             return super.queryIntent(computer, intent, resolvedType,
1558                     (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId, flags);
1559         }
1560 
queryIntentForPackage(@onNull Computer computer, Intent intent, String resolvedType, long flags, List<ParsedService> packageServices, int userId)1561         List<ResolveInfo> queryIntentForPackage(@NonNull Computer computer, Intent intent,
1562                 String resolvedType, long flags, List<ParsedService> packageServices, int userId) {
1563             if (!mUserManager.exists(userId)) return null;
1564             if (packageServices == null) {
1565                 return Collections.emptyList();
1566             }
1567             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
1568             final int servicesSize = packageServices.size();
1569             ArrayList<Pair<ParsedService, ParsedIntentInfo>[]> listCut =
1570                     new ArrayList<>(servicesSize);
1571 
1572             List<ParsedIntentInfo> intentFilters;
1573             for (int i = 0; i < servicesSize; ++i) {
1574                 ParsedService service = packageServices.get(i);
1575                 intentFilters = service.getIntents();
1576                 if (intentFilters.size() > 0) {
1577                     Pair<ParsedService, ParsedIntentInfo>[] array = newArray(intentFilters.size());
1578                     for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) {
1579                         array[arrayIndex] = Pair.create(service, intentFilters.get(arrayIndex));
1580                     }
1581                     listCut.add(array);
1582                 }
1583             }
1584             return super.queryIntentFromList(computer, intent, resolvedType,
1585                     defaultOnly, listCut, userId, flags);
1586         }
1587 
addService(@onNull Computer computer, ParsedService s)1588         void addService(@NonNull Computer computer, ParsedService s) {
1589             mServices.put(s.getComponentName(), s);
1590             if (DEBUG_SHOW_INFO) {
1591                 Log.v(TAG, "  service:");
1592                 Log.v(TAG, "    Class=" + s.getName());
1593             }
1594             final int intentsSize = s.getIntents().size();
1595             int j;
1596             for (j = 0; j < intentsSize; j++) {
1597                 ParsedIntentInfo intent = s.getIntents().get(j);
1598                 IntentFilter intentFilter = intent.getIntentFilter();
1599                 if (DEBUG_SHOW_INFO) {
1600                     Log.v(TAG, "    IntentFilter:");
1601                     intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
1602                 }
1603                 if (!intentFilter.debugCheck()) {
1604                     Log.w(TAG, "==> For Service " + s.getName());
1605                 }
1606                 addFilter(computer, Pair.create(s, intent));
1607             }
1608         }
1609 
removeService(ParsedService s)1610         void removeService(ParsedService s) {
1611             mServices.remove(s.getComponentName());
1612             if (DEBUG_SHOW_INFO) {
1613                 Log.v(TAG, "  service:");
1614                 Log.v(TAG, "    Class=" + s.getName());
1615             }
1616             final int intentsSize = s.getIntents().size();
1617             int j;
1618             for (j = 0; j < intentsSize; j++) {
1619                 ParsedIntentInfo intent = s.getIntents().get(j);
1620                 IntentFilter intentFilter = intent.getIntentFilter();
1621                 if (DEBUG_SHOW_INFO) {
1622                     Log.v(TAG, "    IntentFilter:");
1623                     intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
1624                 }
1625                 removeFilter(Pair.create(s, intent));
1626             }
1627         }
1628 
1629         @Override
allowFilterResult(Pair<ParsedService, ParsedIntentInfo> filter, List<ResolveInfo> dest)1630         protected boolean allowFilterResult(Pair<ParsedService, ParsedIntentInfo> filter,
1631                 List<ResolveInfo> dest) {
1632             for (int i = dest.size() - 1; i >= 0; --i) {
1633                 ServiceInfo destAi = dest.get(i).serviceInfo;
1634                 if (Objects.equals(destAi.name, filter.first.getClassName())
1635                         && Objects.equals(destAi.packageName, filter.first.getPackageName())) {
1636                     return false;
1637                 }
1638             }
1639             return true;
1640         }
1641 
1642         @Override
newArray(int size)1643         protected Pair<ParsedService, ParsedIntentInfo>[] newArray(int size) {
1644             //noinspection unchecked
1645             return (Pair<ParsedService, ParsedIntentInfo>[]) new Pair<?, ?>[size];
1646         }
1647 
1648         @Override
isPackageForFilter(String packageName, Pair<ParsedService, ParsedIntentInfo> info)1649         protected boolean isPackageForFilter(String packageName,
1650                 Pair<ParsedService, ParsedIntentInfo> info) {
1651             return packageName.equals(info.first.getPackageName());
1652         }
1653 
1654         @Override
newResult(@onNull Computer computer, Pair<ParsedService, ParsedIntentInfo> pair, int match, int userId, long customFlags)1655         protected ResolveInfo newResult(@NonNull Computer computer,
1656                 Pair<ParsedService, ParsedIntentInfo> pair, int match, int userId,
1657                 long customFlags) {
1658             if (!mUserManager.exists(userId)) return null;
1659 
1660             ParsedService service = pair.first;
1661             ParsedIntentInfo intentInfo = pair.second;
1662             IntentFilter filter = intentInfo.getIntentFilter();
1663 
1664             final PackageStateInternal packageState = computer.getPackageStateInternal(
1665                     service.getPackageName());
1666             if (packageState == null || packageState.getPkg() == null
1667                     || !PackageStateUtils.isEnabledAndMatches(packageState, service, customFlags,
1668                     userId)) {
1669                 return null;
1670             }
1671 
1672             final PackageUserStateInternal userState = packageState.getUserStateOrDefault(userId);
1673             ServiceInfo si = PackageInfoUtils.generateServiceInfo(packageState.getPkg(), service,
1674                     customFlags, userState, userId, packageState);
1675             if (si == null) {
1676                 return null;
1677             }
1678             final boolean matchVisibleToInstantApp =
1679                     (customFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
1680             final boolean isInstantApp = (customFlags & PackageManager.MATCH_INSTANT) != 0;
1681             // throw out filters that aren't visible to ephemeral apps
1682             if (matchVisibleToInstantApp
1683                     && !(filter.isVisibleToInstantApp() || userState.isInstantApp())) {
1684                 return null;
1685             }
1686             // throw out ephemeral filters if we're not explicitly requesting them
1687             if (!isInstantApp && userState.isInstantApp()) {
1688                 return null;
1689             }
1690             // throw out instant app filters if updates are available; will trigger
1691             // instant app resolution
1692             if (userState.isInstantApp() && packageState.isUpdateAvailable()) {
1693                 return null;
1694             }
1695             final ResolveInfo res = new ResolveInfo();
1696             res.serviceInfo = si;
1697             if ((customFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
1698                 res.filter = filter;
1699             }
1700             res.priority = filter.getPriority();
1701             // TODO(b/135203078): This field was unwritten and does nothing
1702 //            res.preferredOrder = pkg.getPreferredOrder();
1703             res.match = match;
1704             res.isDefault = intentInfo.isHasDefault();
1705             res.labelRes = intentInfo.getLabelRes();
1706             res.nonLocalizedLabel = intentInfo.getNonLocalizedLabel();
1707             res.icon = intentInfo.getIcon();
1708             res.system = res.serviceInfo.applicationInfo.isSystemApp();
1709             return res;
1710         }
1711 
1712         @Override
sortResults(List<ResolveInfo> results)1713         protected void sortResults(List<ResolveInfo> results) {
1714             results.sort(RESOLVE_PRIORITY_SORTER);
1715         }
1716 
1717         @Override
dumpFilter(PrintWriter out, String prefix, Pair<ParsedService, ParsedIntentInfo> pair)1718         protected void dumpFilter(PrintWriter out, String prefix,
1719                 Pair<ParsedService, ParsedIntentInfo> pair) {
1720             ParsedService service = pair.first;
1721             ParsedIntentInfo filter = pair.second;
1722 
1723             out.print(prefix);
1724             out.print(Integer.toHexString(System.identityHashCode(service)));
1725             out.print(' ');
1726             ComponentName.printShortString(out, service.getPackageName(), service.getClassName());
1727             out.print(" filter ");
1728             out.print(Integer.toHexString(System.identityHashCode(filter)));
1729             if (service.getPermission() != null) {
1730                 out.print(" permission "); out.println(service.getPermission());
1731             } else {
1732                 out.println();
1733             }
1734         }
1735 
1736         @Override
filterToLabel(Pair<ParsedService, ParsedIntentInfo> filter)1737         protected Object filterToLabel(Pair<ParsedService, ParsedIntentInfo> filter) {
1738             return filter;
1739         }
1740 
dumpFilterLabel(PrintWriter out, String prefix, Object label, int count)1741         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
1742             @SuppressWarnings("unchecked") final Pair<ParsedService, ParsedIntentInfo> pair =
1743                     (Pair<ParsedService, ParsedIntentInfo>) label;
1744             out.print(prefix);
1745             out.print(Integer.toHexString(System.identityHashCode(pair.first)));
1746             out.print(' ');
1747             ComponentName.printShortString(out, pair.first.getPackageName(),
1748                     pair.first.getClassName());
1749             if (count > 1) {
1750                 out.print(" ("); out.print(count); out.print(" filters)");
1751             }
1752             out.println();
1753         }
1754 
1755         @Override
getIntentFilter( @onNull Pair<ParsedService, ParsedIntentInfo> input)1756         protected IntentFilter getIntentFilter(
1757                 @NonNull Pair<ParsedService, ParsedIntentInfo> input) {
1758             return input.second.getIntentFilter();
1759         }
1760 
1761         // Keys are String (activity class name), values are Activity.
1762         final ArrayMap<ComponentName, ParsedService> mServices = new ArrayMap<>();
1763     }
1764 
1765     public static final class InstantAppIntentResolver
1766             extends IntentResolver<AuxiliaryResolveInfo.AuxiliaryFilter,
1767             AuxiliaryResolveInfo.AuxiliaryFilter> {
1768         /**
1769          * The result that has the highest defined order. Ordering applies on a
1770          * per-package basis. Mapping is from package name to Pair of order and
1771          * EphemeralResolveInfo.
1772          * <p>
1773          * NOTE: This is implemented as a field variable for convenience and efficiency.
1774          * By having a field variable, we're able to track filter ordering as soon as
1775          * a non-zero order is defined. Otherwise, multiple loops across the result set
1776          * would be needed to apply ordering. If the intent resolver becomes re-entrant,
1777          * this needs to be contained entirely within {@link #filterResults}.
1778          */
1779         final ArrayMap<String, Pair<Integer, InstantAppResolveInfo>> mOrderResult =
1780                 new ArrayMap<>();
1781 
1782         @NonNull
1783         private final UserManagerService mUserManager;
1784 
InstantAppIntentResolver(@onNull UserManagerService userManager)1785         public InstantAppIntentResolver(@NonNull UserManagerService userManager) {
1786             mUserManager = userManager;
1787         }
1788 
1789         @Override
newArray(int size)1790         protected AuxiliaryResolveInfo.AuxiliaryFilter[] newArray(int size) {
1791             return new AuxiliaryResolveInfo.AuxiliaryFilter[size];
1792         }
1793 
1794         @Override
isPackageForFilter(String packageName, AuxiliaryResolveInfo.AuxiliaryFilter responseObj)1795         protected boolean isPackageForFilter(String packageName,
1796                 AuxiliaryResolveInfo.AuxiliaryFilter responseObj) {
1797             return true;
1798         }
1799 
1800         @Override
newResult(@onNull Computer computer, AuxiliaryResolveInfo.AuxiliaryFilter responseObj, int match, int userId, long customFlags)1801         protected AuxiliaryResolveInfo.AuxiliaryFilter newResult(@NonNull Computer computer,
1802                 AuxiliaryResolveInfo.AuxiliaryFilter responseObj, int match, int userId,
1803                 long customFlags) {
1804             if (!mUserManager.exists(userId)) {
1805                 return null;
1806             }
1807             final String packageName = responseObj.resolveInfo.getPackageName();
1808             final Integer order = responseObj.getOrder();
1809             final Pair<Integer, InstantAppResolveInfo> lastOrderResult =
1810                     mOrderResult.get(packageName);
1811             // ordering is enabled and this item's order isn't high enough
1812             if (lastOrderResult != null && lastOrderResult.first >= order) {
1813                 return null;
1814             }
1815             final InstantAppResolveInfo res = responseObj.resolveInfo;
1816             if (order > 0) {
1817                 // non-zero order, enable ordering
1818                 mOrderResult.put(packageName, new Pair<>(order, res));
1819             }
1820             return responseObj;
1821         }
1822 
1823         @Override
filterResults(List<AuxiliaryResolveInfo.AuxiliaryFilter> results)1824         protected void filterResults(List<AuxiliaryResolveInfo.AuxiliaryFilter> results) {
1825             // only do work if ordering is enabled [most of the time it won't be]
1826             if (mOrderResult.size() == 0) {
1827                 return;
1828             }
1829             int resultSize = results.size();
1830             for (int i = 0; i < resultSize; i++) {
1831                 final InstantAppResolveInfo info = results.get(i).resolveInfo;
1832                 final String packageName = info.getPackageName();
1833                 final Pair<Integer, InstantAppResolveInfo> savedInfo =
1834                         mOrderResult.get(packageName);
1835                 if (savedInfo == null) {
1836                     // package doesn't having ordering
1837                     continue;
1838                 }
1839                 if (savedInfo.second == info) {
1840                     // circled back to the highest ordered item; remove from order list
1841                     mOrderResult.remove(packageName);
1842                     if (mOrderResult.size() == 0) {
1843                         // no more ordered items
1844                         break;
1845                     }
1846                     continue;
1847                 }
1848                 // item has a worse order, remove it from the result list
1849                 results.remove(i);
1850                 resultSize--;
1851                 i--;
1852             }
1853         }
1854 
1855         @Override
getIntentFilter( @onNull AuxiliaryResolveInfo.AuxiliaryFilter input)1856         protected IntentFilter getIntentFilter(
1857                 @NonNull AuxiliaryResolveInfo.AuxiliaryFilter input) {
1858             return input;
1859         }
1860     }
1861 
1862     /**
1863      * Removes MIME type from the group, by delegating to IntentResolvers
1864      * @return true if any intent filters were changed due to this update
1865      */
updateMimeGroup(@onNull Computer computer, String packageName, String group)1866     public boolean updateMimeGroup(@NonNull Computer computer, String packageName, String group) {
1867         boolean hasChanges = false;
1868         synchronized (mLock) {
1869             hasChanges |= mActivities.updateMimeGroup(computer, packageName, group);
1870             hasChanges |= mProviders.updateMimeGroup(computer, packageName, group);
1871             hasChanges |= mReceivers.updateMimeGroup(computer, packageName, group);
1872             hasChanges |= mServices.updateMimeGroup(computer, packageName, group);
1873             if (hasChanges) {
1874                 onChanged();
1875             }
1876         }
1877         return hasChanges;
1878     }
1879 }
1880