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