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