• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
4 import static android.content.pm.PackageManager.GET_ACTIVITIES;
5 import static android.content.pm.PackageManager.GET_CONFIGURATIONS;
6 import static android.content.pm.PackageManager.GET_GIDS;
7 import static android.content.pm.PackageManager.GET_INSTRUMENTATION;
8 import static android.content.pm.PackageManager.GET_INTENT_FILTERS;
9 import static android.content.pm.PackageManager.GET_META_DATA;
10 import static android.content.pm.PackageManager.GET_PERMISSIONS;
11 import static android.content.pm.PackageManager.GET_PROVIDERS;
12 import static android.content.pm.PackageManager.GET_RECEIVERS;
13 import static android.content.pm.PackageManager.GET_RESOLVED_FILTER;
14 import static android.content.pm.PackageManager.GET_SERVICES;
15 import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
16 import static android.content.pm.PackageManager.GET_SIGNATURES;
17 import static android.content.pm.PackageManager.GET_URI_PERMISSION_PATTERNS;
18 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
19 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
20 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
21 import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
22 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
23 import static android.content.pm.PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
24 import static android.content.pm.PackageManager.SIGNATURE_MATCH;
25 import static android.content.pm.PackageManager.SIGNATURE_NEITHER_SIGNED;
26 import static android.content.pm.PackageManager.SIGNATURE_NO_MATCH;
27 import static android.content.pm.PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
28 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
29 import static android.os.Build.VERSION_CODES.KITKAT;
30 import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
31 import static android.os.Build.VERSION_CODES.M;
32 import static android.os.Build.VERSION_CODES.N;
33 import static java.util.Arrays.asList;
34 
35 import android.Manifest;
36 import android.annotation.Nullable;
37 import android.annotation.UserIdInt;
38 import android.content.ComponentName;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.IntentFilter;
42 import android.content.IntentFilter.AuthorityEntry;
43 import android.content.IntentSender;
44 import android.content.pm.ApplicationInfo;
45 import android.content.pm.ComponentInfo;
46 import android.content.pm.FeatureInfo;
47 import android.content.pm.IPackageDataObserver;
48 import android.content.pm.IPackageDeleteObserver;
49 import android.content.pm.PackageInfo;
50 import android.content.pm.PackageManager;
51 import android.content.pm.PackageManager.NameNotFoundException;
52 import android.content.pm.PackageParser;
53 import android.content.pm.PackageParser.Component;
54 import android.content.pm.PackageParser.Package;
55 import android.content.pm.PackageStats;
56 import android.content.pm.PackageUserState;
57 import android.content.pm.PermissionGroupInfo;
58 import android.content.pm.PermissionInfo;
59 import android.content.pm.ResolveInfo;
60 import android.content.pm.Signature;
61 import android.content.res.Resources;
62 import android.graphics.drawable.Drawable;
63 import android.net.Uri;
64 import android.os.Binder;
65 import android.os.Build;
66 import android.os.Build.VERSION;
67 import android.os.PatternMatcher;
68 import android.os.PersistableBundle;
69 import android.os.Process;
70 import android.os.RemoteException;
71 import android.os.UserHandle;
72 import android.util.ArraySet;
73 import android.util.Pair;
74 import com.google.common.base.Preconditions;
75 import com.google.common.collect.HashMultimap;
76 import com.google.common.collect.Multimap;
77 import java.util.ArrayList;
78 import java.util.Arrays;
79 import java.util.Collections;
80 import java.util.Comparator;
81 import java.util.HashMap;
82 import java.util.HashSet;
83 import java.util.Iterator;
84 import java.util.LinkedHashMap;
85 import java.util.List;
86 import java.util.Map;
87 import java.util.Objects;
88 import java.util.Set;
89 import java.util.TreeMap;
90 import org.robolectric.RuntimeEnvironment;
91 import org.robolectric.annotation.Implementation;
92 import org.robolectric.annotation.Implements;
93 import org.robolectric.annotation.Resetter;
94 import org.robolectric.util.ReflectionHelpers;
95 import org.robolectric.util.TempDirectory;
96 
97 @Implements(PackageManager.class)
98 public class ShadowPackageManager {
99 
100   static Map<String, Boolean> permissionRationaleMap = new HashMap<>();
101   static List<FeatureInfo> systemAvailableFeatures = new ArrayList<>();
102   static final List<String> systemSharedLibraryNames = new ArrayList<>();
103   static final Map<String, PackageInfo> packageInfos = new LinkedHashMap<>();
104   static final Map<String, Package> packages = new LinkedHashMap<>();
105   private static Map<String, PackageInfo> packageArchiveInfo = new HashMap<>();
106   static final Map<String, PackageStats> packageStatsMap = new HashMap<>();
107   static final Map<String, String> packageInstallerMap = new HashMap<>();
108   static final Map<Integer, String[]> packagesForUid = new HashMap<>();
109   static final Map<String, Integer> uidForPackage = new HashMap<>();
110   static final Map<Integer, String> namesForUid = new HashMap<>();
111   static final Map<Integer, Integer> verificationResults = new HashMap<>();
112   static final Map<Integer, Long> verificationTimeoutExtension = new HashMap<>();
113   static final Map<String, String> currentToCanonicalNames = new HashMap<>();
114   static final Map<ComponentName, ComponentState> componentList = new LinkedHashMap<>();
115   static final Map<ComponentName, Drawable> drawableList = new LinkedHashMap<>();
116   static final Map<String, Drawable> applicationIcons = new HashMap<>();
117   static final Map<String, Drawable> unbadgedApplicationIcons = new HashMap<>();
118   static final Map<String, Boolean> systemFeatureList = new LinkedHashMap<>();
119   static final Map<IntentFilterWrapper, ComponentName> preferredActivities = new LinkedHashMap<>();
120   static final Map<Pair<String, Integer>, Drawable> drawables = new LinkedHashMap<>();
121   static final Map<String, Integer> applicationEnabledSettingMap = new HashMap<>();
122   static Map<String, PermissionInfo> extraPermissions = new HashMap<>();
123   static Map<String, PermissionGroupInfo> extraPermissionGroups = new HashMap<>();
124   public static Map<String, Resources> resources = new HashMap<>();
125   private static final Map<Intent, List<ResolveInfo>> resolveInfoForIntent =
126       new TreeMap<>(new IntentComparator());
127   private static Set<String> deletedPackages = new HashSet<>();
128   static Map<String, IPackageDeleteObserver> pendingDeleteCallbacks = new HashMap<>();
129   static Set<String> hiddenPackages = new HashSet<>();
130   static Multimap<Integer, String> sequenceNumberChangedPackagesMap = HashMultimap.create();
131   static boolean canRequestPackageInstalls = false;
132 
133   /**
134    * Settings for a particular package.
135    *
136    * <p>This class mirrors {@link com.android.server.pm.PackageSetting}, which is used by {@link
137    * PackageManager}.
138    */
139   public static class PackageSetting {
140 
141     /** Whether the package is suspended in {@link PackageManager}. */
142     private boolean suspended = false;
143 
144     /** The message to be displayed to the user when they try to launch the app. */
145     private String dialogMessage = null;
146 
147     /** An optional {@link PersistableBundle} shared with the app. */
148     private PersistableBundle suspendedAppExtras = null;
149 
150     /** An optional {@link PersistableBundle} shared with the launcher. */
151     private PersistableBundle suspendedLauncherExtras = null;
152 
PackageSetting()153     public PackageSetting() {}
154 
PackageSetting(PackageSetting that)155     public PackageSetting(PackageSetting that) {
156       this.suspended = that.suspended;
157       this.dialogMessage = that.dialogMessage;
158       this.suspendedAppExtras = deepCopyNullablePersistableBundle(that.suspendedAppExtras);
159       this.suspendedLauncherExtras =
160           deepCopyNullablePersistableBundle(that.suspendedLauncherExtras);
161     }
162 
163     /**
164      * Sets the suspension state of the package.
165      *
166      * <p>If {@code suspended} is false, {@code dialogMessage}, {@code appExtras}, and {@code
167      * launcherExtras} will be ignored.
168      */
setSuspended( boolean suspended, String dialogMessage, PersistableBundle appExtras, PersistableBundle launcherExtras)169     void setSuspended(
170         boolean suspended,
171         String dialogMessage,
172         PersistableBundle appExtras,
173         PersistableBundle launcherExtras) {
174       this.suspended = suspended;
175       this.dialogMessage = suspended ? dialogMessage : null;
176       this.suspendedAppExtras = suspended ? deepCopyNullablePersistableBundle(appExtras) : null;
177       this.suspendedLauncherExtras =
178           suspended ? deepCopyNullablePersistableBundle(launcherExtras) : null;
179     }
180 
isSuspended()181     public boolean isSuspended() {
182       return suspended;
183     }
184 
getDialogMessage()185     public String getDialogMessage() {
186       return dialogMessage;
187     }
188 
getSuspendedAppExtras()189     public PersistableBundle getSuspendedAppExtras() {
190       return suspendedAppExtras;
191     }
192 
getSuspendedLauncherExtras()193     public PersistableBundle getSuspendedLauncherExtras() {
194       return suspendedLauncherExtras;
195     }
196 
deepCopyNullablePersistableBundle(PersistableBundle bundle)197     private static PersistableBundle deepCopyNullablePersistableBundle(PersistableBundle bundle) {
198       return bundle == null ? null : bundle.deepCopy();
199     }
200   }
201 
202   static final Map<String, PackageSetting> packageSettings = new HashMap<>();
203 
204   // From com.android.server.pm.PackageManagerService.compareSignatures().
compareSignature(Signature[] signatures1, Signature[] signatures2)205   static int compareSignature(Signature[] signatures1, Signature[] signatures2) {
206     if (signatures1 == null) {
207       return (signatures2 == null) ? SIGNATURE_NEITHER_SIGNED : SIGNATURE_FIRST_NOT_SIGNED;
208     }
209     if (signatures2 == null) {
210       return SIGNATURE_SECOND_NOT_SIGNED;
211     }
212     if (signatures1.length != signatures2.length) {
213       return SIGNATURE_NO_MATCH;
214     }
215     HashSet<Signature> signatures1set = new HashSet<>(asList(signatures1));
216     HashSet<Signature> signatures2set = new HashSet<>(asList(signatures2));
217     return signatures1set.equals(signatures2set) ? SIGNATURE_MATCH : SIGNATURE_NO_MATCH;
218   }
219 
resolvePackageName(String packageName, ComponentName componentName)220   static String resolvePackageName(String packageName, ComponentName componentName) {
221     String classString = componentName.getClassName();
222     int index = classString.indexOf('.');
223     if (index == -1) {
224       classString = packageName + "." + classString;
225     } else if (index == 0) {
226       classString = packageName + classString;
227     }
228     return classString;
229   }
230 
231   // TODO(christianw): reconcile with ParallelUniverse.setUpPackageStorage
setUpPackageStorage(ApplicationInfo applicationInfo)232   private static void setUpPackageStorage(ApplicationInfo applicationInfo) {
233     TempDirectory tempDirectory = RuntimeEnvironment.getTempDirectory();
234 
235     if (applicationInfo.sourceDir == null) {
236       applicationInfo.sourceDir =
237           tempDirectory
238               .createIfNotExists(applicationInfo.packageName + "-sourceDir")
239               .toAbsolutePath()
240               .toString();
241     }
242 
243     if (applicationInfo.dataDir == null) {
244       applicationInfo.dataDir =
245           tempDirectory
246               .createIfNotExists(applicationInfo.packageName + "-dataDir")
247               .toAbsolutePath()
248               .toString();
249     }
250     if (applicationInfo.publicSourceDir == null) {
251       applicationInfo.publicSourceDir = applicationInfo.sourceDir;
252     }
253     if (RuntimeEnvironment.getApiLevel() >= N) {
254       applicationInfo.credentialProtectedDataDir =
255           tempDirectory.createIfNotExists("userDataDir").toAbsolutePath().toString();
256       applicationInfo.deviceProtectedDataDir =
257           tempDirectory.createIfNotExists("deviceDataDir").toAbsolutePath().toString();
258     }
259   }
260 
261   /**
262    * Sets extra resolve infos for an intent.
263    *
264    * <p>Those entries are added to whatever might be in the manifest already.
265    *
266    * <p>Note that all resolve infos will have {@link ResolveInfo#isDefault} field set to {@code
267    * true} to allow their resolution for implicit intents. If this is not what you want, then you
268    * still have the reference to those ResolveInfos, and you can set the field back to {@code
269    * false}.
270    */
setResolveInfosForIntent(Intent intent, List<ResolveInfo> info)271   public void setResolveInfosForIntent(Intent intent, List<ResolveInfo> info) {
272     resolveInfoForIntent.remove(intent);
273     for (ResolveInfo resolveInfo : info) {
274       addResolveInfoForIntent(intent, resolveInfo);
275     }
276   }
277 
278   /**
279    * @deprecated please use {@link #setResolveInfosForIntent} or {@link
280    *     #addResolveInfoForIntent(Intent, ResolveInfo)} instead.
281    */
282   @Deprecated
addResolveInfoForIntent(Intent intent, List<ResolveInfo> info)283   public void addResolveInfoForIntent(Intent intent, List<ResolveInfo> info) {
284     setResolveInfosForIntent(intent, info);
285   }
286 
287   /**
288    * Adds extra resolve info for an intent.
289    *
290    * <p>Note that this resolve info will have {@link ResolveInfo#isDefault} field set to {@code
291    * true} to allow its resolution for implicit intents. If this is not what you want, then please
292    * use {@link #addResolveInfoForIntentNoDefaults} instead.
293    */
addResolveInfoForIntent(Intent intent, ResolveInfo info)294   public void addResolveInfoForIntent(Intent intent, ResolveInfo info) {
295     info.isDefault = true;
296     ComponentInfo[] componentInfos =
297         new ComponentInfo[] {
298           info.activityInfo,
299           info.serviceInfo,
300           Build.VERSION.SDK_INT >= KITKAT ? info.providerInfo : null
301         };
302     for (ComponentInfo component : componentInfos) {
303       if (component != null && component.applicationInfo != null) {
304         component.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
305       }
306     }
307     addResolveInfoForIntentNoDefaults(intent, info);
308   }
309 
310   /**
311    * Adds the {@code info} as {@link ResolveInfo} for the intent but without applying any default
312    * values.
313    *
314    * <p>In particular it will not make the {@link ResolveInfo#isDefault} field {@code true}, that
315    * means that this resolve info will not resolve for {@link Intent#resolveActivity} and {@link
316    * Context#startActivity}.
317    */
addResolveInfoForIntentNoDefaults(Intent intent, ResolveInfo info)318   public void addResolveInfoForIntentNoDefaults(Intent intent, ResolveInfo info) {
319     Preconditions.checkNotNull(info);
320     List<ResolveInfo> infoList = resolveInfoForIntent.get(intent);
321     if (infoList == null) {
322       infoList = new ArrayList<>();
323       resolveInfoForIntent.put(intent, infoList);
324     }
325     infoList.add(info);
326   }
327 
removeResolveInfosForIntent(Intent intent, String packageName)328   public void removeResolveInfosForIntent(Intent intent, String packageName) {
329     List<ResolveInfo> infoList = resolveInfoForIntent.get(intent);
330     if (infoList == null) {
331       infoList = new ArrayList<>();
332       resolveInfoForIntent.put(intent, infoList);
333     }
334 
335     for (Iterator<ResolveInfo> iterator = infoList.iterator(); iterator.hasNext(); ) {
336       ResolveInfo resolveInfo = iterator.next();
337       if (getPackageName(resolveInfo).equals(packageName)) {
338         iterator.remove();
339       }
340     }
341   }
342 
getPackageName(ResolveInfo resolveInfo)343   private static String getPackageName(ResolveInfo resolveInfo) {
344     if (resolveInfo.resolvePackageName != null) {
345       return resolveInfo.resolvePackageName;
346     } else if (resolveInfo.activityInfo != null) {
347       return resolveInfo.activityInfo.packageName;
348     } else if (resolveInfo.serviceInfo != null) {
349       return resolveInfo.serviceInfo.packageName;
350     } else if (resolveInfo.providerInfo != null) {
351       return resolveInfo.providerInfo.packageName;
352     }
353     throw new IllegalStateException(
354         "Could not find package name for ResolveInfo " + resolveInfo.toString());
355   }
356 
addActivityIcon(ComponentName component, Drawable drawable)357   public void addActivityIcon(ComponentName component, Drawable drawable) {
358     drawableList.put(component, drawable);
359   }
360 
addActivityIcon(Intent intent, Drawable drawable)361   public void addActivityIcon(Intent intent, Drawable drawable) {
362     drawableList.put(intent.getComponent(), drawable);
363   }
364 
setApplicationIcon(String packageName, Drawable drawable)365   public void setApplicationIcon(String packageName, Drawable drawable) {
366     applicationIcons.put(packageName, drawable);
367   }
368 
setUnbadgedApplicationIcon(String packageName, Drawable drawable)369   public void setUnbadgedApplicationIcon(String packageName, Drawable drawable) {
370     unbadgedApplicationIcons.put(packageName, drawable);
371   }
372 
373   /**
374    * Return the flags set in call to {@link
375    * android.app.ApplicationPackageManager#setComponentEnabledSetting(ComponentName, int, int)}.
376    *
377    * @param componentName The component name.
378    * @return The flags.
379    */
getComponentEnabledSettingFlags(ComponentName componentName)380   public int getComponentEnabledSettingFlags(ComponentName componentName) {
381     ComponentState state = componentList.get(componentName);
382     return state != null ? state.flags : 0;
383   }
384 
385   /**
386    * Installs a package with the {@link PackageManager}.
387    *
388    * <p>In order to create PackageInfo objects in a valid state please use {@link
389    * androidx.test.core.content.pm.PackageInfoBuilder}.
390    *
391    * <p>This method automatically simulates instalation of a package in the system, so it adds a
392    * flag {@link ApplicationInfo#FLAG_INSTALLED} to the application info and makes sure it exits. It
393    * will update applicationInfo in package components as well.
394    *
395    * <p>If you don't want the package to be installed, use {@link #addPackageNoDefaults} instead.
396    */
installPackage(PackageInfo packageInfo)397   public void installPackage(PackageInfo packageInfo) {
398     ApplicationInfo appInfo = packageInfo.applicationInfo;
399     if (appInfo == null) {
400       appInfo = new ApplicationInfo();
401       appInfo.packageName = packageInfo.packageName;
402       packageInfo.applicationInfo = appInfo;
403     }
404     appInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
405     ComponentInfo[][] componentInfoArrays =
406         new ComponentInfo[][] {
407           packageInfo.activities,
408           packageInfo.services,
409           packageInfo.providers,
410           packageInfo.receivers,
411         };
412     for (ComponentInfo[] componentInfos : componentInfoArrays) {
413       if (componentInfos == null) {
414         continue;
415       }
416       for (ComponentInfo componentInfo : componentInfos) {
417         if (componentInfo.applicationInfo == null) {
418           componentInfo.applicationInfo = appInfo;
419         }
420         componentInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
421       }
422     }
423     addPackageNoDefaults(packageInfo);
424   }
425 
426   /**
427    * Adds a package to the {@link PackageManager}, but doesn't set any default values on it.
428    *
429    * <p>Right now it will not set {@link ApplicationInfo#FLAG_INSTALLED} flag on its application, so
430    * if not set explicitly, it will be treated as not installed.
431    */
addPackageNoDefaults(PackageInfo packageInfo)432   public void addPackageNoDefaults(PackageInfo packageInfo) {
433     PackageStats packageStats = new PackageStats(packageInfo.packageName);
434     addPackage(packageInfo, packageStats);
435   }
436 
437   /**
438    * Installs a package with its stats with the {@link PackageManager}.
439    *
440    * <p>This method doesn't add any defaults to the {@code packageInfo} parameters. You should make
441    * sure it is valid (see {@link #installPackage(PackageInfo)}).
442    */
addPackage(PackageInfo packageInfo, PackageStats packageStats)443   public synchronized void addPackage(PackageInfo packageInfo, PackageStats packageStats) {
444     Preconditions.checkArgument(packageInfo.packageName.equals(packageStats.packageName));
445 
446     packageInfos.put(packageInfo.packageName, packageInfo);
447     packageStatsMap.put(packageInfo.packageName, packageStats);
448 
449     packageSettings.put(packageInfo.packageName, new PackageSetting());
450 
451     applicationEnabledSettingMap.put(
452         packageInfo.packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
453     if (packageInfo.applicationInfo != null) {
454       namesForUid.put(packageInfo.applicationInfo.uid, packageInfo.packageName);
455     }
456   }
457 
458   /** @deprecated Use {@link #installPackage(PackageInfo)} instead. */
459   @Deprecated
addPackage(String packageName)460   public void addPackage(String packageName) {
461     PackageInfo packageInfo = new PackageInfo();
462     packageInfo.packageName = packageName;
463 
464     ApplicationInfo applicationInfo = new ApplicationInfo();
465 
466     applicationInfo.packageName = packageName;
467     // TODO: setUpPackageStorage should be in installPackage but we need to fix all tests first
468     setUpPackageStorage(applicationInfo);
469     packageInfo.applicationInfo = applicationInfo;
470     installPackage(packageInfo);
471   }
472 
473   /** This method is getting renamed to {link {@link #installPackage}. */
474   @Deprecated
addPackage(PackageInfo packageInfo)475   public void addPackage(PackageInfo packageInfo) {
476     installPackage(packageInfo);
477   }
478 
479   /**
480    * Testing API allowing to retrieve internal package representation.
481    *
482    * <p>This will allow to modify the package in a way visible to Robolectric, as this is
483    * Robolectric's internal full package representation.
484    *
485    * <p>Note that maybe a better way is to just modify the test manifest to make those modifications
486    * in a standard way.
487    *
488    * <p>Retrieving package info using {@link PackageManager#getPackageInfo} / {@link
489    * PackageManager#getApplicationInfo} will return defensive copies that will be stripped out of
490    * information according to provided flags. Don't use it to modify Robolectric state.
491    */
getInternalMutablePackageInfo(String packageName)492   public PackageInfo getInternalMutablePackageInfo(String packageName) {
493     return packageInfos.get(packageName);
494   }
495 
496   /** @deprecated Use {@link #getInternalMutablePackageInfo} instead. It has better name. */
497   @Deprecated
getPackageInfoForTesting(String packageName)498   public PackageInfo getPackageInfoForTesting(String packageName) {
499     return getInternalMutablePackageInfo(packageName);
500   }
501 
addPermissionInfo(PermissionInfo permissionInfo)502   public void addPermissionInfo(PermissionInfo permissionInfo) {
503     extraPermissions.put(permissionInfo.name, permissionInfo);
504   }
505 
506   /**
507    * Adds {@code packageName} to the list of changed packages for the particular {@code
508    * sequenceNumber}.
509    *
510    * @param sequenceNumber has to be >= 0
511    * @param packageName name of the package that was changed
512    */
addChangedPackage(int sequenceNumber, String packageName)513   public void addChangedPackage(int sequenceNumber, String packageName) {
514     if (sequenceNumber < 0) {
515       return;
516     }
517     sequenceNumberChangedPackagesMap.put(sequenceNumber, packageName);
518   }
519 
520   /**
521    * Allows overriding or adding permission-group elements. These would be otherwise specified by
522    * either (the
523    * system)[https://developer.android.com/guide/topics/permissions/requesting.html#perm-groups] or
524    * by (the app
525    * itself)[https://developer.android.com/guide/topics/manifest/permission-group-element.html], as
526    * part of its manifest
527    *
528    * <p>{@link android.content.pm.PackageParser.PermissionGroup}s added through this method have
529    * precedence over those specified with the same name by one of the aforementioned methods.
530    *
531    * @see PackageManager#getAllPermissionGroups(int)
532    * @see PackageManager#getPermissionGroupInfo(String, int)
533    */
addPermissionGroupInfo(PermissionGroupInfo permissionGroupInfo)534   public void addPermissionGroupInfo(PermissionGroupInfo permissionGroupInfo) {
535     extraPermissionGroups.put(permissionGroupInfo.name, permissionGroupInfo);
536   }
537 
removePackage(String packageName)538   public void removePackage(String packageName) {
539     packages.remove(packageName);
540     packageInfos.remove(packageName);
541 
542     packageSettings.remove(packageName);
543   }
544 
setSystemFeature(String name, boolean supported)545   public void setSystemFeature(String name, boolean supported) {
546     systemFeatureList.put(name, supported);
547   }
548 
addDrawableResolution(String packageName, int resourceId, Drawable drawable)549   public void addDrawableResolution(String packageName, int resourceId, Drawable drawable) {
550     drawables.put(new Pair(packageName, resourceId), drawable);
551   }
552 
setNameForUid(int uid, String name)553   public void setNameForUid(int uid, String name) {
554     namesForUid.put(uid, name);
555   }
556 
setPackagesForCallingUid(String... packagesForCallingUid)557   public void setPackagesForCallingUid(String... packagesForCallingUid) {
558     packagesForUid.put(Binder.getCallingUid(), packagesForCallingUid);
559     for (String packageName : packagesForCallingUid) {
560       uidForPackage.put(packageName, Binder.getCallingUid());
561     }
562   }
563 
setPackagesForUid(int uid, String... packagesForCallingUid)564   public void setPackagesForUid(int uid, String... packagesForCallingUid) {
565     packagesForUid.put(uid, packagesForCallingUid);
566     for (String packageName : packagesForCallingUid) {
567       uidForPackage.put(packageName, uid);
568     }
569   }
570 
571   @Implementation
572   @Nullable
getPackagesForUid(int uid)573   protected String[] getPackagesForUid(int uid) {
574     return packagesForUid.get(uid);
575   }
576 
setPackageArchiveInfo(String archiveFilePath, PackageInfo packageInfo)577   public void setPackageArchiveInfo(String archiveFilePath, PackageInfo packageInfo) {
578     packageArchiveInfo.put(archiveFilePath, packageInfo);
579   }
580 
getVerificationResult(int id)581   public int getVerificationResult(int id) {
582     Integer result = verificationResults.get(id);
583     if (result == null) {
584       // 0 isn't a "valid" result, so we can check for the case when verification isn't
585       // called, if needed
586       return 0;
587     }
588     return result;
589   }
590 
getVerificationExtendedTimeout(int id)591   public long getVerificationExtendedTimeout(int id) {
592     Long result = verificationTimeoutExtension.get(id);
593     if (result == null) {
594       return 0;
595     }
596     return result;
597   }
598 
setShouldShowRequestPermissionRationale(String permission, boolean show)599   public void setShouldShowRequestPermissionRationale(String permission, boolean show) {
600     permissionRationaleMap.put(permission, show);
601   }
602 
addSystemAvailableFeature(FeatureInfo featureInfo)603   public void addSystemAvailableFeature(FeatureInfo featureInfo) {
604     systemAvailableFeatures.add(featureInfo);
605   }
606 
clearSystemAvailableFeatures()607   public void clearSystemAvailableFeatures() {
608     systemAvailableFeatures.clear();
609   }
610 
611   /** Adds a value to be returned by {@link PackageManager#getSystemSharedLibraryNames()}. */
addSystemSharedLibraryName(String name)612   public void addSystemSharedLibraryName(String name) {
613     systemSharedLibraryNames.add(name);
614   }
615 
616   /** Clears the values returned by {@link PackageManager#getSystemSharedLibraryNames()}. */
clearSystemSharedLibraryNames()617   public void clearSystemSharedLibraryNames() {
618     systemSharedLibraryNames.clear();
619   }
620 
addCurrentToCannonicalName(String currentName, String canonicalName)621   public void addCurrentToCannonicalName(String currentName, String canonicalName) {
622     currentToCanonicalNames.put(currentName, canonicalName);
623   }
624 
625   /**
626    * Sets if the {@link PackageManager} is allowed to request package installs through package
627    * installer.
628    */
setCanRequestPackageInstalls(boolean canRequestPackageInstalls)629   public void setCanRequestPackageInstalls(boolean canRequestPackageInstalls) {
630     ShadowPackageManager.canRequestPackageInstalls = canRequestPackageInstalls;
631   }
632 
633   @Implementation(minSdk = N)
queryBroadcastReceiversAsUser( Intent intent, int flags, UserHandle userHandle)634   protected List<ResolveInfo> queryBroadcastReceiversAsUser(
635       Intent intent, int flags, UserHandle userHandle) {
636     return null;
637   }
638 
639   @Implementation(minSdk = JELLY_BEAN_MR1)
queryBroadcastReceivers( Intent intent, int flags, @UserIdInt int userId)640   protected List<ResolveInfo> queryBroadcastReceivers(
641       Intent intent, int flags, @UserIdInt int userId) {
642     return null;
643   }
644 
645   @Implementation
getPackageArchiveInfo(String archiveFilePath, int flags)646   protected PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
647     List<PackageInfo> result = new ArrayList<>();
648     for (PackageInfo packageInfo : packageInfos.values()) {
649       if (applicationEnabledSettingMap.get(packageInfo.packageName)
650               != COMPONENT_ENABLED_STATE_DISABLED
651           || (flags & MATCH_UNINSTALLED_PACKAGES) == MATCH_UNINSTALLED_PACKAGES) {
652         result.add(packageInfo);
653       }
654     }
655 
656     List<PackageInfo> packages = result;
657     for (PackageInfo aPackage : packages) {
658       ApplicationInfo appInfo = aPackage.applicationInfo;
659       if (appInfo != null && archiveFilePath.equals(appInfo.sourceDir)) {
660         return aPackage;
661       }
662     }
663     return null;
664   }
665 
666   @Implementation
freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer)667   protected void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer) {}
668 
669   @Implementation
freeStorage(long freeStorageSize, IntentSender pi)670   protected void freeStorage(long freeStorageSize, IntentSender pi) {}
671 
672   /**
673    * Runs the callbacks pending from calls to {@link PackageManager#deletePackage(String,
674    * IPackageDeleteObserver, int)}
675    */
doPendingUninstallCallbacks()676   public void doPendingUninstallCallbacks() {
677     boolean hasDeletePackagesPermission = false;
678     String[] requestedPermissions =
679         packageInfos.get(RuntimeEnvironment.application.getPackageName()).requestedPermissions;
680     if (requestedPermissions != null) {
681       for (String permission : requestedPermissions) {
682         if (Manifest.permission.DELETE_PACKAGES.equals(permission)) {
683           hasDeletePackagesPermission = true;
684           break;
685         }
686       }
687     }
688 
689     for (String packageName : pendingDeleteCallbacks.keySet()) {
690       int resultCode = PackageManager.DELETE_FAILED_INTERNAL_ERROR;
691 
692       PackageInfo removed = packageInfos.get(packageName);
693       if (hasDeletePackagesPermission && removed != null) {
694         packageInfos.remove(packageName);
695 
696         packageSettings.remove(packageName);
697 
698         deletedPackages.add(packageName);
699         resultCode = PackageManager.DELETE_SUCCEEDED;
700       }
701 
702       try {
703         pendingDeleteCallbacks.get(packageName).packageDeleted(packageName, resultCode);
704       } catch (RemoteException e) {
705         throw new RuntimeException(e);
706       }
707     }
708     pendingDeleteCallbacks.clear();
709   }
710 
711   /**
712    * Returns package names successfully deleted with {@link PackageManager#deletePackage(String,
713    * IPackageDeleteObserver, int)} Note that like real {@link PackageManager} the calling context
714    * must have {@link android.Manifest.permission#DELETE_PACKAGES} permission set.
715    */
getDeletedPackages()716   public Set<String> getDeletedPackages() {
717     return deletedPackages;
718   }
719 
queryOverriddenIntents(Intent intent, int flags)720   protected List<ResolveInfo> queryOverriddenIntents(Intent intent, int flags) {
721     List<ResolveInfo> overrides = resolveInfoForIntent.get(intent);
722     if (overrides == null) {
723       return Collections.emptyList();
724     }
725     List<ResolveInfo> result = new ArrayList<>(overrides.size());
726     for (ResolveInfo resolveInfo : overrides) {
727       result.add(ShadowResolveInfo.newResolveInfo(resolveInfo));
728     }
729     return result;
730   }
731 
732   /**
733    * Internal use only.
734    *
735    * @param appPackage
736    */
addPackageInternal(Package appPackage)737   public void addPackageInternal(Package appPackage) {
738     int flags =
739         GET_ACTIVITIES
740             | GET_RECEIVERS
741             | GET_SERVICES
742             | GET_PROVIDERS
743             | GET_INSTRUMENTATION
744             | GET_INTENT_FILTERS
745             | GET_SIGNATURES
746             | GET_RESOLVED_FILTER
747             | GET_META_DATA
748             | GET_GIDS
749             | MATCH_DISABLED_COMPONENTS
750             | GET_SHARED_LIBRARY_FILES
751             | GET_URI_PERMISSION_PATTERNS
752             | GET_PERMISSIONS
753             | MATCH_UNINSTALLED_PACKAGES
754             | GET_CONFIGURATIONS
755             | MATCH_DISABLED_UNTIL_USED_COMPONENTS
756             | MATCH_DIRECT_BOOT_UNAWARE
757             | MATCH_DIRECT_BOOT_AWARE;
758 
759     packages.put(appPackage.packageName, appPackage);
760     PackageInfo packageInfo;
761     if (RuntimeEnvironment.getApiLevel() >= M) {
762       packageInfo =
763           PackageParser.generatePackageInfo(
764               appPackage,
765               new int[] {0},
766               flags,
767               0,
768               0,
769               new HashSet<String>(),
770               new PackageUserState());
771     } else if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP_MR1) {
772       packageInfo =
773           ReflectionHelpers.callStaticMethod(
774               PackageParser.class,
775               "generatePackageInfo",
776               ReflectionHelpers.ClassParameter.from(Package.class, appPackage),
777               ReflectionHelpers.ClassParameter.from(int[].class, new int[] {0}),
778               ReflectionHelpers.ClassParameter.from(int.class, flags),
779               ReflectionHelpers.ClassParameter.from(long.class, 0L),
780               ReflectionHelpers.ClassParameter.from(long.class, 0L),
781               ReflectionHelpers.ClassParameter.from(ArraySet.class, new ArraySet<>()),
782               ReflectionHelpers.ClassParameter.from(
783                   PackageUserState.class, new PackageUserState()));
784     } else if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR1) {
785       packageInfo =
786           ReflectionHelpers.callStaticMethod(
787               PackageParser.class,
788               "generatePackageInfo",
789               ReflectionHelpers.ClassParameter.from(Package.class, appPackage),
790               ReflectionHelpers.ClassParameter.from(int[].class, new int[] {0}),
791               ReflectionHelpers.ClassParameter.from(int.class, flags),
792               ReflectionHelpers.ClassParameter.from(long.class, 0L),
793               ReflectionHelpers.ClassParameter.from(long.class, 0L),
794               ReflectionHelpers.ClassParameter.from(HashSet.class, new HashSet<>()),
795               ReflectionHelpers.ClassParameter.from(
796                   PackageUserState.class, new PackageUserState()));
797     } else {
798       packageInfo =
799           ReflectionHelpers.callStaticMethod(
800               PackageParser.class,
801               "generatePackageInfo",
802               ReflectionHelpers.ClassParameter.from(Package.class, appPackage),
803               ReflectionHelpers.ClassParameter.from(int[].class, new int[] {0}),
804               ReflectionHelpers.ClassParameter.from(int.class, flags),
805               ReflectionHelpers.ClassParameter.from(long.class, 0L),
806               ReflectionHelpers.ClassParameter.from(long.class, 0L),
807               ReflectionHelpers.ClassParameter.from(HashSet.class, new HashSet<>()));
808     }
809 
810     packageInfo.applicationInfo.uid = Process.myUid();
811     packageInfo.applicationInfo.dataDir =
812         RuntimeEnvironment.getTempDirectory()
813             .createIfNotExists(packageInfo.packageName + "-dataDir")
814             .toString();
815     installPackage(packageInfo);
816   }
817 
818   public static class IntentComparator implements Comparator<Intent> {
819 
820     @Override
compare(Intent i1, Intent i2)821     public int compare(Intent i1, Intent i2) {
822       if (i1 == null && i2 == null) return 0;
823       if (i1 == null && i2 != null) return -1;
824       if (i1 != null && i2 == null) return 1;
825       if (i1.equals(i2)) return 0;
826       String action1 = i1.getAction();
827       String action2 = i2.getAction();
828       if (action1 == null && action2 != null) return -1;
829       if (action1 != null && action2 == null) return 1;
830       if (action1 != null && action2 != null) {
831         if (!action1.equals(action2)) {
832           return action1.compareTo(action2);
833         }
834       }
835       Uri data1 = i1.getData();
836       Uri data2 = i2.getData();
837       if (data1 == null && data2 != null) return -1;
838       if (data1 != null && data2 == null) return 1;
839       if (data1 != null && data2 != null) {
840         if (!data1.equals(data2)) {
841           return data1.compareTo(data2);
842         }
843       }
844       ComponentName component1 = i1.getComponent();
845       ComponentName component2 = i2.getComponent();
846       if (component1 == null && component2 != null) return -1;
847       if (component1 != null && component2 == null) return 1;
848       if (component1 != null && component2 != null) {
849         if (!component1.equals(component2)) {
850           return component1.compareTo(component2);
851         }
852       }
853       String package1 = i1.getPackage();
854       String package2 = i2.getPackage();
855       if (package1 == null && package2 != null) return -1;
856       if (package1 != null && package2 == null) return 1;
857       if (package1 != null && package2 != null) {
858         if (!package1.equals(package2)) {
859           return package1.compareTo(package2);
860         }
861       }
862       Set<String> categories1 = i1.getCategories();
863       Set<String> categories2 = i2.getCategories();
864       if (categories1 == null) return categories2 == null ? 0 : -1;
865       if (categories2 == null) return 1;
866       if (categories1.size() > categories2.size()) return 1;
867       if (categories1.size() < categories2.size()) return -1;
868       String[] array1 = categories1.toArray(new String[0]);
869       String[] array2 = categories2.toArray(new String[0]);
870       Arrays.sort(array1);
871       Arrays.sort(array2);
872       for (int i = 0; i < array1.length; ++i) {
873         int val = array1[i].compareTo(array2[i]);
874         if (val != 0) return val;
875       }
876       return 0;
877     }
878   }
879 
880   /**
881    * This class wraps {@link IntentFilter} so it has reasonable {@link #equals} and {@link
882    * #hashCode} methods.
883    */
884   protected static class IntentFilterWrapper {
885     final IntentFilter filter;
886     private final HashSet<String> actions = new HashSet<>();
887     private HashSet<String> categories = new HashSet<>();
888     private HashSet<String> dataSchemes = new HashSet<>();
889     private HashSet<String> dataSchemeSpecificParts = new HashSet<>();
890     private HashSet<String> dataAuthorities = new HashSet<>();
891     private HashSet<String> dataPaths = new HashSet<>();
892     private HashSet<String> dataTypes = new HashSet<>();
893 
IntentFilterWrapper(IntentFilter filter)894     public IntentFilterWrapper(IntentFilter filter) {
895       this.filter = filter;
896       if (filter == null) {
897         return;
898       }
899       for (int i = 0; i < filter.countActions(); i++) {
900         actions.add(filter.getAction(i));
901       }
902       for (int i = 0; i < filter.countCategories(); i++) {
903         categories.add(filter.getCategory(i));
904       }
905       for (int i = 0; i < filter.countDataAuthorities(); i++) {
906         AuthorityEntry dataAuthority = filter.getDataAuthority(i);
907         dataAuthorities.add(dataAuthority.getHost() + ":" + dataAuthority.getPort());
908       }
909       for (int i = 0; i < filter.countDataPaths(); i++) {
910         PatternMatcher dataPath = filter.getDataPath(i);
911         dataPaths.add(dataPath.toString());
912       }
913       for (int i = 0; i < filter.countDataSchemes(); i++) {
914         dataSchemes.add(filter.getDataScheme(i));
915       }
916       if (VERSION.SDK_INT >= KITKAT) {
917         for (int i = 0; i < filter.countDataSchemeSpecificParts(); i++) {
918           dataSchemeSpecificParts.add(filter.getDataSchemeSpecificPart(i).toString());
919         }
920       }
921       for (int i = 0; i < filter.countDataTypes(); i++) {
922         dataTypes.add(filter.getDataType(i));
923       }
924     }
925 
926     @Override
equals(Object o)927     public boolean equals(Object o) {
928       if (this == o) {
929         return true;
930       }
931       if (!(o instanceof IntentFilterWrapper)) {
932         return false;
933       }
934       IntentFilterWrapper that = (IntentFilterWrapper) o;
935       if (filter == null && that.filter == null) {
936         return true;
937       }
938       if (filter == null || that.filter == null) {
939         return false;
940       }
941       return filter.getPriority() == that.filter.getPriority()
942           && Objects.equals(actions, that.actions)
943           && Objects.equals(categories, that.categories)
944           && Objects.equals(dataSchemes, that.dataSchemes)
945           && Objects.equals(dataSchemeSpecificParts, that.dataSchemeSpecificParts)
946           && Objects.equals(dataAuthorities, that.dataAuthorities)
947           && Objects.equals(dataPaths, that.dataPaths)
948           && Objects.equals(dataTypes, that.dataTypes);
949     }
950 
951     @Override
hashCode()952     public int hashCode() {
953       return Objects.hash(
954           filter == null ? null : filter.getPriority(),
955           actions,
956           categories,
957           dataSchemes,
958           dataSchemeSpecificParts,
959           dataAuthorities,
960           dataPaths,
961           dataTypes);
962     }
963 
getFilter()964     public IntentFilter getFilter() {
965       return filter;
966     }
967   }
968 
969   /** Compares {@link ResolveInfo}, where better is bigger. */
970   static class ResolveInfoComparator implements Comparator<ResolveInfo> {
971 
972     private final HashSet<ComponentName> preferredComponents;
973 
ResolveInfoComparator(HashSet<ComponentName> preferredComponents)974     public ResolveInfoComparator(HashSet<ComponentName> preferredComponents) {
975       this.preferredComponents = preferredComponents;
976     }
977 
978     @Override
compare(ResolveInfo o1, ResolveInfo o2)979     public int compare(ResolveInfo o1, ResolveInfo o2) {
980       if (o1 == null && o2 == null) {
981         return 0;
982       }
983       if (o1 == null) {
984         return -1;
985       }
986       if (o2 == null) {
987         return 1;
988       }
989       boolean o1isPreferred = isPreferred(o1);
990       boolean o2isPreferred = isPreferred(o2);
991       if (o1isPreferred != o2isPreferred) {
992         return Boolean.compare(o1isPreferred, o2isPreferred);
993       }
994       if (o1.preferredOrder != o2.preferredOrder) {
995         return Integer.compare(o1.preferredOrder, o2.preferredOrder);
996       }
997       if (o1.priority != o2.priority) {
998         return Integer.compare(o1.priority, o2.priority);
999       }
1000       return 0;
1001     }
1002 
isPreferred(ResolveInfo resolveInfo)1003     private boolean isPreferred(ResolveInfo resolveInfo) {
1004       return resolveInfo.activityInfo != null
1005           && resolveInfo.activityInfo.packageName != null
1006           && resolveInfo.activityInfo.name != null
1007           && preferredComponents.contains(
1008               new ComponentName(
1009                   resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name));
1010     }
1011   }
1012 
1013   protected static class ComponentState {
1014     public int newState;
1015     public int flags;
1016 
ComponentState(int newState, int flags)1017     public ComponentState(int newState, int flags) {
1018       this.newState = newState;
1019       this.flags = flags;
1020     }
1021   }
1022 
1023   /**
1024    * Get list of intent filters defined for given activity.
1025    *
1026    * @param componentName Name of the activity whose intent filters are to be retrieved
1027    * @return the activity's intent filters
1028    */
getIntentFiltersForActivity(ComponentName componentName)1029   public List<IntentFilter> getIntentFiltersForActivity(ComponentName componentName)
1030       throws NameNotFoundException {
1031     return getIntentFiltersForComponent(getAppPackage(componentName).activities, componentName);
1032   }
1033 
1034   /**
1035    * Get list of intent filters defined for given service.
1036    *
1037    * @param componentName Name of the service whose intent filters are to be retrieved
1038    * @return the service's intent filters
1039    */
getIntentFiltersForService(ComponentName componentName)1040   public List<IntentFilter> getIntentFiltersForService(ComponentName componentName)
1041       throws NameNotFoundException {
1042     return getIntentFiltersForComponent(getAppPackage(componentName).services, componentName);
1043   }
1044 
1045   /**
1046    * Get list of intent filters defined for given receiver.
1047    *
1048    * @param componentName Name of the receiver whose intent filters are to be retrieved
1049    * @return the receiver's intent filters
1050    */
getIntentFiltersForReceiver(ComponentName componentName)1051   public List<IntentFilter> getIntentFiltersForReceiver(ComponentName componentName)
1052       throws NameNotFoundException {
1053     return getIntentFiltersForComponent(getAppPackage(componentName).receivers, componentName);
1054   }
1055 
getIntentFiltersForComponent( List<? extends Component> components, ComponentName componentName)1056   private static List<IntentFilter> getIntentFiltersForComponent(
1057       List<? extends Component> components, ComponentName componentName)
1058       throws NameNotFoundException {
1059     for (Component component : components) {
1060       if (component.getComponentName().equals(componentName)) {
1061         return component.intents;
1062       }
1063     }
1064     throw new NameNotFoundException("unknown component " + componentName);
1065   }
1066 
getAppPackage(ComponentName componentName)1067   private static Package getAppPackage(ComponentName componentName) throws NameNotFoundException {
1068     Package appPackage = packages.get(componentName.getPackageName());
1069     if (appPackage == null) {
1070       throw new NameNotFoundException("unknown package " + componentName.getPackageName());
1071     }
1072     return appPackage;
1073   }
1074 
1075   /**
1076    * Returns the current {@link PackageSetting} of {@code packageName}.
1077    *
1078    * <p>If {@code packageName} is not present in this {@link ShadowPackageManager}, this method will
1079    * return null.
1080    */
getPackageSetting(String packageName)1081   public PackageSetting getPackageSetting(String packageName) {
1082     PackageSetting setting = packageSettings.get(packageName);
1083     return setting == null ? null : new PackageSetting(setting);
1084   }
1085 
1086   @Resetter
reset()1087   public static void reset() {
1088     permissionRationaleMap.clear();
1089     systemAvailableFeatures.clear();
1090     systemSharedLibraryNames.clear();
1091     packageInfos.clear();
1092     packages.clear();
1093     packageArchiveInfo.clear();
1094     packageStatsMap.clear();
1095     packageInstallerMap.clear();
1096     packagesForUid.clear();
1097     uidForPackage.clear();
1098     namesForUid.clear();
1099     verificationResults.clear();
1100     verificationTimeoutExtension.clear();
1101     currentToCanonicalNames.clear();
1102     componentList.clear();
1103     drawableList.clear();
1104     applicationIcons.clear();
1105     unbadgedApplicationIcons.clear();
1106     systemFeatureList.clear();
1107     preferredActivities.clear();
1108     drawables.clear();
1109     applicationEnabledSettingMap.clear();
1110     extraPermissions.clear();
1111     extraPermissionGroups.clear();
1112     resources.clear();
1113     resolveInfoForIntent.clear();
1114     deletedPackages.clear();
1115     pendingDeleteCallbacks.clear();
1116     hiddenPackages.clear();
1117     sequenceNumberChangedPackagesMap.clear();
1118 
1119     packageSettings.clear();
1120   }
1121 }
1122