• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.util.ArrayMap;
39 import android.util.ArraySet;
40 import android.util.DebugUtils;
41 import android.util.Log;
42 import android.util.LogPrinter;
43 import android.util.Pair;
44 import android.util.Slog;
45 
46 import com.android.internal.annotations.GuardedBy;
47 import com.android.internal.util.ArrayUtils;
48 import com.android.server.IntentResolver;
49 import com.android.server.pm.Computer;
50 import com.android.server.pm.PackageManagerException;
51 import com.android.server.pm.UserManagerService;
52 import com.android.server.pm.UserNeedsBadgingCache;
53 import com.android.server.pm.parsing.PackageInfoUtils;
54 import com.android.server.pm.parsing.pkg.AndroidPackage;
55 import com.android.server.pm.pkg.PackageStateInternal;
56 import com.android.server.pm.pkg.PackageStateUtils;
57 import com.android.server.pm.pkg.PackageUserStateInternal;
58 import com.android.server.pm.pkg.component.ComponentMutateUtils;
59 import com.android.server.pm.pkg.component.ParsedActivity;
60 import com.android.server.pm.pkg.component.ParsedComponent;
61 import com.android.server.pm.pkg.component.ParsedIntentInfo;
62 import com.android.server.pm.pkg.component.ParsedMainComponent;
63 import com.android.server.pm.pkg.component.ParsedProvider;
64 import com.android.server.pm.pkg.component.ParsedProviderImpl;
65 import com.android.server.pm.pkg.component.ParsedService;
66 import com.android.server.pm.snapshot.PackageDataSnapshot;
67 import com.android.server.utils.Snappable;
68 import com.android.server.utils.SnapshotCache;
69 
70 import java.io.PrintWriter;
71 import java.util.ArrayList;
72 import java.util.Collection;
73 import java.util.Collections;
74 import java.util.Comparator;
75 import java.util.Iterator;
76 import java.util.List;
77 import java.util.Objects;
78 import java.util.Set;
79 import java.util.function.Function;
80 
81 /** Resolves all Android component types [activities, services, providers and receivers]. */
82 public class ComponentResolver extends ComponentResolverLocked implements
83         Snappable<ComponentResolverApi> {
84     private static final boolean DEBUG = false;
85     private static final String TAG = "PackageManager";
86     private static final boolean DEBUG_FILTERS = false;
87     private static final boolean DEBUG_SHOW_INFO = false;
88 
89     // Convenience function to report that this object has changed.
onChanged()90     private void onChanged() {
91         dispatchChange(this);
92     }
93 
94     /**
95      * The set of all protected actions [i.e. those actions for which a high priority
96      * intent filter is disallowed].
97      */
98     private static final Set<String> PROTECTED_ACTIONS = new ArraySet<>();
99     static {
100         PROTECTED_ACTIONS.add(Intent.ACTION_SEND);
101         PROTECTED_ACTIONS.add(Intent.ACTION_SENDTO);
102         PROTECTED_ACTIONS.add(Intent.ACTION_SEND_MULTIPLE);
103         PROTECTED_ACTIONS.add(Intent.ACTION_VIEW);
104     }
105 
106     public static final Comparator<ResolveInfo> RESOLVE_PRIORITY_SORTER = (r1, r2) -> {
107         int v1 = r1.priority;
108         int v2 = r2.priority;
109         //System.out.println("Comparing: q1=" + q1 + " q2=" + q2);
110         if (v1 != v2) {
111             return (v1 > v2) ? -1 : 1;
112         }
113         v1 = r1.preferredOrder;
114         v2 = r2.preferredOrder;
115         if (v1 != v2) {
116             return (v1 > v2) ? -1 : 1;
117         }
118         if (r1.isDefault != r2.isDefault) {
119             return r1.isDefault ? -1 : 1;
120         }
121         v1 = r1.match;
122         v2 = r2.match;
123         //System.out.println("Comparing: m1=" + m1 + " m2=" + m2);
124         if (v1 != v2) {
125             return (v1 > v2) ? -1 : 1;
126         }
127         if (r1.system != r2.system) {
128             return r1.system ? -1 : 1;
129         }
130         if (r1.activityInfo != null) {
131             return r1.activityInfo.packageName.compareTo(r2.activityInfo.packageName);
132         }
133         if (r1.serviceInfo != null) {
134             return r1.serviceInfo.packageName.compareTo(r2.serviceInfo.packageName);
135         }
136         if (r1.providerInfo != null) {
137             return r1.providerInfo.packageName.compareTo(r2.providerInfo.packageName);
138         }
139         return 0;
140     };
141 
142     /** Whether or not processing protected filters should be deferred. */
143     boolean mDeferProtectedFilters = true;
144 
145     /**
146      * Tracks high priority intent filters for protected actions. During boot, certain
147      * filter actions are protected and should never be allowed to have a high priority
148      * intent filter for them. However, there is one, and only one exception -- the
149      * setup wizard. It must be able to define a high priority intent filter for these
150      * actions to ensure there are no escapes from the wizard. We need to delay processing
151      * of these during boot as we need to inspect at all of the intent filters on the
152      * /system partition in order to know which component is the setup wizard. This can
153      * only ever be non-empty if {@link #mDeferProtectedFilters} is {@code true}.
154      *
155      * This is a pair of component package name to actual filter, because we don't store the
156      * name inside the filter. It's technically independent of the component it's contained in.
157      */
158     List<Pair<ParsedMainComponent, ParsedIntentInfo>> mProtectedFilters;
159 
ComponentResolver(@onNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)160     public ComponentResolver(@NonNull UserManagerService userManager,
161             @NonNull UserNeedsBadgingCache userNeedsBadgingCache) {
162         super(userManager);
163         mActivities = new ActivityIntentResolver(userManager, userNeedsBadgingCache);
164         mProviders = new ProviderIntentResolver(userManager);
165         mReceivers = new ReceiverIntentResolver(userManager, userNeedsBadgingCache);
166         mServices = new ServiceIntentResolver(userManager);
167         mProvidersByAuthority = new ArrayMap<>();
168         mDeferProtectedFilters = true;
169 
170         mSnapshot = new SnapshotCache<>(this, this) {
171                 @Override
172                 public ComponentResolverApi createSnapshot() {
173                     synchronized (mLock) {
174                         return new ComponentResolverSnapshot(ComponentResolver.this,
175                                 userNeedsBadgingCache);
176                     }
177                 }};
178     }
179 
180     final SnapshotCache<ComponentResolverApi> mSnapshot;
181 
182     /**
183      * Create a snapshot.
184      */
snapshot()185     public ComponentResolverApi snapshot() {
186         return mSnapshot.snapshot();
187     }
188 
189     /** Add all components defined in the given package to the internal structures. */
addAllComponents(AndroidPackage pkg, boolean chatty, @Nullable String setupWizardPackage, @NonNull Computer computer)190     public void addAllComponents(AndroidPackage pkg, boolean chatty,
191             @Nullable String setupWizardPackage, @NonNull Computer computer) {
192         final ArrayList<Pair<ParsedActivity, ParsedIntentInfo>> newIntents = new ArrayList<>();
193         synchronized (mLock) {
194             addActivitiesLocked(computer, pkg, newIntents, chatty);
195             addReceiversLocked(computer, pkg, chatty);
196             addProvidersLocked(computer, pkg, chatty);
197             addServicesLocked(computer, pkg, chatty);
198             onChanged();
199         }
200 
201         for (int i = newIntents.size() - 1; i >= 0; --i) {
202             final Pair<ParsedActivity, ParsedIntentInfo> pair = newIntents.get(i);
203             final PackageStateInternal disabledPkgSetting = computer
204                     .getDisabledSystemPackage(pair.first.getPackageName());
205             final AndroidPackage disabledPkg =
206                     disabledPkgSetting == null ? null : disabledPkgSetting.getPkg();
207             final List<ParsedActivity> systemActivities =
208                     disabledPkg != null ? disabledPkg.getActivities() : null;
209             adjustPriority(computer, systemActivities, pair.first, pair.second, setupWizardPackage);
210             onChanged();
211         }
212     }
213 
214     /** Removes all components defined in the given package from the internal structures. */
removeAllComponents(AndroidPackage pkg, boolean chatty)215     public void removeAllComponents(AndroidPackage pkg, boolean chatty) {
216         synchronized (mLock) {
217             removeAllComponentsLocked(pkg, chatty);
218             onChanged();
219         }
220     }
221 
222     /**
223      * Reprocess any protected filters that have been deferred. At this point, we've scanned
224      * all of the filters defined on the /system partition and know the special components.
225      */
fixProtectedFilterPriorities(@ullable String setupWizardPackage)226     public void fixProtectedFilterPriorities(@Nullable String setupWizardPackage) {
227         synchronized (mLock) {
228             if (!mDeferProtectedFilters) {
229                 return;
230             }
231             mDeferProtectedFilters = false;
232 
233             if (mProtectedFilters == null || mProtectedFilters.size() == 0) {
234                 return;
235             }
236             final List<Pair<ParsedMainComponent, ParsedIntentInfo>> protectedFilters =
237                     mProtectedFilters;
238             mProtectedFilters = null;
239 
240             if (DEBUG_FILTERS && setupWizardPackage == null) {
241                 Slog.i(TAG, "No setup wizard;"
242                         + " All protected intents capped to priority 0");
243             }
244             for (int i = protectedFilters.size() - 1; i >= 0; --i) {
245                 final Pair<ParsedMainComponent, ParsedIntentInfo> pair = protectedFilters.get(i);
246                 ParsedMainComponent component = pair.first;
247                 ParsedIntentInfo intentInfo = pair.second;
248                 IntentFilter filter = intentInfo.getIntentFilter();
249                 String packageName = component.getPackageName();
250                 String className = component.getClassName();
251                 if (packageName.equals(setupWizardPackage)) {
252                     if (DEBUG_FILTERS) {
253                         Slog.i(TAG, "Found setup wizard;"
254                                 + " allow priority " + filter.getPriority() + ";"
255                                 + " package: " + packageName
256                                 + " activity: " + className
257                                 + " priority: " + filter.getPriority());
258                     }
259                     // skip setup wizard; allow it to keep the high priority filter
260                     continue;
261                 }
262                 if (DEBUG_FILTERS) {
263                     Slog.i(TAG, "Protected action; cap priority to 0;"
264                             + " package: " + packageName
265                             + " activity: " + className
266                             + " origPrio: " + filter.getPriority());
267                 }
268                 filter.setPriority(0);
269             }
270             onChanged();
271         }
272     }
273 
274     @GuardedBy("mLock")
addActivitiesLocked(@onNull Computer computer, AndroidPackage pkg, List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty)275     private void addActivitiesLocked(@NonNull Computer computer, AndroidPackage pkg,
276             List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty) {
277         final int activitiesSize = ArrayUtils.size(pkg.getActivities());
278         StringBuilder r = null;
279         for (int i = 0; i < activitiesSize; i++) {
280             ParsedActivity a = pkg.getActivities().get(i);
281             mActivities.addActivity(computer, a, "activity", newIntents);
282             if (DEBUG_PACKAGE_SCANNING && chatty) {
283                 if (r == null) {
284                     r = new StringBuilder(256);
285                 } else {
286                     r.append(' ');
287                 }
288                 r.append(a.getName());
289             }
290         }
291         if (DEBUG_PACKAGE_SCANNING && chatty) {
292             Log.d(TAG, "  Activities: " + (r == null ? "<NONE>" : r));
293         }
294     }
295 
296     @GuardedBy("mLock")
addProvidersLocked(@onNull Computer computer, AndroidPackage pkg, boolean chatty)297     private void addProvidersLocked(@NonNull Computer computer, AndroidPackage pkg, boolean chatty) {
298         final int providersSize = ArrayUtils.size(pkg.getProviders());
299         StringBuilder r = null;
300         for (int i = 0; i < providersSize; i++) {
301             ParsedProvider p = pkg.getProviders().get(i);
302             mProviders.addProvider(computer, p);
303             if (p.getAuthority() != null) {
304                 String[] names = p.getAuthority().split(";");
305 
306                 // TODO(b/135203078): Remove this mutation
307                 ComponentMutateUtils.setAuthority(p, null);
308                 for (int j = 0; j < names.length; j++) {
309                     if (j == 1 && p.isSyncable()) {
310                         // We only want the first authority for a provider to possibly be
311                         // syncable, so if we already added this provider using a different
312                         // authority clear the syncable flag. We copy the provider before
313                         // changing it because the mProviders object contains a reference
314                         // to a provider that we don't want to change.
315                         // Only do this for the second authority since the resulting provider
316                         // object can be the same for all future authorities for this provider.
317                         p = new ParsedProviderImpl(p);
318                         ComponentMutateUtils.setSyncable(p, false);
319                     }
320                     if (!mProvidersByAuthority.containsKey(names[j])) {
321                         mProvidersByAuthority.put(names[j], p);
322                         if (p.getAuthority() == null) {
323                             ComponentMutateUtils.setAuthority(p, names[j]);
324                         } else {
325                             ComponentMutateUtils.setAuthority(p, p.getAuthority() + ";" + names[j]);
326                         }
327                         if (DEBUG_PACKAGE_SCANNING && chatty) {
328                             Log.d(TAG, "Registered content provider: " + names[j]
329                                     + ", className = " + p.getName()
330                                     + ", isSyncable = " + p.isSyncable());
331                         }
332                     } else {
333                         final ParsedProvider other =
334                                 mProvidersByAuthority.get(names[j]);
335                         final ComponentName component =
336                                 (other != null && other.getComponentName() != null)
337                                         ? other.getComponentName() : null;
338                         final String packageName =
339                                 component != null ? component.getPackageName() : "?";
340                         Slog.w(TAG, "Skipping provider name " + names[j]
341                                 + " (in package " + pkg.getPackageName() + ")"
342                                 + ": name already used by " + packageName);
343                     }
344                 }
345             }
346             if (DEBUG_PACKAGE_SCANNING && chatty) {
347                 if (r == null) {
348                     r = new StringBuilder(256);
349                 } else {
350                     r.append(' ');
351                 }
352                 r.append(p.getName());
353             }
354         }
355         if (DEBUG_PACKAGE_SCANNING && chatty) {
356             Log.d(TAG, "  Providers: " + (r == null ? "<NONE>" : r));
357         }
358     }
359 
360     @GuardedBy("mLock")
addReceiversLocked(@onNull Computer computer, AndroidPackage pkg, boolean chatty)361     private void addReceiversLocked(@NonNull Computer computer, AndroidPackage pkg, boolean chatty) {
362         final int receiversSize = ArrayUtils.size(pkg.getReceivers());
363         StringBuilder r = null;
364         for (int i = 0; i < receiversSize; i++) {
365             ParsedActivity a = pkg.getReceivers().get(i);
366             mReceivers.addActivity(computer, a, "receiver", null);
367             if (DEBUG_PACKAGE_SCANNING && chatty) {
368                 if (r == null) {
369                     r = new StringBuilder(256);
370                 } else {
371                     r.append(' ');
372                 }
373                 r.append(a.getName());
374             }
375         }
376         if (DEBUG_PACKAGE_SCANNING && chatty) {
377             Log.d(TAG, "  Receivers: " + (r == null ? "<NONE>" : r));
378         }
379     }
380 
381     @GuardedBy("mLock")
addServicesLocked(@onNull Computer computer, AndroidPackage pkg, boolean chatty)382     private void addServicesLocked(@NonNull Computer computer, AndroidPackage pkg, boolean chatty) {
383         final int servicesSize = ArrayUtils.size(pkg.getServices());
384         StringBuilder r = null;
385         for (int i = 0; i < servicesSize; i++) {
386             ParsedService s = pkg.getServices().get(i);
387             mServices.addService(computer, s);
388             if (DEBUG_PACKAGE_SCANNING && chatty) {
389                 if (r == null) {
390                     r = new StringBuilder(256);
391                 } else {
392                     r.append(' ');
393                 }
394                 r.append(s.getName());
395             }
396         }
397         if (DEBUG_PACKAGE_SCANNING && chatty) {
398             Log.d(TAG, "  Services: " + (r == null ? "<NONE>" : r));
399         }
400     }
401 
402     /**
403      * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE
404      * MODIFIED. Do not pass in a list that should not be changed.
405      */
getIntentListSubset(List<ParsedIntentInfo> intentList, Function<IntentFilter, Iterator<T>> generator, Iterator<T> searchIterator)406     private static <T> void getIntentListSubset(List<ParsedIntentInfo> intentList,
407             Function<IntentFilter, Iterator<T>> generator, Iterator<T> searchIterator) {
408         // loop through the set of actions; every one must be found in the intent filter
409         while (searchIterator.hasNext()) {
410             // we must have at least one filter in the list to consider a match
411             if (intentList.size() == 0) {
412                 break;
413             }
414 
415             final T searchAction = searchIterator.next();
416 
417             // loop through the set of intent filters
418             final Iterator<ParsedIntentInfo> intentIter = intentList.iterator();
419             while (intentIter.hasNext()) {
420                 final ParsedIntentInfo intentInfo = intentIter.next();
421                 boolean selectionFound = false;
422 
423                 // loop through the intent filter's selection criteria; at least one
424                 // of them must match the searched criteria
425                 final Iterator<T> intentSelectionIter =
426                         generator.apply(intentInfo.getIntentFilter());
427                 while (intentSelectionIter != null && intentSelectionIter.hasNext()) {
428                     final T intentSelection = intentSelectionIter.next();
429                     if (intentSelection != null && intentSelection.equals(searchAction)) {
430                         selectionFound = true;
431                         break;
432                     }
433                 }
434 
435                 // the selection criteria wasn't found in this filter's set; this filter
436                 // is not a potential match
437                 if (!selectionFound) {
438                     intentIter.remove();
439                 }
440             }
441         }
442     }
443 
isProtectedAction(IntentFilter filter)444     private static boolean isProtectedAction(IntentFilter filter) {
445         final Iterator<String> actionsIter = filter.actionsIterator();
446         while (actionsIter != null && actionsIter.hasNext()) {
447             final String filterAction = actionsIter.next();
448             if (PROTECTED_ACTIONS.contains(filterAction)) {
449                 return true;
450             }
451         }
452         return false;
453     }
454 
455     /**
456      * Finds a privileged activity that matches the specified activity names.
457      */
findMatchingActivity( List<ParsedActivity> activityList, ParsedActivity activityInfo)458     private static ParsedActivity findMatchingActivity(
459             List<ParsedActivity> activityList, ParsedActivity activityInfo) {
460         for (ParsedActivity sysActivity : activityList) {
461             if (sysActivity.getName().equals(activityInfo.getName())) {
462                 return sysActivity;
463             }
464             if (sysActivity.getName().equals(activityInfo.getTargetActivity())) {
465                 return sysActivity;
466             }
467             if (sysActivity.getTargetActivity() != null) {
468                 if (sysActivity.getTargetActivity().equals(activityInfo.getName())) {
469                     return sysActivity;
470                 }
471                 if (sysActivity.getTargetActivity().equals(activityInfo.getTargetActivity())) {
472                     return sysActivity;
473                 }
474             }
475         }
476         return null;
477     }
478 
479     /**
480      * Adjusts the priority of the given intent filter according to policy.
481      * <p>
482      * <ul>
483      * <li>The priority for non privileged applications is capped to '0'</li>
484      * <li>The priority for protected actions on privileged applications is capped to '0'</li>
485      * <li>The priority for unbundled updates to privileged applications is capped to the
486      *      priority defined on the system partition</li>
487      * </ul>
488      * <p>
489      * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
490      * allowed to obtain any priority on any action.
491      */
adjustPriority(@onNull Computer computer, List<ParsedActivity> systemActivities, ParsedActivity activity, ParsedIntentInfo intentInfo, String setupWizardPackage)492     private void adjustPriority(@NonNull Computer computer, List<ParsedActivity> systemActivities,
493             ParsedActivity activity, ParsedIntentInfo intentInfo, String setupWizardPackage) {
494         // nothing to do; priority is fine as-is
495         IntentFilter intentFilter = intentInfo.getIntentFilter();
496         if (intentFilter.getPriority() <= 0) {
497             return;
498         }
499 
500         String packageName = activity.getPackageName();
501         AndroidPackage pkg = computer.getPackage(packageName);
502 
503         final boolean privilegedApp = pkg.isPrivileged();
504         String className = activity.getClassName();
505         if (!privilegedApp) {
506             // non-privileged applications can never define a priority >0
507             if (DEBUG_FILTERS) {
508                 Slog.i(TAG, "Non-privileged app; cap priority to 0;"
509                         + " package: " + packageName
510                         + " activity: " + className
511                         + " origPrio: " + intentFilter.getPriority());
512             }
513             intentFilter.setPriority(0);
514             return;
515         }
516 
517         if (isProtectedAction(intentFilter)) {
518             if (mDeferProtectedFilters) {
519                 // We can't deal with these just yet. No component should ever obtain a
520                 // >0 priority for a protected actions, with ONE exception -- the setup
521                 // wizard. The setup wizard, however, cannot be known until we're able to
522                 // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do
523                 // until all intent filters have been processed. Chicken, meet egg.
524                 // Let the filter temporarily have a high priority and rectify the
525                 // priorities after all system packages have been scanned.
526                 if (mProtectedFilters == null) {
527                     mProtectedFilters = new ArrayList<>();
528                 }
529                 mProtectedFilters.add(Pair.create(activity, intentInfo));
530                 if (DEBUG_FILTERS) {
531                     Slog.i(TAG, "Protected action; save for later;"
532                             + " package: " + packageName
533                             + " activity: " + className
534                             + " origPrio: " + intentFilter.getPriority());
535                 }
536             } else {
537                 if (DEBUG_FILTERS && setupWizardPackage == null) {
538                     Slog.i(TAG, "No setup wizard;"
539                             + " All protected intents capped to priority 0");
540                 }
541                 if (packageName.equals(setupWizardPackage)) {
542                     if (DEBUG_FILTERS) {
543                         Slog.i(TAG, "Found setup wizard;"
544                                 + " allow priority " + intentFilter.getPriority() + ";"
545                                 + " package: " + packageName
546                                 + " activity: " + className
547                                 + " priority: " + intentFilter.getPriority());
548                     }
549                     // setup wizard gets whatever it wants
550                     return;
551                 }
552                 if (DEBUG_FILTERS) {
553                     Slog.i(TAG, "Protected action; cap priority to 0;"
554                             + " package: " + packageName
555                             + " activity: " + className
556                             + " origPrio: " + intentFilter.getPriority());
557                 }
558                 intentFilter.setPriority(0);
559             }
560             return;
561         }
562 
563         if (systemActivities == null) {
564             // the system package is not disabled; we're parsing the system partition
565 
566             // privileged apps on the system image get whatever priority they request
567             return;
568         }
569 
570         // privileged app unbundled update ... try to find the same activity
571 
572         ParsedActivity foundActivity = findMatchingActivity(systemActivities, activity);
573         if (foundActivity == null) {
574             // this is a new activity; it cannot obtain >0 priority
575             if (DEBUG_FILTERS) {
576                 Slog.i(TAG, "New activity; cap priority to 0;"
577                         + " package: " + packageName
578                         + " activity: " + className
579                         + " origPrio: " + intentFilter.getPriority());
580             }
581             intentFilter.setPriority(0);
582             return;
583         }
584 
585         // found activity, now check for filter equivalence
586 
587         // a shallow copy is enough; we modify the list, not its contents
588         final List<ParsedIntentInfo> intentListCopy =
589                 new ArrayList<>(foundActivity.getIntents());
590 
591         // find matching action subsets
592         final Iterator<String> actionsIterator = intentFilter.actionsIterator();
593         if (actionsIterator != null) {
594             getIntentListSubset(intentListCopy, IntentFilter::actionsIterator, actionsIterator);
595             if (intentListCopy.size() == 0) {
596                 // no more intents to match; we're not equivalent
597                 if (DEBUG_FILTERS) {
598                     Slog.i(TAG, "Mismatched action; cap priority to 0;"
599                             + " package: " + packageName
600                             + " activity: " + className
601                             + " origPrio: " + intentFilter.getPriority());
602                 }
603                 intentFilter.setPriority(0);
604                 return;
605             }
606         }
607 
608         // find matching category subsets
609         final Iterator<String> categoriesIterator = intentFilter.categoriesIterator();
610         if (categoriesIterator != null) {
611             getIntentListSubset(intentListCopy, IntentFilter::categoriesIterator,
612                     categoriesIterator);
613             if (intentListCopy.size() == 0) {
614                 // no more intents to match; we're not equivalent
615                 if (DEBUG_FILTERS) {
616                     Slog.i(TAG, "Mismatched category; cap priority to 0;"
617                             + " package: " + packageName
618                             + " activity: " + className
619                             + " origPrio: " + intentFilter.getPriority());
620                 }
621                 intentFilter.setPriority(0);
622                 return;
623             }
624         }
625 
626         // find matching schemes subsets
627         final Iterator<String> schemesIterator = intentFilter.schemesIterator();
628         if (schemesIterator != null) {
629             getIntentListSubset(intentListCopy, IntentFilter::schemesIterator, schemesIterator);
630             if (intentListCopy.size() == 0) {
631                 // no more intents to match; we're not equivalent
632                 if (DEBUG_FILTERS) {
633                     Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
634                             + " package: " + packageName
635                             + " activity: " + className
636                             + " origPrio: " + intentFilter.getPriority());
637                 }
638                 intentFilter.setPriority(0);
639                 return;
640             }
641         }
642 
643         // find matching authorities subsets
644         final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator =
645                 intentFilter.authoritiesIterator();
646         if (authoritiesIterator != null) {
647             getIntentListSubset(intentListCopy, IntentFilter::authoritiesIterator,
648                     authoritiesIterator);
649             if (intentListCopy.size() == 0) {
650                 // no more intents to match; we're not equivalent
651                 if (DEBUG_FILTERS) {
652                     Slog.i(TAG, "Mismatched authority; cap priority to 0;"
653                             + " package: " + packageName
654                             + " activity: " + className
655                             + " origPrio: " + intentFilter.getPriority());
656                 }
657                 intentFilter.setPriority(0);
658                 return;
659             }
660         }
661 
662         // we found matching filter(s); app gets the max priority of all intents
663         int cappedPriority = 0;
664         for (int i = intentListCopy.size() - 1; i >= 0; --i) {
665             cappedPriority = Math.max(cappedPriority,
666                     intentListCopy.get(i).getIntentFilter().getPriority());
667         }
668         if (intentFilter.getPriority() > cappedPriority) {
669             if (DEBUG_FILTERS) {
670                 Slog.i(TAG, "Found matching filter(s);"
671                         + " cap priority to " + cappedPriority + ";"
672                         + " package: " + packageName
673                         + " activity: " + className
674                         + " origPrio: " + intentFilter.getPriority());
675             }
676             intentFilter.setPriority(cappedPriority);
677             return;
678         }
679         // all this for nothing; the requested priority was <= what was on the system
680     }
681 
682     @GuardedBy("mLock")
removeAllComponentsLocked(AndroidPackage pkg, boolean chatty)683     private void removeAllComponentsLocked(AndroidPackage pkg, boolean chatty) {
684         int componentSize;
685         StringBuilder r;
686         int i;
687 
688         componentSize = ArrayUtils.size(pkg.getActivities());
689         r = null;
690         for (i = 0; i < componentSize; i++) {
691             ParsedActivity a = pkg.getActivities().get(i);
692             mActivities.removeActivity(a, "activity");
693             if (DEBUG_REMOVE && chatty) {
694                 if (r == null) {
695                     r = new StringBuilder(256);
696                 } else {
697                     r.append(' ');
698                 }
699                 r.append(a.getName());
700             }
701         }
702         if (DEBUG_REMOVE && chatty) {
703             Log.d(TAG, "  Activities: " + (r == null ? "<NONE>" : r));
704         }
705 
706         componentSize = ArrayUtils.size(pkg.getProviders());
707         r = null;
708         for (i = 0; i < componentSize; i++) {
709             ParsedProvider p = pkg.getProviders().get(i);
710             mProviders.removeProvider(p);
711             if (p.getAuthority() == null) {
712                 // Another content provider with this authority existed when this app was
713                 // installed, so this authority is null. Ignore it as we don't have to
714                 // unregister the provider.
715                 continue;
716             }
717             String[] names = p.getAuthority().split(";");
718             for (int j = 0; j < names.length; j++) {
719                 if (mProvidersByAuthority.get(names[j]) == p) {
720                     mProvidersByAuthority.remove(names[j]);
721                     if (DEBUG_REMOVE && chatty) {
722                         Log.d(TAG, "Unregistered content provider: " + names[j]
723                                 + ", className = " + p.getName() + ", isSyncable = "
724                                 + p.isSyncable());
725                     }
726                 }
727             }
728             if (DEBUG_REMOVE && chatty) {
729                 if (r == null) {
730                     r = new StringBuilder(256);
731                 } else {
732                     r.append(' ');
733                 }
734                 r.append(p.getName());
735             }
736         }
737         if (DEBUG_REMOVE && chatty) {
738             Log.d(TAG, "  Providers: " + (r == null ? "<NONE>" : r));
739         }
740 
741         componentSize = ArrayUtils.size(pkg.getReceivers());
742         r = null;
743         for (i = 0; i < componentSize; i++) {
744             ParsedActivity a = pkg.getReceivers().get(i);
745             mReceivers.removeActivity(a, "receiver");
746             if (DEBUG_REMOVE && chatty) {
747                 if (r == null) {
748                     r = new StringBuilder(256);
749                 } else {
750                     r.append(' ');
751                 }
752                 r.append(a.getName());
753             }
754         }
755         if (DEBUG_REMOVE && chatty) {
756             Log.d(TAG, "  Receivers: " + (r == null ? "<NONE>" : r));
757         }
758 
759         componentSize = ArrayUtils.size(pkg.getServices());
760         r = null;
761         for (i = 0; i < componentSize; i++) {
762             ParsedService s = pkg.getServices().get(i);
763             mServices.removeService(s);
764             if (DEBUG_REMOVE && chatty) {
765                 if (r == null) {
766                     r = new StringBuilder(256);
767                 } else {
768                     r.append(' ');
769                 }
770                 r.append(s.getName());
771             }
772         }
773         if (DEBUG_REMOVE && chatty) {
774             Log.d(TAG, "  Services: " + (r == null ? "<NONE>" : r));
775         }
776     }
777 
778     /** Asserts none of the providers defined in the given package haven't already been defined. */
assertProvidersNotDefined(@onNull AndroidPackage pkg)779     public void assertProvidersNotDefined(@NonNull AndroidPackage pkg)
780             throws PackageManagerException {
781         synchronized (mLock) {
782             final int providersSize = ArrayUtils.size(pkg.getProviders());
783             int i;
784             for (i = 0; i < providersSize; i++) {
785                 ParsedProvider p = pkg.getProviders().get(i);
786                 if (p.getAuthority() != null) {
787                     final String[] names = p.getAuthority().split(";");
788                     for (int j = 0; j < names.length; j++) {
789                         if (mProvidersByAuthority.containsKey(names[j])) {
790                             final ParsedProvider other = mProvidersByAuthority.get(names[j]);
791                             final String otherPackageName =
792                                     (other != null && other.getComponentName() != null)
793                                             ? other.getComponentName().getPackageName() : "?";
794                             // if installing over the same already-installed package,this is ok
795                             if (!otherPackageName.equals(pkg.getPackageName())) {
796                                 throw new PackageManagerException(
797                                         INSTALL_FAILED_CONFLICTING_PROVIDER,
798                                         "Can't install because provider name " + names[j]
799                                                 + " (in package " + pkg.getPackageName()
800                                                 + ") is already used by " + otherPackageName);
801                             }
802                         }
803                     }
804                 }
805             }
806         }
807     }
808 
809     private abstract static class MimeGroupsAwareIntentResolver<F extends Pair<?
810             extends ParsedComponent, ParsedIntentInfo>, R>
811             extends IntentResolver<F, R> {
812         private final ArrayMap<String, F[]> mMimeGroupToFilter = new ArrayMap<>();
813         private boolean mIsUpdatingMimeGroup = false;
814 
815         @NonNull
816         protected final UserManagerService mUserManager;
817 
818         // Default constructor
MimeGroupsAwareIntentResolver(@onNull UserManagerService userManager)819         MimeGroupsAwareIntentResolver(@NonNull UserManagerService userManager) {
820             mUserManager = userManager;
821         }
822 
823         // Copy constructor used in creating snapshots
MimeGroupsAwareIntentResolver(MimeGroupsAwareIntentResolver<F, R> orig, @NonNull UserManagerService userManager)824         MimeGroupsAwareIntentResolver(MimeGroupsAwareIntentResolver<F, R> orig,
825                 @NonNull UserManagerService userManager) {
826             mUserManager = userManager;
827             copyFrom(orig);
828             copyInto(mMimeGroupToFilter, orig.mMimeGroupToFilter);
829             mIsUpdatingMimeGroup = orig.mIsUpdatingMimeGroup;
830         }
831 
832         @Override
addFilter(@ullable PackageDataSnapshot snapshot, F f)833         public void addFilter(@Nullable PackageDataSnapshot snapshot, F f) {
834             IntentFilter intentFilter = getIntentFilter(f);
835             // We assume Computer is available for this class and all subclasses. Because this class
836             // uses subclass method override to handle logic, the Computer parameter must be in the
837             // base, leading to this odd nullability.
838             applyMimeGroups((Computer) snapshot, f);
839             super.addFilter(snapshot, f);
840 
841             if (!mIsUpdatingMimeGroup) {
842                 register_intent_filter(f, intentFilter.mimeGroupsIterator(), mMimeGroupToFilter,
843                         "      MimeGroup: ");
844             }
845         }
846 
847         @Override
removeFilterInternal(F f)848         protected void removeFilterInternal(F f) {
849             IntentFilter intentFilter = getIntentFilter(f);
850             if (!mIsUpdatingMimeGroup) {
851                 unregister_intent_filter(f, intentFilter.mimeGroupsIterator(), mMimeGroupToFilter,
852                         "      MimeGroup: ");
853             }
854 
855             super.removeFilterInternal(f);
856             intentFilter.clearDynamicDataTypes();
857         }
858 
859         /**
860          * Updates MIME group by applying changes to all IntentFilters
861          * that contain the group and repopulating m*ToFilter maps accordingly
862          *
863          * @param packageName package to which MIME group belongs
864          * @param mimeGroup MIME group to update
865          * @return true, if any intent filters were changed due to this update
866          */
updateMimeGroup(@onNull Computer computer, String packageName, String mimeGroup)867         public boolean updateMimeGroup(@NonNull Computer computer, String packageName,
868                 String mimeGroup) {
869             F[] filters = mMimeGroupToFilter.get(mimeGroup);
870             int n = filters != null ? filters.length : 0;
871 
872             mIsUpdatingMimeGroup = true;
873             boolean hasChanges = false;
874             F filter;
875             for (int i = 0; i < n && (filter = filters[i]) != null; i++) {
876                 if (isPackageForFilter(packageName, filter)) {
877                     hasChanges |= updateFilter(computer, filter);
878                 }
879             }
880             mIsUpdatingMimeGroup = false;
881             return hasChanges;
882         }
883 
updateFilter(@onNull Computer computer, F f)884         private boolean updateFilter(@NonNull Computer computer, F f) {
885             IntentFilter filter = getIntentFilter(f);
886             List<String> oldTypes = filter.dataTypes();
887             removeFilter(f);
888             addFilter(computer, f);
889             List<String> newTypes = filter.dataTypes();
890             return !equalLists(oldTypes, newTypes);
891         }
892 
equalLists(List<String> first, List<String> second)893         private boolean equalLists(List<String> first, List<String> second) {
894             if (first == null) {
895                 return second == null;
896             } else if (second == null) {
897                 return false;
898             }
899 
900             if (first.size() != second.size()) {
901                 return false;
902             }
903 
904             Collections.sort(first);
905             Collections.sort(second);
906             return first.equals(second);
907         }
908 
applyMimeGroups(@onNull Computer computer, F f)909         private void applyMimeGroups(@NonNull Computer computer, F f) {
910             IntentFilter filter = getIntentFilter(f);
911 
912             for (int i = filter.countMimeGroups() - 1; i >= 0; i--) {
913                 final PackageStateInternal packageState = computer.getPackageStateInternal(
914                         f.first.getPackageName());
915 
916                 Collection<String> mimeTypes = packageState == null
917                         ? Collections.emptyList() : packageState.getMimeGroups()
918                         .get(filter.getMimeGroup(i));
919 
920                 for (String mimeType : mimeTypes) {
921                     try {
922                         filter.addDynamicDataType(mimeType);
923                     } catch (IntentFilter.MalformedMimeTypeException e) {
924                         if (DEBUG) {
925                             Slog.w(TAG, "Malformed mime type: " + mimeType, e);
926                         }
927                     }
928                 }
929             }
930         }
931 
932         @Override
isFilterStopped(@ullable PackageStateInternal packageState, @UserIdInt int userId)933         protected boolean isFilterStopped(@Nullable PackageStateInternal packageState,
934                 @UserIdInt int userId) {
935             if (!mUserManager.exists(userId)) {
936                 return true;
937             }
938 
939             if (packageState == null || packageState.getPkg() == null) {
940                 return false;
941             }
942 
943             // System apps are never considered stopped for purposes of
944             // filtering, because there may be no way for the user to
945             // actually re-launch them.
946             return !packageState.isSystem()
947                     && packageState.getUserStateOrDefault(userId).isStopped();
948         }
949     }
950 
951     public static class ActivityIntentResolver
952             extends MimeGroupsAwareIntentResolver<Pair<ParsedActivity, ParsedIntentInfo>, ResolveInfo> {
953 
954         @NonNull
955         private UserNeedsBadgingCache mUserNeedsBadging;
956 
957         // Default constructor
ActivityIntentResolver(@onNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)958         ActivityIntentResolver(@NonNull UserManagerService userManager,
959                 @NonNull UserNeedsBadgingCache userNeedsBadgingCache) {
960             super(userManager);
961             mUserNeedsBadging = userNeedsBadgingCache;
962         }
963 
964         // Copy constructor used in creating snapshots
ActivityIntentResolver(@onNull ActivityIntentResolver orig, @NonNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)965         ActivityIntentResolver(@NonNull ActivityIntentResolver orig,
966                 @NonNull UserManagerService userManager,
967                 @NonNull UserNeedsBadgingCache userNeedsBadgingCache) {
968             super(orig, userManager);
969             mActivities.putAll(orig.mActivities);
970             mUserNeedsBadging = userNeedsBadgingCache;
971         }
972 
973         @Override
queryIntent(@onNull PackageDataSnapshot snapshot, Intent intent, String resolvedType, boolean defaultOnly, @UserIdInt int userId)974         public List<ResolveInfo> queryIntent(@NonNull PackageDataSnapshot snapshot, Intent intent,
975                 String resolvedType, boolean defaultOnly, @UserIdInt int userId) {
976             if (!mUserManager.exists(userId)) return null;
977             long flags = (defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0);
978             return super.queryIntent(snapshot, intent, resolvedType, defaultOnly, userId, flags);
979         }
980 
queryIntent(@onNull Computer computer, Intent intent, String resolvedType, long flags, int userId)981         List<ResolveInfo> queryIntent(@NonNull Computer computer, Intent intent,
982                 String resolvedType, long flags, int userId) {
983             if (!mUserManager.exists(userId)) {
984                 return null;
985             }
986             return super.queryIntent(computer, intent, resolvedType,
987                     (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId, flags);
988         }
989 
queryIntentForPackage(@onNull Computer computer, Intent intent, String resolvedType, long flags, List<ParsedActivity> packageActivities, int userId)990         List<ResolveInfo> queryIntentForPackage(@NonNull Computer computer, Intent intent,
991                 String resolvedType, long flags, List<ParsedActivity> packageActivities,
992                 int userId) {
993             if (!mUserManager.exists(userId)) {
994                 return null;
995             }
996             if (packageActivities == null) {
997                 return Collections.emptyList();
998             }
999             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
1000             final int activitiesSize = packageActivities.size();
1001             ArrayList<Pair<ParsedActivity, ParsedIntentInfo>[]> listCut =
1002                     new ArrayList<>(activitiesSize);
1003 
1004             List<ParsedIntentInfo> intentFilters;
1005             for (int i = 0; i < activitiesSize; ++i) {
1006                 ParsedActivity activity = packageActivities.get(i);
1007                 intentFilters = activity.getIntents();
1008                 if (!intentFilters.isEmpty()) {
1009                     Pair<ParsedActivity, ParsedIntentInfo>[] array = newArray(intentFilters.size());
1010                     for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) {
1011                         array[arrayIndex] = Pair.create(activity, intentFilters.get(arrayIndex));
1012                     }
1013                     listCut.add(array);
1014                 }
1015             }
1016             return super.queryIntentFromList(computer, intent, resolvedType,
1017                     defaultOnly, listCut, userId, flags);
1018         }
1019 
addActivity(@onNull Computer computer, ParsedActivity a, String type, List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents)1020         protected void addActivity(@NonNull Computer computer, ParsedActivity a, String type,
1021                 List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents) {
1022             mActivities.put(a.getComponentName(), a);
1023             if (DEBUG_SHOW_INFO) {
1024                 Log.v(TAG, "  " + type + ":");
1025                 Log.v(TAG, "    Class=" + a.getName());
1026             }
1027             final int intentsSize = a.getIntents().size();
1028             for (int j = 0; j < intentsSize; j++) {
1029                 ParsedIntentInfo intent = a.getIntents().get(j);
1030                 IntentFilter intentFilter = intent.getIntentFilter();
1031                 if (newIntents != null && "activity".equals(type)) {
1032                     newIntents.add(Pair.create(a, intent));
1033                 }
1034                 if (DEBUG_SHOW_INFO) {
1035                     Log.v(TAG, "    IntentFilter:");
1036                     intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
1037                 }
1038                 if (!intentFilter.debugCheck()) {
1039                     Log.w(TAG, "==> For Activity " + a.getName());
1040                 }
1041                 addFilter(computer, Pair.create(a, intent));
1042             }
1043         }
1044 
removeActivity(ParsedActivity a, String type)1045         protected void removeActivity(ParsedActivity a, String type) {
1046             mActivities.remove(a.getComponentName());
1047             if (DEBUG_SHOW_INFO) {
1048                 Log.v(TAG, "  " + type + ":");
1049                 Log.v(TAG, "    Class=" + a.getName());
1050             }
1051             final int intentsSize = a.getIntents().size();
1052             for (int j = 0; j < intentsSize; j++) {
1053                 ParsedIntentInfo intent = a.getIntents().get(j);
1054                 IntentFilter intentFilter = intent.getIntentFilter();
1055                 if (DEBUG_SHOW_INFO) {
1056                     Log.v(TAG, "    IntentFilter:");
1057                     intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
1058                 }
1059                 removeFilter(Pair.create(a, intent));
1060             }
1061         }
1062 
1063         @Override
allowFilterResult(Pair<ParsedActivity, ParsedIntentInfo> filter, List<ResolveInfo> dest)1064         protected boolean allowFilterResult(Pair<ParsedActivity, ParsedIntentInfo> filter,
1065                 List<ResolveInfo> dest) {
1066             for (int i = dest.size() - 1; i >= 0; --i) {
1067                 ActivityInfo destAi = dest.get(i).activityInfo;
1068                 if (Objects.equals(destAi.name, filter.first.getName())
1069                         && Objects.equals(destAi.packageName, filter.first.getPackageName())) {
1070                     return false;
1071                 }
1072             }
1073             return true;
1074         }
1075 
1076         @Override
newArray(int size)1077         protected Pair<ParsedActivity, ParsedIntentInfo>[] newArray(int size) {
1078             //noinspection unchecked
1079             return (Pair<ParsedActivity, ParsedIntentInfo>[]) new Pair<?, ?>[size];
1080         }
1081 
1082         @Override
isPackageForFilter(String packageName, Pair<ParsedActivity, ParsedIntentInfo> info)1083         protected boolean isPackageForFilter(String packageName,
1084                 Pair<ParsedActivity, ParsedIntentInfo> info) {
1085             return packageName.equals(info.first.getPackageName());
1086         }
1087 
log(String reason, ParsedIntentInfo info, int match, int userId)1088         private void log(String reason, ParsedIntentInfo info, int match,
1089                 int userId) {
1090             Slog.w(TAG, reason
1091                     + "; match: "
1092                     + DebugUtils.flagsToString(IntentFilter.class, "MATCH_", match)
1093                     + "; userId: " + userId
1094                     + "; intent info: " + info);
1095         }
1096 
1097         @Override
newResult(@onNull Computer computer, Pair<ParsedActivity, ParsedIntentInfo> pair, int match, int userId, long customFlags)1098         protected ResolveInfo newResult(@NonNull Computer computer,
1099                 Pair<ParsedActivity, ParsedIntentInfo> pair, int match, int userId,
1100                 long customFlags) {
1101             ParsedActivity activity = pair.first;
1102             ParsedIntentInfo info = pair.second;
1103             IntentFilter intentFilter = info.getIntentFilter();
1104 
1105             if (!mUserManager.exists(userId)) {
1106                 if (DEBUG) {
1107                     log("User doesn't exist", info, match, userId);
1108                 }
1109                 return null;
1110             }
1111 
1112             final PackageStateInternal packageState =
1113                     computer.getPackageStateInternal(activity.getPackageName());
1114             if (packageState == null || packageState.getPkg() == null
1115                     || !PackageStateUtils.isEnabledAndMatches(packageState, activity, customFlags,
1116                     userId)) {
1117                 if (DEBUG) {
1118                     log("!PackageManagerInternal.isEnabledAndMatches; flags="
1119                             + DebugUtils.flagsToString(PackageManager.class, "MATCH_", customFlags),
1120                             info, match, userId);
1121                 }
1122                 return null;
1123             }
1124             final PackageUserStateInternal userState = packageState.getUserStateOrDefault(userId);
1125             ActivityInfo ai = PackageInfoUtils.generateActivityInfo(packageState.getPkg(), activity,
1126                     customFlags, userState, userId, packageState);
1127             if (ai == null) {
1128                 if (DEBUG) {
1129                     log("Failed to create ActivityInfo based on " + activity, info, match,
1130                             userId);
1131                 }
1132                 return null;
1133             }
1134             final boolean matchExplicitlyVisibleOnly =
1135                     (customFlags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0;
1136             final boolean matchVisibleToInstantApp =
1137                     (customFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
1138             final boolean componentVisible =
1139                     matchVisibleToInstantApp
1140                     && intentFilter.isVisibleToInstantApp()
1141                     && (!matchExplicitlyVisibleOnly
1142                             || intentFilter.isExplicitlyVisibleToInstantApp());
1143             final boolean matchInstantApp = (customFlags & PackageManager.MATCH_INSTANT) != 0;
1144             // throw out filters that aren't visible to ephemeral apps
1145             if (matchVisibleToInstantApp && !(componentVisible || userState.isInstantApp())) {
1146                 if (DEBUG) {
1147                     log("Filter(s) not visible to ephemeral apps"
1148                             + "; matchVisibleToInstantApp=" + matchVisibleToInstantApp
1149                             + "; matchInstantApp=" + matchInstantApp
1150                             + "; info.isVisibleToInstantApp()="
1151                                     + intentFilter.isVisibleToInstantApp()
1152                             + "; matchExplicitlyVisibleOnly=" + matchExplicitlyVisibleOnly
1153                             + "; info.isExplicitlyVisibleToInstantApp()="
1154                                     + intentFilter.isExplicitlyVisibleToInstantApp(),
1155                             info, match, userId);
1156                 }
1157                 return null;
1158             }
1159             // throw out instant app filters if we're not explicitly requesting them
1160             if (!matchInstantApp && userState.isInstantApp()) {
1161                 if (DEBUG) {
1162                     log("Instant app filter is not explicitly requested", info, match, userId);
1163                 }
1164                 return null;
1165             }
1166             // throw out instant app filters if updates are available; will trigger
1167             // instant app resolution
1168             if (userState.isInstantApp() && packageState.isUpdateAvailable()) {
1169                 if (DEBUG) {
1170                     log("Instant app update is available", info, match, userId);
1171                 }
1172                 return null;
1173             }
1174             final ResolveInfo res =
1175                     new ResolveInfo(intentFilter.hasCategory(Intent.CATEGORY_BROWSABLE));
1176             res.activityInfo = ai;
1177             if ((customFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
1178                 res.filter = intentFilter;
1179             }
1180             res.handleAllWebDataURI = intentFilter.handleAllWebDataURI();
1181             res.priority = intentFilter.getPriority();
1182             // TODO(b/135203078): This field was unwritten and does nothing
1183 //            res.preferredOrder = pkg.getPreferredOrder();
1184             //System.out.println("Result: " + res.activityInfo.className +
1185             //                   " = " + res.priority);
1186             res.match = match;
1187             res.isDefault = info.isHasDefault();
1188             res.labelRes = info.getLabelRes();
1189             res.nonLocalizedLabel = info.getNonLocalizedLabel();
1190             if (mUserNeedsBadging.get(userId)) {
1191                 res.noResourceId = true;
1192             } else {
1193                 res.icon = info.getIcon();
1194             }
1195             res.iconResourceId = info.getIcon();
1196             res.system = res.activityInfo.applicationInfo.isSystemApp();
1197             res.isInstantAppAvailable = userState.isInstantApp();
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