1 package org.robolectric.shadows;
2 
3 import static android.content.IntentFilter.MATCH_CATEGORY_MASK;
4 import static android.content.pm.ApplicationInfo.FLAG_INSTALLED;
5 import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
6 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
7 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
8 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
9 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
10 import static android.content.pm.PackageManager.DONT_KILL_APP;
11 import static android.content.pm.PackageManager.GET_ACTIVITIES;
12 import static android.content.pm.PackageManager.GET_META_DATA;
13 import static android.content.pm.PackageManager.GET_PROVIDERS;
14 import static android.content.pm.PackageManager.GET_RECEIVERS;
15 import static android.content.pm.PackageManager.GET_RESOLVED_FILTER;
16 import static android.content.pm.PackageManager.GET_SERVICES;
17 import static android.content.pm.PackageManager.GET_SIGNATURES;
18 import static android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES;
19 import static android.content.pm.PackageManager.MATCH_ALL;
20 import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
21 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
22 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
23 import static android.content.pm.PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
24 import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
25 import static android.os.Build.VERSION_CODES.M;
26 import static android.os.Build.VERSION_CODES.N;
27 import static android.os.Build.VERSION_CODES.O;
28 import static android.os.Build.VERSION_CODES.O_MR1;
29 import static android.os.Build.VERSION_CODES.P;
30 import static android.os.Build.VERSION_CODES.Q;
31 import static android.os.Build.VERSION_CODES.R;
32 import static android.os.Build.VERSION_CODES.S;
33 import static android.os.Build.VERSION_CODES.S_V2;
34 import static android.os.Build.VERSION_CODES.TIRAMISU;
35 import static com.google.common.base.Preconditions.checkNotNull;
36 import static org.robolectric.annotation.GetInstallerPackageNameMode.Mode.REALISTIC;
37 import static org.robolectric.util.reflector.Reflector.reflector;
38 
39 import android.Manifest.permission;
40 import android.annotation.DrawableRes;
41 import android.annotation.NonNull;
42 import android.annotation.Nullable;
43 import android.annotation.RequiresPermission;
44 import android.annotation.StringRes;
45 import android.annotation.UserIdInt;
46 import android.app.ApplicationPackageManager;
47 import android.app.admin.DevicePolicyManager;
48 import android.content.ComponentName;
49 import android.content.Context;
50 import android.content.Intent;
51 import android.content.IntentFilter;
52 import android.content.IntentSender;
53 import android.content.pm.ActivityInfo;
54 import android.content.pm.ApplicationInfo;
55 import android.content.pm.ChangedPackages;
56 import android.content.pm.ComponentInfo;
57 import android.content.pm.FeatureInfo;
58 import android.content.pm.IPackageDataObserver;
59 import android.content.pm.IPackageDeleteObserver;
60 import android.content.pm.IPackageStatsObserver;
61 import android.content.pm.InstrumentationInfo;
62 import android.content.pm.IntentFilterVerificationInfo;
63 import android.content.pm.ModuleInfo;
64 import android.content.pm.PackageInfo;
65 import android.content.pm.PackageItemInfo;
66 import android.content.pm.PackageManager;
67 import android.content.pm.PackageManager.ComponentEnabledSetting;
68 import android.content.pm.PackageManager.ComponentInfoFlags;
69 import android.content.pm.PackageManager.NameNotFoundException;
70 import android.content.pm.PackageManager.OnPermissionsChangedListener;
71 import android.content.pm.PackageManager.PackageInfoFlags;
72 import android.content.pm.PackageManager.ResolveInfoFlags;
73 import android.content.pm.PackageStats;
74 import android.content.pm.PermissionGroupInfo;
75 import android.content.pm.PermissionInfo;
76 import android.content.pm.ProviderInfo;
77 import android.content.pm.ResolveInfo;
78 import android.content.pm.ServiceInfo;
79 import android.content.pm.Signature;
80 import android.content.pm.VerifierDeviceIdentity;
81 import android.content.res.AssetManager;
82 import android.content.res.Resources;
83 import android.graphics.drawable.Drawable;
84 import android.net.Uri;
85 import android.os.Build;
86 import android.os.Build.VERSION;
87 import android.os.Build.VERSION_CODES;
88 import android.os.Handler;
89 import android.os.Looper;
90 import android.os.Parcel;
91 import android.os.PersistableBundle;
92 import android.os.RemoteException;
93 import android.os.UserHandle;
94 import android.os.storage.VolumeInfo;
95 import android.telecom.TelecomManager;
96 import android.util.Log;
97 import android.util.Pair;
98 import com.google.common.base.Function;
99 import com.google.common.base.Preconditions;
100 import com.google.common.base.Splitter;
101 import com.google.common.collect.ImmutableList;
102 import com.google.common.collect.Sets;
103 import java.io.File;
104 import java.util.ArrayList;
105 import java.util.Arrays;
106 import java.util.Collections;
107 import java.util.HashMap;
108 import java.util.HashSet;
109 import java.util.Iterator;
110 import java.util.List;
111 import java.util.Map;
112 import java.util.Objects;
113 import java.util.Set;
114 import java.util.SortedMap;
115 import java.util.concurrent.Executor;
116 import java.util.function.BiConsumer;
117 import java.util.function.Consumer;
118 import org.robolectric.RuntimeEnvironment;
119 import org.robolectric.annotation.ClassName;
120 import org.robolectric.annotation.GetInstallerPackageNameMode;
121 import org.robolectric.annotation.HiddenApi;
122 import org.robolectric.annotation.Implementation;
123 import org.robolectric.annotation.Implements;
124 import org.robolectric.annotation.RealObject;
125 import org.robolectric.config.ConfigurationRegistry;
126 import org.robolectric.util.reflector.Accessor;
127 import org.robolectric.util.reflector.Direct;
128 import org.robolectric.util.reflector.ForType;
129 
130 /** Shadow for {@link ApplicationPackageManager}. */
131 @Implements(value = ApplicationPackageManager.class, isInAndroidSdk = false)
132 public class ShadowApplicationPackageManager extends ShadowPackageManager {
133   /** Package name of the Android platform. */
134   private static final String PLATFORM_PACKAGE_NAME = "android";
135 
136   /** MIME type of Android Packages (APKs). */
137   private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
138 
139   /** {@link Uri} scheme of installed apps. */
140   private static final String PACKAGE_SCHEME = "package";
141 
142   public static final String PERMISSION_CONTROLLER_PACKAGE_NAME =
143       "org.robolectric.permissioncontroller";
144 
145   @RealObject private ApplicationPackageManager realObject;
146   private final List<String> clearedApplicationUserDataPackages = new ArrayList<>();
147   // A map of UserIDs to default browsers.
148   private final HashMap<Integer, String> defaultBrowsers = new HashMap<>();
149 
150   @Implementation
getInstalledPackages(int flags)151   public List<PackageInfo> getInstalledPackages(int flags) {
152     return getInstalledPackages((long) flags);
153   }
154 
155   @Implementation(minSdk = TIRAMISU)
getInstalledPackages( @lassName"android.content.pm.PackageManager$PackageInfoFlags") Object flags)156   protected List<PackageInfo> getInstalledPackages(
157       @ClassName("android.content.pm.PackageManager$PackageInfoFlags") Object flags) {
158     return getInstalledPackages(((PackageInfoFlags) flags).getValue());
159   }
160 
getInstalledPackages(long flags)161   private List<PackageInfo> getInstalledPackages(long flags) {
162     List<PackageInfo> result = new ArrayList<>();
163     synchronized (lock) {
164       Set<String> packageNames = null;
165       if ((flags & MATCH_UNINSTALLED_PACKAGES) == 0) {
166         packageNames = packageInfos.keySet();
167       } else {
168         packageNames = Sets.union(packageInfos.keySet(), deletedPackages);
169       }
170       for (String packageName : packageNames) {
171         try {
172           PackageInfo packageInfo = getPackageInfo(packageName, flags);
173           result.add(packageInfo);
174         } catch (NameNotFoundException e) {
175           Log.i(TAG, String.format("Package %s filtered out: %s", packageName, e.getMessage()));
176         }
177       }
178     }
179     return result;
180   }
181 
182   @Implementation(minSdk = Q)
getInstalledModules(int flags)183   protected List<ModuleInfo> getInstalledModules(int flags) {
184     synchronized (lock) {
185       List<ModuleInfo> result = new ArrayList<>();
186       for (String moduleName : moduleInfos.keySet()) {
187         try {
188           ModuleInfo moduleInfo = (ModuleInfo) getModuleInfo(moduleName, flags);
189           result.add(moduleInfo);
190         } catch (NameNotFoundException e) {
191           Log.i(TAG, String.format("Module %s filtered out: %s", moduleName, e.getMessage()));
192         }
193       }
194       return result;
195     }
196   }
197 
198   @Implementation(minSdk = Q)
getModuleInfo( String packageName, int flags)199   protected @ClassName("android.content.pm.ModuleInfo") Object getModuleInfo(
200       String packageName, int flags) throws NameNotFoundException {
201     synchronized (lock) {
202       // Double checks that the respective package matches and is not disabled
203       getPackageInfo(packageName, flags);
204       Object info = moduleInfos.get(packageName);
205       if (info == null) {
206         throw new NameNotFoundException("Module: " + packageName + " is not installed.");
207       }
208 
209       return info;
210     }
211   }
212 
213   @Implementation
getActivityInfo(ComponentName component, int flags)214   protected ActivityInfo getActivityInfo(ComponentName component, int flags)
215       throws NameNotFoundException {
216     return getComponentInfo(
217         component,
218         flags,
219         packageInfo -> packageInfo.activities,
220         resolveInfo -> resolveInfo.activityInfo,
221         ActivityInfo::new);
222   }
223 
getComponentInfo( ComponentName component, int flags, Function<PackageInfo, T[]> componentsInPackage, Function<ResolveInfo, T> componentInResolveInfo, Function<T, T> copyConstructor)224   private <T extends ComponentInfo> T getComponentInfo(
225       ComponentName component,
226       int flags,
227       Function<PackageInfo, T[]> componentsInPackage,
228       Function<ResolveInfo, T> componentInResolveInfo,
229       Function<T, T> copyConstructor)
230       throws NameNotFoundException {
231     String activityName = component.getClassName();
232     String packageName = component.getPackageName();
233     PackageInfo packageInfo = getInternalMutablePackageInfo(packageName);
234     T result = null;
235     ApplicationInfo appInfo = null;
236     // search in the manifest
237     if (packageInfo != null) {
238       if (packageInfo.applicationInfo != null) {
239         appInfo = packageInfo.applicationInfo;
240       }
241       T[] components = componentsInPackage.apply(packageInfo);
242       if (components != null) {
243         for (T activity : components) {
244           if (activityName.equals(activity.name)) {
245             result = copyConstructor.apply(activity);
246             break;
247           }
248         }
249       }
250     }
251     if (result == null) {
252       // look in the registered intents
253       outer:
254       for (List<ResolveInfo> listOfResolveInfo : resolveInfoForIntent.values()) {
255         for (ResolveInfo resolveInfo : listOfResolveInfo) {
256           T info = componentInResolveInfo.apply(resolveInfo);
257           if (isValidComponentInfo(info)
258               && component.equals(new ComponentName(info.applicationInfo.packageName, info.name))) {
259             result = copyConstructor.apply(info);
260             if (appInfo == null) {
261               // we found valid app info in the resolve info. Use it.
262               appInfo = result.applicationInfo;
263             }
264             break outer;
265           }
266         }
267       }
268     }
269     if (result == null) {
270       throw new NameNotFoundException("Component not found: " + component);
271     }
272     if (appInfo == null) {
273       appInfo = new ApplicationInfo();
274       appInfo.packageName = packageName;
275       appInfo.flags = ApplicationInfo.FLAG_INSTALLED;
276     } else {
277       appInfo = new ApplicationInfo(appInfo);
278     }
279     result.applicationInfo = appInfo;
280     applyFlagsToComponentInfo(result, flags);
281     return result;
282   }
283 
284   @Implementation
hasSystemFeature(String name)285   protected boolean hasSystemFeature(String name) {
286     return systemFeatureList.containsKey(name) ? systemFeatureList.get(name) : false;
287   }
288 
289   @Implementation
getComponentEnabledSetting(ComponentName componentName)290   protected int getComponentEnabledSetting(ComponentName componentName) {
291     ComponentState state = componentList.get(componentName);
292     return state != null ? state.newState : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
293   }
294 
295   @Implementation
getNameForUid(int uid)296   protected @Nullable String getNameForUid(int uid) {
297     return namesForUid.get(uid);
298   }
299 
300   @Implementation
301   @Override
getPackagesForUid(int uid)302   protected @Nullable String[] getPackagesForUid(int uid) {
303     String[] packageNames = packagesForUid.get(uid);
304     if (packageNames != null) {
305       return packageNames;
306     }
307 
308     Set<String> results = new HashSet<>();
309     synchronized (lock) {
310       for (PackageInfo packageInfo : packageInfos.values()) {
311         if (packageInfo.applicationInfo != null && packageInfo.applicationInfo.uid == uid) {
312           results.add(packageInfo.packageName);
313         }
314       }
315     }
316 
317     return results.isEmpty() ? null : results.toArray(new String[results.size()]);
318   }
319 
320   @Implementation
getApplicationEnabledSetting(String packageName)321   protected int getApplicationEnabledSetting(String packageName) {
322     synchronized (lock) {
323       if (!packageInfos.containsKey(packageName)) {
324         throw new IllegalArgumentException("Package doesn't exist: " + packageName);
325       }
326     }
327 
328     return applicationEnabledSettingMap.get(packageName);
329   }
330 
331   @Implementation
getProviderInfo(ComponentName component, int flags)332   protected ProviderInfo getProviderInfo(ComponentName component, int flags)
333       throws NameNotFoundException {
334     return getComponentInfo(
335         component,
336         flags,
337         packageInfo -> packageInfo.providers,
338         resolveInfo -> resolveInfo.providerInfo,
339         ProviderInfo::new);
340   }
341 
342   @Implementation
setComponentEnabledSetting(ComponentName componentName, int newState, int flags)343   protected void setComponentEnabledSetting(ComponentName componentName, int newState, int flags) {
344     componentList.put(componentName, new ComponentState(newState, flags));
345   }
346 
347   @Implementation(minSdk = TIRAMISU)
setComponentEnabledSettings(List<ComponentEnabledSetting> settings)348   protected void setComponentEnabledSettings(List<ComponentEnabledSetting> settings) {
349     for (ComponentEnabledSetting setting : settings) {
350       componentList.put(
351           setting.getComponentName(),
352           new ComponentState(setting.getEnabledState(), setting.getEnabledFlags()));
353     }
354   }
355 
356   @Implementation(minSdk = Q)
setSyntheticAppDetailsActivityEnabled(String packageName, boolean enabled)357   protected void setSyntheticAppDetailsActivityEnabled(String packageName, boolean enabled) {
358     ComponentName componentName =
359         new ComponentName(packageName, PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME);
360     setComponentEnabledSetting(
361         componentName,
362         enabled ? COMPONENT_ENABLED_STATE_DEFAULT : COMPONENT_ENABLED_STATE_DISABLED,
363         DONT_KILL_APP);
364   }
365 
366   @Implementation(minSdk = Q)
getSyntheticAppDetailsActivityEnabled(String packageName)367   protected boolean getSyntheticAppDetailsActivityEnabled(String packageName) {
368     ComponentName componentName =
369         new ComponentName(packageName, PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME);
370     int state = getComponentEnabledSetting(componentName);
371     return state == COMPONENT_ENABLED_STATE_ENABLED || state == COMPONENT_ENABLED_STATE_DEFAULT;
372   }
373 
374   @Implementation
setApplicationEnabledSetting(String packageName, int newState, int flags)375   protected void setApplicationEnabledSetting(String packageName, int newState, int flags) {
376     applicationEnabledSettingMap.put(packageName, newState);
377   }
378 
379   @Implementation
resolveActivity(Intent intent, int flags)380   protected ResolveInfo resolveActivity(Intent intent, int flags) {
381     List<ResolveInfo> candidates = queryIntentActivities(intent, flags);
382     if (candidates.isEmpty()) {
383       return null;
384     }
385     if (candidates.size() == 1) {
386       return candidates.get(0);
387     }
388     ResolveInfo persistentPreferredResolveInfo =
389         resolvePreferredActivity(intent, candidates, persistentPreferredActivities);
390     if (persistentPreferredResolveInfo != null) {
391       return persistentPreferredResolveInfo;
392     }
393     ResolveInfo preferredResolveInfo =
394         resolvePreferredActivity(intent, candidates, preferredActivities);
395     if (preferredResolveInfo != null) {
396       return preferredResolveInfo;
397     }
398     if (!shouldShowActivityChooser) {
399       return candidates.get(0);
400     }
401     ResolveInfo c1 = candidates.get(0);
402     ResolveInfo c2 = candidates.get(1);
403     if (c1.preferredOrder == c2.preferredOrder
404         && isValidComponentInfo(c1.activityInfo)
405         && isValidComponentInfo(c2.activityInfo)) {
406       // When the top pick is as good as the second and is not preferred explicitly show the
407       // chooser
408       ResolveInfo result = new ResolveInfo();
409       result.activityInfo = new ActivityInfo();
410       result.activityInfo.name = "ActivityResolver";
411       result.activityInfo.packageName = "android";
412       result.activityInfo.applicationInfo = new ApplicationInfo();
413       result.activityInfo.applicationInfo.flags = FLAG_INSTALLED | FLAG_SYSTEM;
414       result.activityInfo.applicationInfo.packageName = "android";
415       return result;
416     } else {
417       return c1;
418     }
419   }
420 
resolvePreferredActivity( Intent intent, List<ResolveInfo> candidates, SortedMap<ComponentName, List<IntentFilter>> preferredActivities)421   private ResolveInfo resolvePreferredActivity(
422       Intent intent,
423       List<ResolveInfo> candidates,
424       SortedMap<ComponentName, List<IntentFilter>> preferredActivities) {
425     preferredActivities = mapForPackage(preferredActivities, intent.getPackage());
426     for (ResolveInfo candidate : candidates) {
427       ActivityInfo activityInfo = candidate.activityInfo;
428       if (!isValidComponentInfo(activityInfo)) {
429         continue;
430       }
431       ComponentName candidateName =
432           new ComponentName(activityInfo.applicationInfo.packageName, activityInfo.name);
433       List<IntentFilter> intentFilters = preferredActivities.get(candidateName);
434       if (intentFilters == null) {
435         continue;
436       }
437       for (IntentFilter filter : intentFilters) {
438         if ((filter.match(getContext().getContentResolver(), intent, false, "robo")
439                 & MATCH_CATEGORY_MASK)
440             != 0) {
441           return candidate;
442         }
443       }
444     }
445     return null;
446   }
447 
448   @Implementation
resolveContentProvider(String name, int flags)449   protected ProviderInfo resolveContentProvider(String name, int flags) {
450     if (name == null) {
451       return null;
452     }
453     synchronized (lock) {
454       for (PackageInfo packageInfo : packageInfos.values()) {
455         if (packageInfo.providers == null) {
456           continue;
457         }
458 
459         for (ProviderInfo providerInfo : packageInfo.providers) {
460           for (String authority : Splitter.on(';').split(providerInfo.authority)) {
461             if (name.equals(authority)) {
462               return new ProviderInfo(providerInfo);
463             }
464           }
465         }
466       }
467     }
468     return null;
469   }
470 
471   @Implementation
resolveContentProviderAsUser( String name, int flags, @UserIdInt int userId)472   protected ProviderInfo resolveContentProviderAsUser(
473       String name, int flags, @UserIdInt int userId) {
474     return null;
475   }
476 
477   @Implementation
getPackageInfo(String packageName, int flags)478   protected PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException {
479     return getPackageInfo(packageName, (long) flags);
480   }
481 
482   @Implementation(minSdk = TIRAMISU)
getPackageInfo( String packageName, @ClassName("android.content.pm.PackageManager$PackageInfoFlags") Object flags)483   protected PackageInfo getPackageInfo(
484       String packageName,
485       @ClassName("android.content.pm.PackageManager$PackageInfoFlags") Object flags)
486       throws NameNotFoundException {
487     return getPackageInfo(packageName, ((PackageInfoFlags) flags).getValue());
488   }
489 
getPackageInfo(String packageName, long flags)490   private PackageInfo getPackageInfo(String packageName, long flags) throws NameNotFoundException {
491     synchronized (lock) {
492       PackageInfo info = packageInfos.get(packageName);
493       if (info == null
494           && (flags & MATCH_UNINSTALLED_PACKAGES) != 0
495           && deletedPackages.contains(packageName)) {
496         info = new PackageInfo();
497         info.packageName = packageName;
498         info.applicationInfo = new ApplicationInfo();
499         info.applicationInfo.packageName = packageName;
500       }
501       if (info == null) {
502         throw new NameNotFoundException(packageName);
503       }
504       info = newPackageInfo(info);
505       if (info.applicationInfo == null) {
506         return info;
507       }
508       if (hiddenPackages.contains(packageName) && !isFlagSet(flags, MATCH_UNINSTALLED_PACKAGES)) {
509         throw new NameNotFoundException("Package is hidden, can't find");
510       }
511       applyFlagsToApplicationInfo(info.applicationInfo, flags);
512       info.activities =
513           applyFlagsToComponentInfoList(info.activities, flags, GET_ACTIVITIES, ActivityInfo::new);
514       info.services =
515           applyFlagsToComponentInfoList(info.services, flags, GET_SERVICES, ServiceInfo::new);
516       info.receivers =
517           applyFlagsToComponentInfoList(info.receivers, flags, GET_RECEIVERS, ActivityInfo::new);
518       info.providers =
519           applyFlagsToComponentInfoList(info.providers, flags, GET_PROVIDERS, ProviderInfo::new);
520       return info;
521     }
522   }
523 
524   /**
525    * Starting in Android S, this method was moved from {@link android.content.pm.PackageManager} to
526    * {@link ApplicationPackageManager}. However, it was moved back to {@link
527    * android.content.pm.PackageManager} in T.
528    */
529   @Override
530   @Implementation(minSdk = S, maxSdk = S_V2)
getPackageArchiveInfo(String archiveFilePath, int flags)531   protected PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
532     int apiLevel = RuntimeEnvironment.getApiLevel();
533     if (apiLevel == S || apiLevel == S_V2) {
534 
535       PackageInfo shadowPackageInfo = getShadowPackageArchiveInfo(archiveFilePath, flags);
536       if (shadowPackageInfo != null) {
537         return shadowPackageInfo;
538       } else {
539         return reflector(ReflectorApplicationPackageManager.class, realObject)
540             .getPackageArchiveInfo(archiveFilePath, flags);
541       }
542     } else {
543       return super.getPackageArchiveInfo(archiveFilePath, flags);
544     }
545   }
546 
547   // There is no copy constructor for PackageInfo
newPackageInfo(PackageInfo orig)548   private static PackageInfo newPackageInfo(PackageInfo orig) {
549     Parcel parcel = Parcel.obtain();
550     orig.writeToParcel(parcel, 0);
551     parcel.setDataPosition(0);
552     return PackageInfo.CREATOR.createFromParcel(parcel);
553   }
554 
applyFlagsToComponentInfoList( T[] components, long flags, int activationFlag, Function<T, T> copyConstructor)555   private <T extends ComponentInfo> T[] applyFlagsToComponentInfoList(
556       T[] components, long flags, int activationFlag, Function<T, T> copyConstructor) {
557     if (components == null || (flags & activationFlag) == 0) {
558       return null;
559     }
560     List<T> returned = new ArrayList<>(components.length);
561     for (T component : components) {
562       component = copyConstructor.apply(component);
563       try {
564         applyFlagsToComponentInfo(component, flags);
565         returned.add(component);
566       } catch (NameNotFoundException e) {
567         // skip this component
568       }
569     }
570     if (returned.isEmpty()) {
571       return null;
572     }
573     @SuppressWarnings("unchecked") // component arrays are of their respective types.
574     Class<T[]> componentArrayType = (Class<T[]>) components.getClass();
575     T[] result = Arrays.copyOf(components, returned.size(), componentArrayType);
576     return returned.toArray(result);
577   }
578 
579   @Implementation
queryIntentServices(Intent intent, int flags)580   protected List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
581     return queryIntentComponents(
582         intent,
583         flags,
584         (pkg) -> pkg.services,
585         serviceFilters,
586         (resolveInfo, serviceInfo) -> resolveInfo.serviceInfo = serviceInfo,
587         (resolveInfo) -> resolveInfo.serviceInfo,
588         ServiceInfo::new);
589   }
590 
591   @Implementation(minSdk = TIRAMISU)
queryIntentServices( Intent intent, @ClassName("android.content.pm.PackageManager$ResolveInfoFlags") Object flagsObject)592   protected List<ResolveInfo> queryIntentServices(
593       Intent intent,
594       @ClassName("android.content.pm.PackageManager$ResolveInfoFlags") Object flagsObject) {
595     return queryIntentServices(intent, (int) ((ResolveInfoFlags) flagsObject).getValue());
596   }
597 
hasSomeComponentInfo(ResolveInfo resolveInfo)598   private boolean hasSomeComponentInfo(ResolveInfo resolveInfo) {
599 
600     return resolveInfo.activityInfo != null
601         || resolveInfo.serviceInfo != null
602         || resolveInfo.providerInfo != null;
603   }
604 
isFlagSet(long flags, long matchFlag)605   private static boolean isFlagSet(long flags, long matchFlag) {
606     return (flags & matchFlag) == matchFlag;
607   }
608 
isValidComponentInfo(ComponentInfo componentInfo)609   private static boolean isValidComponentInfo(ComponentInfo componentInfo) {
610     return componentInfo != null
611         && componentInfo.applicationInfo != null
612         && componentInfo.applicationInfo.packageName != null
613         && componentInfo.name != null;
614   }
615 
616   /** Behaves as {@link #queryIntentServices(Intent, int)} and currently ignores userId. */
617   @Implementation
queryIntentServicesAsUser(Intent intent, int flags, int userId)618   protected List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
619     return queryIntentServices(intent, flags);
620   }
621 
622   @Implementation
queryIntentActivities(Intent intent, int flags)623   protected List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
624     return this.queryIntentComponents(
625         intent,
626         flags,
627         (pkg) -> pkg.activities,
628         activityFilters,
629         (resolveInfo, activityInfo) -> resolveInfo.activityInfo = activityInfo,
630         (resolveInfo) -> resolveInfo.activityInfo,
631         ActivityInfo::new);
632   }
633 
queryIntentComponents( Intent intent, int flags, Function<PackageInfo, I[]> componentsInPackage, SortedMap<ComponentName, List<IntentFilter>> filters, BiConsumer<ResolveInfo, I> componentSetter, Function<ResolveInfo, I> componentInResolveInfo, Function<I, I> copyConstructor)634   private <I extends ComponentInfo> List<ResolveInfo> queryIntentComponents(
635       Intent intent,
636       int flags,
637       Function<PackageInfo, I[]> componentsInPackage,
638       SortedMap<ComponentName, List<IntentFilter>> filters,
639       BiConsumer<ResolveInfo, I> componentSetter,
640       Function<ResolveInfo, I> componentInResolveInfo,
641       Function<I, I> copyConstructor) {
642     synchronized (lock) {
643       if (intent.getComponent() != null) {
644         flags &= ~MATCH_DEFAULT_ONLY;
645       }
646       List<ResolveInfo> result = new ArrayList<>();
647       List<ResolveInfo> resolveInfoList = queryOverriddenIntents(intent, flags);
648       if (!resolveInfoList.isEmpty()) {
649         result.addAll(resolveInfoList);
650       }
651 
652       result.addAll(
653           queryComponentsInManifest(intent, componentsInPackage, filters, componentSetter));
654 
655       for (Iterator<ResolveInfo> iterator = result.iterator(); iterator.hasNext(); ) {
656         ResolveInfo resolveInfo = iterator.next();
657         I componentInfo = componentInResolveInfo.apply(resolveInfo);
658         if (hasSomeComponentInfo(resolveInfo) && componentInfo == null) {
659           Log.d(TAG, "ResolveInfo for different component type");
660           // different component type
661           iterator.remove();
662           continue;
663         }
664         if (componentInfo == null) {
665           // null component? Don't filter this sh...
666           continue;
667         }
668         if (!applyFlagsToResolveInfo(resolveInfo, flags)) {
669           Log.d(TAG, "ResolveInfo doesn't match flags");
670           iterator.remove();
671           continue;
672         }
673         ApplicationInfo applicationInfo = componentInfo.applicationInfo;
674         if (applicationInfo == null) {
675           String packageName = null;
676           if (getComponentForIntent(intent) != null) {
677             packageName = getComponentForIntent(intent).getPackageName();
678           } else if (intent.getPackage() != null) {
679             packageName = intent.getPackage();
680           } else if (componentInfo.packageName != null) {
681             packageName = componentInfo.packageName;
682           }
683           if (packageName != null) {
684             PackageInfo packageInfo = packageInfos.get(packageName);
685             if (packageInfo != null && packageInfo.applicationInfo != null) {
686               applicationInfo = new ApplicationInfo(packageInfo.applicationInfo);
687             } else {
688               applicationInfo = new ApplicationInfo();
689               applicationInfo.packageName = packageName;
690               applicationInfo.flags = FLAG_INSTALLED;
691             }
692           }
693         } else {
694           applicationInfo = new ApplicationInfo(applicationInfo);
695         }
696         componentInfo = copyConstructor.apply(componentInfo);
697         componentSetter.accept(resolveInfo, componentInfo);
698         componentInfo.applicationInfo = applicationInfo;
699 
700         try {
701           applyFlagsToComponentInfo(componentInfo, flags);
702         } catch (NameNotFoundException e) {
703           Log.d(TAG, "ComponentInfo doesn't match flags:" + e.getMessage());
704           iterator.remove();
705           continue;
706         }
707       }
708       Collections.sort(result, new ResolveInfoComparator());
709       return result;
710     }
711   }
712 
applyFlagsToResolveInfo(ResolveInfo resolveInfo, int flags)713   private boolean applyFlagsToResolveInfo(ResolveInfo resolveInfo, int flags) {
714     if ((flags & GET_RESOLVED_FILTER) == 0) {
715       resolveInfo.filter = null;
716     }
717     return (flags & MATCH_DEFAULT_ONLY) == 0 || resolveInfo.isDefault;
718   }
719 
queryComponentsInManifest( Intent intent, Function<PackageInfo, I[]> componentsInPackage, SortedMap<ComponentName, List<IntentFilter>> filters, BiConsumer<ResolveInfo, I> componentSetter)720   private <I extends ComponentInfo> ImmutableList<ResolveInfo> queryComponentsInManifest(
721       Intent intent,
722       Function<PackageInfo, I[]> componentsInPackage,
723       SortedMap<ComponentName, List<IntentFilter>> filters,
724       BiConsumer<ResolveInfo, I> componentSetter) {
725     synchronized (lock) {
726       if (isExplicitIntent(intent)) {
727         ComponentName component = getComponentForIntent(intent);
728         PackageInfo appPackage = packageInfos.get(component.getPackageName());
729         if (appPackage == null) {
730           return ImmutableList.of();
731         }
732         I componentInfo = findMatchingComponent(component, componentsInPackage.apply(appPackage));
733         if (componentInfo != null) {
734           List<IntentFilter> componentFilters = filters.get(component);
735           PackageInfo targetPackage = packageInfos.get(component.getPackageName());
736           if (RuntimeEnvironment.getApiLevel() >= TIRAMISU
737               && (intent.getAction() != null
738                   || intent.getCategories() != null
739                   || intent.getData() != null)
740               && componentFilters != null
741               && !component.getPackageName().equals(getContext().getPackageName())
742               && targetPackage.applicationInfo.targetSdkVersion >= TIRAMISU) {
743             // Check if the explicit intent matches filters on the target component for T+
744             boolean matchFound = false;
745             for (IntentFilter filter : componentFilters) {
746               if (matchIntentFilter(intent, filter) > 0) {
747                 matchFound = true;
748                 break;
749               }
750             }
751             if (!matchFound) {
752               Log.w(
753                   TAG,
754                   "Component "
755                       + componentInfo
756                       + " doesn't have required intent filters for "
757                       + intent);
758               return ImmutableList.of();
759             }
760           }
761           ResolveInfo resolveInfo = buildResolveInfo(componentInfo);
762           componentSetter.accept(resolveInfo, componentInfo);
763           return ImmutableList.copyOf(new ArrayList<>(Collections.singletonList(resolveInfo)));
764         }
765 
766         return ImmutableList.of();
767       } else {
768         List<ResolveInfo> resolveInfoList = new ArrayList<>();
769         Map<ComponentName, List<IntentFilter>> filtersForPackage =
770             mapForPackage(filters, intent.getPackage());
771         components:
772         for (Map.Entry<ComponentName, List<IntentFilter>> componentEntry :
773             filtersForPackage.entrySet()) {
774           ComponentName componentName = componentEntry.getKey();
775           for (IntentFilter filter : componentEntry.getValue()) {
776             int match = matchIntentFilter(intent, filter);
777             if (match > 0) {
778               PackageInfo packageInfo = packageInfos.get(componentName.getPackageName());
779               I[] componentInfoArray = componentsInPackage.apply(packageInfo);
780               if (componentInfoArray != null) {
781                 for (I componentInfo : componentInfoArray) {
782                   if (!componentInfo.name.equals(componentName.getClassName())) {
783                     continue;
784                   }
785                   ResolveInfo resolveInfo = buildResolveInfo(componentInfo, filter);
786                   resolveInfo.match = match;
787                   componentSetter.accept(resolveInfo, componentInfo);
788                   resolveInfoList.add(resolveInfo);
789                   continue components;
790                 }
791               }
792             }
793           }
794         }
795         return ImmutableList.copyOf(resolveInfoList);
796       }
797     }
798   }
799 
800   /** Behaves as {@link #queryIntentActivities(Intent, int)} and currently ignores userId. */
801   @Implementation
queryIntentActivitiesAsUser(Intent intent, int flags, int userId)802   protected List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId) {
803     return queryIntentActivities(intent, flags);
804   }
805 
806   /** Behaves as {@link #queryIntentActivities(Intent, int)} and currently ignores userId. */
807   @Implementation(minSdk = TIRAMISU)
queryIntentActivitiesAsUser( Intent intent, @ClassName("android.content.pm.PackageManager$ResolveInfoFlags") Object flags, int userId)808   protected List<ResolveInfo> queryIntentActivitiesAsUser(
809       Intent intent,
810       @ClassName("android.content.pm.PackageManager$ResolveInfoFlags") Object flags,
811       int userId) {
812     return queryIntentActivities(intent, (int) ((ResolveInfoFlags) flags).getValue());
813   }
814 
815   /** Returns true if intent has specified a specific component. */
isExplicitIntent(Intent intent)816   private static boolean isExplicitIntent(Intent intent) {
817     return getComponentForIntent(intent) != null;
818   }
819 
findMatchingComponent( ComponentName componentName, T[] components)820   private static <T extends ComponentInfo> T findMatchingComponent(
821       ComponentName componentName, T[] components) {
822     if (components == null) {
823       return null;
824     }
825     for (T component : components) {
826       if (componentName.equals(new ComponentName(component.packageName, component.name))) {
827         return component;
828       }
829     }
830     return null;
831   }
832 
getComponentForIntent(Intent intent)833   private static ComponentName getComponentForIntent(Intent intent) {
834     ComponentName component = intent.getComponent();
835     if (component == null) {
836       if (intent.getSelector() != null) {
837         intent = intent.getSelector();
838         component = intent.getComponent();
839       }
840     }
841     return component;
842   }
843 
buildResolveInfo(ComponentInfo componentInfo)844   private static ResolveInfo buildResolveInfo(ComponentInfo componentInfo) {
845     ResolveInfo resolveInfo = new ResolveInfo();
846     resolveInfo.resolvePackageName = componentInfo.applicationInfo.packageName;
847     resolveInfo.labelRes = componentInfo.labelRes;
848     resolveInfo.icon = componentInfo.icon;
849     resolveInfo.nonLocalizedLabel = componentInfo.nonLocalizedLabel;
850     return resolveInfo;
851   }
852 
buildResolveInfo(ComponentInfo componentInfo, IntentFilter intentFilter)853   static ResolveInfo buildResolveInfo(ComponentInfo componentInfo, IntentFilter intentFilter) {
854     ResolveInfo info = buildResolveInfo(componentInfo);
855     info.isDefault = intentFilter.hasCategory("android.intent.category.DEFAULT");
856     info.filter = new IntentFilter(intentFilter);
857     info.priority = intentFilter.getPriority();
858     return info;
859   }
860 
861   @Implementation
checkPermission(String permName, String pkgName)862   protected int checkPermission(String permName, String pkgName) {
863     PackageInfo permissionsInfo = getInternalMutablePackageInfo(pkgName);
864     if (permissionsInfo == null || permissionsInfo.requestedPermissions == null) {
865       return PackageManager.PERMISSION_DENIED;
866     }
867 
868     String permission;
869     for (int i = 0; i < permissionsInfo.requestedPermissions.length; i++) {
870       permission = permissionsInfo.requestedPermissions[i];
871       if (permission != null && permission.equals(permName)) {
872         // The package requests this permission. Now check if it's been granted to the package.
873         if (isGrantedForBackwardsCompatibility(pkgName, permissionsInfo)) {
874           return PackageManager.PERMISSION_GRANTED;
875         }
876 
877         if ((permissionsInfo.requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED)
878             == REQUESTED_PERMISSION_GRANTED) {
879           return PackageManager.PERMISSION_GRANTED;
880         }
881       }
882     }
883 
884     return PackageManager.PERMISSION_DENIED;
885   }
886 
887   /**
888    * Returns whether a permission should be treated as granted to the package for backward
889    * compatibility reasons.
890    *
891    * <p>Before Robolectric 4.0 the ShadowPackageManager treated every requested permission as
892    * automatically granted. 4.0 changes this behavior, and only treats a permission as granted if
893    * PackageInfo.requestedPermissionFlags[permissionIndex] & REQUESTED_PERMISSION_GRANTED ==
894    * REQUESTED_PERMISSION_GRANTED which matches the real PackageManager's behavior.
895    *
896    * <p>Since many existing tests didn't set the requestedPermissionFlags on their {@code
897    * PackageInfo} objects, but assumed that all permissions are granted, we auto-grant all
898    * permissions if the requestedPermissionFlags is not set. If the requestedPermissionFlags is set,
899    * we assume that the test is configuring the permission grant state, and we don't override this
900    * setting.
901    */
isGrantedForBackwardsCompatibility(String pkgName, PackageInfo permissionsInfo)902   private boolean isGrantedForBackwardsCompatibility(String pkgName, PackageInfo permissionsInfo) {
903     // Note: it might be cleaner to auto-grant these permissions when the package is added to the
904     // PackageManager. But many existing tests modify the requested permissions _after_ adding the
905     // package to the PackageManager, without updating the requestedPermissionsFlags.
906     return permissionsInfo.requestedPermissionsFlags == null
907         // Robolectric uses the PackageParser to create the current test package's PackageInfo from
908         // the manifest XML. The parser populates the requestedPermissionsFlags, but doesn't grant
909         // the permissions. Several tests rely on the test package being granted all permissions, so
910         // we treat this as a special case.
911         || pkgName.equals(RuntimeEnvironment.getApplication().getPackageName());
912   }
913 
914   @Implementation
getReceiverInfo(ComponentName component, int flags)915   protected ActivityInfo getReceiverInfo(ComponentName component, int flags)
916       throws NameNotFoundException {
917     return getComponentInfo(
918         component,
919         flags,
920         packageInfo -> packageInfo.receivers,
921         resolveInfo -> resolveInfo.activityInfo,
922         ActivityInfo::new);
923   }
924 
925   @Implementation(minSdk = TIRAMISU)
getReceiverInfo( ComponentName component, @ClassName("android.content.pm.PackageManager$ComponentInfoFlags") Object flags)926   protected ActivityInfo getReceiverInfo(
927       ComponentName component,
928       @ClassName("android.content.pm.PackageManager$ComponentInfoFlags") Object flags)
929       throws NameNotFoundException {
930     return getReceiverInfo(component, (int) ((ComponentInfoFlags) flags).getValue());
931   }
932 
933   @Implementation
queryBroadcastReceivers(Intent intent, int flags)934   protected List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
935     return this.queryIntentComponents(
936         intent,
937         flags,
938         (pkg) -> pkg.receivers,
939         receiverFilters,
940         (resolveInfo, activityInfo) -> resolveInfo.activityInfo = activityInfo,
941         (resolveInfo) -> resolveInfo.activityInfo,
942         ActivityInfo::new);
943   }
944 
945   @Implementation(minSdk = TIRAMISU)
queryBroadcastReceivers( Intent intent, @ClassName("android.content.pm.PackageManager$ResolveInfoFlags") Object flags)946   protected List<ResolveInfo> queryBroadcastReceivers(
947       Intent intent,
948       @ClassName("android.content.pm.PackageManager$ResolveInfoFlags") Object flags) {
949     return queryBroadcastReceivers(intent, (int) ((ResolveInfoFlags) flags).getValue());
950   }
951 
matchIntentFilter(Intent intent, IntentFilter intentFilter)952   private static int matchIntentFilter(Intent intent, IntentFilter intentFilter) {
953     return intentFilter.match(
954         intent.getAction(),
955         intent.getType(),
956         intent.getScheme(),
957         intent.getData(),
958         intent.getCategories(),
959         TAG);
960   }
961 
962   @Implementation
resolveService(Intent intent, int flags)963   protected ResolveInfo resolveService(Intent intent, int flags) {
964     List<ResolveInfo> candidates = queryIntentServices(intent, flags);
965     return candidates.isEmpty() ? null : candidates.get(0);
966   }
967 
968   @Implementation
getServiceInfo(ComponentName component, int flags)969   protected ServiceInfo getServiceInfo(ComponentName component, int flags)
970       throws NameNotFoundException {
971     return getComponentInfo(
972         component,
973         flags,
974         packageInfo -> packageInfo.services,
975         resolveInfo -> resolveInfo.serviceInfo,
976         ServiceInfo::new);
977   }
978 
979   @Implementation(minSdk = TIRAMISU)
getServiceInfo( ComponentName component, @ClassName("android.content.pm.PackageManager$ComponentInfoFlags") Object flags)980   protected ServiceInfo getServiceInfo(
981       ComponentName component,
982       @ClassName("android.content.pm.PackageManager$ComponentInfoFlags") Object flags)
983       throws NameNotFoundException {
984     return getServiceInfo(component, (int) ((ComponentInfoFlags) flags).getValue());
985   }
986 
987   /**
988    * Modifies the component in place using.
989    *
990    * @throws NameNotFoundException when component is filtered out by a flag
991    */
applyFlagsToComponentInfo(ComponentInfo componentInfo, long flags)992   private void applyFlagsToComponentInfo(ComponentInfo componentInfo, long flags)
993       throws NameNotFoundException {
994     componentInfo.name = (componentInfo.name == null) ? "" : componentInfo.name;
995     ApplicationInfo applicationInfo = componentInfo.applicationInfo;
996     boolean isApplicationEnabled = true;
997     if (applicationInfo != null) {
998       if (applicationInfo.packageName == null) {
999         applicationInfo.packageName = componentInfo.packageName;
1000       }
1001       applyFlagsToApplicationInfo(componentInfo.applicationInfo, flags);
1002       componentInfo.packageName = applicationInfo.packageName;
1003       isApplicationEnabled = applicationInfo.enabled;
1004     }
1005     if ((flags & GET_META_DATA) == 0) {
1006       componentInfo.metaData = null;
1007     }
1008     boolean isComponentEnabled = isComponentEnabled(componentInfo);
1009     if ((flags & MATCH_ALL) != 0 && Build.VERSION.SDK_INT >= 23) {
1010       return;
1011     }
1012     // Android don't override the enabled field of component with the actual value.
1013     boolean isEnabledForFiltering =
1014         isComponentEnabled && (Build.VERSION.SDK_INT >= 24 ? isApplicationEnabled : true);
1015     if ((flags & MATCH_DISABLED_COMPONENTS) == 0 && !isEnabledForFiltering) {
1016       throw new NameNotFoundException("Disabled component: " + componentInfo);
1017     }
1018     if (isFlagSet(flags, PackageManager.MATCH_SYSTEM_ONLY)) {
1019       if (applicationInfo == null) {
1020         // TODO: for backwards compatibility just skip filtering. In future should just remove
1021         // invalid resolve infos from list
1022       } else {
1023         final int applicationFlags = applicationInfo.flags;
1024         if ((applicationFlags & ApplicationInfo.FLAG_SYSTEM) != ApplicationInfo.FLAG_SYSTEM) {
1025           throw new NameNotFoundException("Not system component: " + componentInfo);
1026         }
1027       }
1028     }
1029     if (!isFlagSet(flags, MATCH_UNINSTALLED_PACKAGES)
1030         && isValidComponentInfo(componentInfo)
1031         && hiddenPackages.contains(componentInfo.applicationInfo.packageName)) {
1032       throw new NameNotFoundException("Uninstalled package: " + componentInfo);
1033     }
1034   }
1035 
1036   @Implementation
getResourcesForApplication(@onNull ApplicationInfo applicationInfo)1037   protected Resources getResourcesForApplication(@NonNull ApplicationInfo applicationInfo)
1038       throws PackageManager.NameNotFoundException {
1039     synchronized (lock) {
1040       if (getContext().getPackageName().equals(applicationInfo.packageName)) {
1041         return getContext().getResources();
1042       } else if (packageInfos.containsKey(applicationInfo.packageName)) {
1043         Resources appResources = resources.get(applicationInfo.packageName);
1044         if (appResources == null) {
1045           appResources = new Resources(new AssetManager(), null, null);
1046           resources.put(applicationInfo.packageName, appResources);
1047         }
1048         return appResources;
1049       }
1050       Resources resources = null;
1051 
1052       try {
1053         resources =
1054             reflector(ReflectorApplicationPackageManager.class, realObject)
1055                 .getResourcesForApplication(applicationInfo);
1056       } catch (Exception ex) {
1057         // handled below
1058       }
1059       if (resources == null) {
1060         throw new NameNotFoundException(applicationInfo.packageName);
1061       }
1062       return resources;
1063     }
1064   }
1065 
1066   @Implementation
getInstalledApplications(int flags)1067   protected List<ApplicationInfo> getInstalledApplications(int flags) {
1068     return getInstalledApplications((long) flags);
1069   }
1070 
1071   @Implementation(minSdk = TIRAMISU)
getInstalledApplications( @lassName"android.content.pm.PackageManager$ApplicationInfoFlags") Object flags)1072   protected List<ApplicationInfo> getInstalledApplications(
1073       @ClassName("android.content.pm.PackageManager$ApplicationInfoFlags") Object flags) {
1074     return getInstalledApplications(((PackageManager.ApplicationInfoFlags) flags).getValue());
1075   }
1076 
getInstalledApplications(long flags)1077   private List<ApplicationInfo> getInstalledApplications(long flags) {
1078     List<PackageInfo> packageInfos = getInstalledPackages(flags);
1079     List<ApplicationInfo> result = new ArrayList<>(packageInfos.size());
1080 
1081     for (PackageInfo packageInfo : packageInfos) {
1082       if (packageInfo.applicationInfo != null) {
1083         result.add(packageInfo.applicationInfo);
1084       }
1085     }
1086     return result;
1087   }
1088 
1089   @Implementation
getInstallerPackageName(String packageName)1090   protected String getInstallerPackageName(String packageName) {
1091     synchronized (lock) {
1092       // In REALISTIC mode, throw exception if the package is not installed or installed but
1093       // later uninstalled
1094       if (ConfigurationRegistry.get(GetInstallerPackageNameMode.Mode.class) == REALISTIC
1095           && (!packageInstallerMap.containsKey(packageName)
1096               || !packageInfos.containsKey(packageName))) {
1097         throw new IllegalArgumentException("Package is not installed: " + packageName);
1098       } else if (!packageInstallerMap.containsKey(packageName)) {
1099         Log.w(
1100             TAG,
1101             String.format(
1102                 "Call to getInstallerPackageName returns null for package: '%s'. Please run"
1103                     + " setInstallerPackageName to set installer package name before making the"
1104                     + " call.",
1105                 packageName));
1106       }
1107       return packageInstallerMap.get(packageName);
1108     }
1109   }
1110 
1111   @Implementation(minSdk = R)
getInstallSourceInfo( String packageName)1112   protected @ClassName("android.content.pm.InstallSourceInfo") Object getInstallSourceInfo(
1113       String packageName) throws NameNotFoundException {
1114     if (!packageInstallSourceInfoMap.containsKey(packageName)) {
1115       throw new NameNotFoundException("Package is not installed: " + packageName);
1116     } else {
1117       return packageInstallSourceInfoMap.get(packageName);
1118     }
1119   }
1120 
1121   @Implementation
getPermissionInfo(String name, int flags)1122   protected PermissionInfo getPermissionInfo(String name, int flags) throws NameNotFoundException {
1123     // Allow extra permissions to override sample platform permissions and package permissions.
1124     PermissionInfo permissionInfo = extraPermissions.get(name);
1125     if (permissionInfo != null) {
1126       return createCopyPermissionInfo(permissionInfo, flags);
1127     }
1128 
1129     permissionInfo = AOSP_PLATFORM_PERMISSIONS.get(name);
1130     if (permissionInfo != null) {
1131       return createCopyPermissionInfo(permissionInfo, flags);
1132     }
1133 
1134     // Assume that package permissions never attempt to override sample platform permissions.
1135     // This is enforced when adding a package.
1136     synchronized (lock) {
1137       for (PackageInfo packageInfo : packageInfos.values()) {
1138         if (packageInfo.permissions != null) {
1139           for (PermissionInfo permission : packageInfo.permissions) {
1140             if (name.equals(permission.name)) {
1141               return createCopyPermissionInfo(permission, flags);
1142             }
1143           }
1144         }
1145       }
1146     }
1147 
1148     throw new NameNotFoundException(name);
1149   }
1150 
1151   @Implementation(minSdk = M)
shouldShowRequestPermissionRationale(String permission)1152   protected boolean shouldShowRequestPermissionRationale(String permission) {
1153     return permissionRationaleMap.containsKey(permission)
1154         ? permissionRationaleMap.get(permission)
1155         : false;
1156   }
1157 
1158   @Implementation
getSystemAvailableFeatures()1159   protected FeatureInfo[] getSystemAvailableFeatures() {
1160     return systemAvailableFeatures.isEmpty()
1161         ? null
1162         : systemAvailableFeatures.toArray(new FeatureInfo[systemAvailableFeatures.size()]);
1163   }
1164 
1165   @Implementation
verifyPendingInstall(int id, int verificationCode)1166   protected void verifyPendingInstall(int id, int verificationCode) {
1167     if (verificationResults.containsKey(id)) {
1168       throw new IllegalStateException("Multiple verifications for id=" + id);
1169     }
1170     verificationResults.put(id, verificationCode);
1171   }
1172 
1173   @Implementation
extendVerificationTimeout( int id, int verificationCodeAtTimeout, long millisecondsToDelay)1174   protected void extendVerificationTimeout(
1175       int id, int verificationCodeAtTimeout, long millisecondsToDelay) {
1176     synchronized (lock) {
1177       verificationTimeoutExtension.put(id, millisecondsToDelay);
1178       verificationCodeAtTimeoutExtension.put(id, verificationCodeAtTimeout);
1179     }
1180   }
1181 
1182   @Override
1183   @Implementation(maxSdk = LOLLIPOP_MR1)
freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer)1184   protected void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer) {}
1185 
1186   @Implementation(minSdk = M)
freeStorageAndNotify( String volumeUuid, long freeStorageSize, IPackageDataObserver observer)1187   protected void freeStorageAndNotify(
1188       String volumeUuid, long freeStorageSize, IPackageDataObserver observer) {}
1189 
1190   @Implementation
setInstallerPackageName(String targetPackage, String installerPackageName)1191   protected void setInstallerPackageName(String targetPackage, String installerPackageName) {
1192     synchronized (lock) {
1193       packageInstallerMap.put(targetPackage, installerPackageName);
1194     }
1195   }
1196 
1197   @Implementation
queryIntentContentProviders(Intent intent, int flags)1198   protected List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags) {
1199     return this.queryIntentComponents(
1200         intent,
1201         flags,
1202         (pkg) -> pkg.providers,
1203         providerFilters,
1204         (resolveInfo, providerInfo) -> resolveInfo.providerInfo = providerInfo,
1205         (resolveInfo) -> resolveInfo.providerInfo,
1206         ProviderInfo::new);
1207   }
1208 
1209   @Implementation
queryIntentContentProvidersAsUser( Intent intent, int flags, int userId)1210   protected List<ResolveInfo> queryIntentContentProvidersAsUser(
1211       Intent intent, int flags, int userId) {
1212     return Collections.emptyList();
1213   }
1214 
1215   @HiddenApi
1216   @Implementation(minSdk = M)
getPermissionControllerPackageName()1217   protected String getPermissionControllerPackageName() {
1218     return PERMISSION_CONTROLLER_PACKAGE_NAME;
1219   }
1220 
1221   @Implementation(maxSdk = M)
getPackageSizeInfo( String pkgName, int uid, final @ClassName("android.content.pm.IPackageStatsObserver") Object observer)1222   protected void getPackageSizeInfo(
1223       String pkgName,
1224       int uid,
1225       final @ClassName("android.content.pm.IPackageStatsObserver") Object observer) {
1226     final PackageStats packageStats = packageStatsMap.get((String) pkgName);
1227     new Handler(Looper.getMainLooper())
1228         .post(
1229             () -> {
1230               try {
1231                 ((IPackageStatsObserver) observer)
1232                     .onGetStatsCompleted(packageStats, packageStats != null);
1233               } catch (RemoteException remoteException) {
1234                 remoteException.rethrowFromSystemServer();
1235               }
1236             });
1237   }
1238 
1239   @Implementation(minSdk = N)
getPackageSizeInfoAsUser( String pkgName, int uid, final @ClassName("android.content.pm.IPackageStatsObserver") Object observer)1240   protected void getPackageSizeInfoAsUser(
1241       String pkgName,
1242       int uid,
1243       final @ClassName("android.content.pm.IPackageStatsObserver") Object observer) {
1244     final PackageStats packageStats = packageStatsMap.get(pkgName);
1245     new Handler(Looper.getMainLooper())
1246         .post(
1247             () -> {
1248               try {
1249                 ((IPackageStatsObserver) observer)
1250                     .onGetStatsCompleted(packageStats, packageStats != null);
1251               } catch (RemoteException remoteException) {
1252                 remoteException.rethrowFromSystemServer();
1253               }
1254             });
1255   }
1256 
1257   @Override
1258   @Implementation
deletePackage(String packageName, IPackageDeleteObserver observer, int flags)1259   protected void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
1260     super.deletePackage(packageName, observer, flags);
1261   }
1262 
1263   @Implementation
currentToCanonicalPackageNames(String[] names)1264   protected String[] currentToCanonicalPackageNames(String[] names) {
1265     String[] out = new String[names.length];
1266     for (int i = 0; i < names.length; i++) {
1267       out[i] = currentToCanonicalNames.getOrDefault(names[i], names[i]);
1268     }
1269     return out;
1270   }
1271 
1272   @Implementation
canonicalToCurrentPackageNames(String[] names)1273   protected String[] canonicalToCurrentPackageNames(String[] names) {
1274     String[] out = new String[names.length];
1275     for (int i = 0; i < names.length; i++) {
1276       out[i] = canonicalToCurrentNames.getOrDefault(names[i], names[i]);
1277     }
1278     return out;
1279   }
1280 
1281   @Implementation
isSafeMode()1282   protected boolean isSafeMode() {
1283     return safeMode;
1284   }
1285 
1286   @Implementation
getApplicationIcon(String packageName)1287   protected Drawable getApplicationIcon(String packageName) throws NameNotFoundException {
1288     return applicationIcons.get(packageName);
1289   }
1290 
1291   @Implementation
getApplicationIcon(ApplicationInfo info)1292   protected Drawable getApplicationIcon(ApplicationInfo info) throws NameNotFoundException {
1293     return getApplicationIcon(info.packageName);
1294   }
1295 
1296   @Implementation
getUserBadgeForDensity(UserHandle userHandle, int i)1297   protected Drawable getUserBadgeForDensity(UserHandle userHandle, int i) {
1298     return null;
1299   }
1300 
1301   @Implementation
checkSignatures(String pkg1, String pkg2)1302   protected int checkSignatures(String pkg1, String pkg2) {
1303     try {
1304       PackageInfo packageInfo1 = getPackageInfo(pkg1, GET_SIGNING_CERTIFICATES | GET_SIGNATURES);
1305       PackageInfo packageInfo2 = getPackageInfo(pkg2, GET_SIGNING_CERTIFICATES | GET_SIGNATURES);
1306       int signaturesResult = compareSignature(packageInfo1.signatures, packageInfo2.signatures);
1307       // Use signatures field for older SDKs
1308       if (VERSION.SDK_INT < P) {
1309         return signaturesResult;
1310       } else {
1311         // Prefer signingInfo where populated, but fall back to signatures for compatibility
1312         Signature[] firstSignatures =
1313             packageInfo1.signingInfo == null
1314                     || packageInfo1.signingInfo.getApkContentsSigners() == null
1315                     || packageInfo1.signingInfo.getApkContentsSigners().length == 0
1316                 ? packageInfo1.signatures
1317                 : packageInfo1.signingInfo.getApkContentsSigners();
1318         Signature[] secondSignatures =
1319             packageInfo2.signingInfo == null
1320                     || packageInfo2.signingInfo.getApkContentsSigners() == null
1321                     || packageInfo2.signingInfo.getApkContentsSigners().length == 0
1322                 ? packageInfo2.signatures
1323                 : packageInfo2.signingInfo.getApkContentsSigners();
1324         return compareSignature(firstSignatures, secondSignatures);
1325       }
1326     } catch (NameNotFoundException e) {
1327       return SIGNATURE_UNKNOWN_PACKAGE;
1328     }
1329   }
1330 
1331   @Implementation
checkSignatures(int uid1, int uid2)1332   protected int checkSignatures(int uid1, int uid2) {
1333     return 0;
1334   }
1335 
1336   @Implementation
queryPermissionsByGroup(String group, int flags)1337   protected List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
1338       throws NameNotFoundException {
1339     Map<String, PermissionInfo> combinedPermissions = new HashMap<>();
1340 
1341     // Assume that package permissions never attempt to override sample platform permissions.
1342     // This is enforced when adding a package.
1343     synchronized (lock) {
1344       for (PackageInfo packageInfo : packageInfos.values()) {
1345         if (packageInfo.permissions != null) {
1346           for (PermissionInfo permissionInfo : packageInfo.permissions) {
1347             combinedPermissions.put(permissionInfo.name, permissionInfo);
1348           }
1349         }
1350       }
1351     }
1352 
1353     combinedPermissions.putAll(AOSP_PLATFORM_PERMISSIONS);
1354 
1355     // Allow extra permissions to override sample platform permissions and package permissions.
1356     // Note that overrides may remove or change the group of a permission.
1357     combinedPermissions.putAll(extraPermissions);
1358 
1359     List<PermissionInfo> result = new ArrayList<>();
1360     for (PermissionInfo permissionInfo : combinedPermissions.values()) {
1361       if (Objects.equals(permissionInfo.group, group)) {
1362         result.add(createCopyPermissionInfo(permissionInfo, flags));
1363       }
1364     }
1365 
1366     if (result.isEmpty()) {
1367       throw new NameNotFoundException(group);
1368     }
1369 
1370     return result;
1371   }
1372 
createCopyPermissionInfo(PermissionInfo src, int flags)1373   private static PermissionInfo createCopyPermissionInfo(PermissionInfo src, int flags) {
1374     PermissionInfo matchedPermission = new PermissionInfo(src);
1375     if ((flags & GET_META_DATA) != GET_META_DATA) {
1376       matchedPermission.metaData = null;
1377     }
1378     return matchedPermission;
1379   }
1380 
getLaunchIntentForPackage(String packageName, String launcherCategory)1381   private Intent getLaunchIntentForPackage(String packageName, String launcherCategory) {
1382     Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1383     intentToResolve.addCategory(Intent.CATEGORY_INFO);
1384     intentToResolve.setPackage(packageName);
1385     List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
1386 
1387     if (ris == null || ris.isEmpty()) {
1388       intentToResolve.removeCategory(Intent.CATEGORY_INFO);
1389       intentToResolve.addCategory(launcherCategory);
1390       intentToResolve.setPackage(packageName);
1391       ris = queryIntentActivities(intentToResolve, 0);
1392     }
1393     if (ris == null || ris.isEmpty()) {
1394       return null;
1395     }
1396     Intent intent = new Intent(intentToResolve);
1397     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1398     intent.setClassName(packageName, ris.get(0).activityInfo.name);
1399     return intent;
1400   }
1401 
1402   @Implementation
getLaunchIntentForPackage(String packageName)1403   protected Intent getLaunchIntentForPackage(String packageName) {
1404     return getLaunchIntentForPackage(packageName, Intent.CATEGORY_LAUNCHER);
1405   }
1406 
1407   @Implementation
getLeanbackLaunchIntentForPackage(String packageName)1408   protected Intent getLeanbackLaunchIntentForPackage(String packageName) {
1409     return getLaunchIntentForPackage(packageName, Intent.CATEGORY_LEANBACK_LAUNCHER);
1410   }
1411 
1412   @Implementation(minSdk = N)
getPackageInfoAsUser( String packageName, int flags, int userId)1413   protected @ClassName("android.content.pm.PackageInfo") Object getPackageInfoAsUser(
1414       String packageName, int flags, int userId) throws NameNotFoundException {
1415     return getPackageInfo(packageName, flags);
1416   }
1417 
1418   /** In Android T, an overloaded one which has parameter type of {@link PackageInfoFlags}. */
1419   @Implementation(minSdk = TIRAMISU)
getPackageInfoAsUser( String packageName, @ClassName("android.content.pm.PackageManager$PackageInfoFlags") Object flagsObject, int userId)1420   protected @ClassName("android.content.pm.PackageInfo") Object getPackageInfoAsUser(
1421       String packageName,
1422       @ClassName("android.content.pm.PackageManager$PackageInfoFlags") Object flagsObject,
1423       int userId)
1424       throws NameNotFoundException {
1425     return getPackageInfo(packageName, ((PackageInfoFlags) flagsObject).getValue());
1426   }
1427 
1428   @Implementation
getPackageGids(String packageName)1429   protected int[] getPackageGids(String packageName) throws NameNotFoundException {
1430     return new int[0];
1431   }
1432 
1433   @Implementation(minSdk = N)
getPackageGids(String packageName, int flags)1434   protected int[] getPackageGids(String packageName, int flags) throws NameNotFoundException {
1435     return null;
1436   }
1437 
1438   @Implementation
getPackageUid(String packageName, int flags)1439   protected int getPackageUid(String packageName, int flags) throws NameNotFoundException {
1440     Integer uid = uidForPackage.get(packageName);
1441     if (uid == null) {
1442       throw new NameNotFoundException(packageName);
1443     }
1444     return uid;
1445   }
1446 
1447   @Implementation(minSdk = TIRAMISU)
getPackageUid( String packageName, @ClassName("android.content.pm.PackageManager$PackageInfoFlags") Object flags)1448   protected int getPackageUid(
1449       String packageName,
1450       @ClassName("android.content.pm.PackageManager$PackageInfoFlags") Object flags)
1451       throws NameNotFoundException {
1452     return getPackageUid(packageName, (int) ((PackageInfoFlags) flags).getValue());
1453   }
1454 
1455   @Implementation(minSdk = N)
getPackageUidAsUser(String packageName, int userId)1456   protected int getPackageUidAsUser(String packageName, int userId) throws NameNotFoundException {
1457     return 0;
1458   }
1459 
1460   @Implementation(minSdk = N)
getPackageUidAsUser(String packageName, int flags, int userId)1461   protected int getPackageUidAsUser(String packageName, int flags, int userId)
1462       throws NameNotFoundException {
1463     return 0;
1464   }
1465 
1466   /**
1467    * @see ShadowPackageManager#addPermissionGroupInfo(android.content.pm.PermissionGroupInfo)
1468    */
1469   @Implementation
getPermissionGroupInfo(String name, int flags)1470   protected PermissionGroupInfo getPermissionGroupInfo(String name, int flags)
1471       throws NameNotFoundException {
1472     // Allow groups added through the shadow API to override sample platform permission groups.
1473     // Assume that manifest permission groups never attempt to override sample platform permission
1474     // groups. This is enforced when parsing the test app manifest.
1475     if (permissionGroups.containsKey(name)) {
1476       return createCopyPermissionGroupInfo(permissionGroups.get(name), flags);
1477     }
1478 
1479     if (AOSP_PLATFORM_PERMISSION_GROUPS.containsKey(name)) {
1480       return createCopyPermissionGroupInfo(AOSP_PLATFORM_PERMISSION_GROUPS.get(name), flags);
1481     }
1482 
1483     throw new NameNotFoundException(name);
1484   }
1485 
1486   /**
1487    * @see ShadowPackageManager#addPermissionGroupInfo(android.content.pm.PermissionGroupInfo)
1488    */
1489   @Implementation
getAllPermissionGroups(int flags)1490   protected List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
1491     Map<String, PermissionGroupInfo> result = new HashMap<>();
1492 
1493     for (PermissionGroupInfo permissionGroupInfo : AOSP_PLATFORM_PERMISSION_GROUPS.values()) {
1494       result.put(
1495           permissionGroupInfo.name, createCopyPermissionGroupInfo(permissionGroupInfo, flags));
1496     }
1497 
1498     // Allow groups added through the shadow API to override sample platform permission groups.
1499     // Assume that manifest permission groups never attempt to override platform permission groups.
1500     // This is enforced when parsing the test app manifest.
1501     for (PermissionGroupInfo permissionGroupInfo : permissionGroups.values()) {
1502       result.put(
1503           permissionGroupInfo.name, createCopyPermissionGroupInfo(permissionGroupInfo, flags));
1504     }
1505 
1506     return new ArrayList<>(result.values());
1507   }
1508 
createCopyPermissionGroupInfo( PermissionGroupInfo src, int flags)1509   private static PermissionGroupInfo createCopyPermissionGroupInfo(
1510       PermissionGroupInfo src, int flags) {
1511     PermissionGroupInfo copy = new PermissionGroupInfo(src);
1512     if ((flags & GET_META_DATA) != GET_META_DATA) {
1513       copy.metaData = null;
1514     }
1515     return copy;
1516   }
1517 
1518   @Implementation
getApplicationInfo(String packageName, int flags)1519   protected ApplicationInfo getApplicationInfo(String packageName, int flags)
1520       throws NameNotFoundException {
1521     PackageInfo packageInfo = getPackageInfo(packageName, flags);
1522     if (packageInfo.applicationInfo == null) {
1523       throw new NameNotFoundException("Package found but without application info");
1524     }
1525     // Maybe query app infos from overridden resolveInfo as well?
1526     return packageInfo.applicationInfo;
1527   }
1528 
1529   @Implementation(minSdk = TIRAMISU)
getApplicationInfo( String packageName, @ClassName("android.content.pm.PackageManager$ApplicationInfoFlags") Object flagsObject)1530   protected ApplicationInfo getApplicationInfo(
1531       String packageName,
1532       @ClassName("android.content.pm.PackageManager$ApplicationInfoFlags") Object flagsObject)
1533       throws NameNotFoundException {
1534     Preconditions.checkArgument(flagsObject instanceof PackageManager.ApplicationInfoFlags);
1535     PackageManager.ApplicationInfoFlags flags = (PackageManager.ApplicationInfoFlags) flagsObject;
1536     return getApplicationInfo(packageName, (int) flags.getValue());
1537   }
1538 
applyFlagsToApplicationInfo(@ullable ApplicationInfo appInfo, long flags)1539   private void applyFlagsToApplicationInfo(@Nullable ApplicationInfo appInfo, long flags)
1540       throws NameNotFoundException {
1541     if (appInfo == null) {
1542       return;
1543     }
1544     String packageName = appInfo.packageName;
1545 
1546     Integer stateOverride = applicationEnabledSettingMap.get(packageName);
1547     if (stateOverride == null) {
1548       stateOverride = COMPONENT_ENABLED_STATE_DEFAULT;
1549     }
1550     appInfo.enabled =
1551         (appInfo.enabled && stateOverride == COMPONENT_ENABLED_STATE_DEFAULT)
1552             || stateOverride == COMPONENT_ENABLED_STATE_ENABLED;
1553 
1554     synchronized (lock) {
1555       if (deletedPackages.contains(packageName)) {
1556         appInfo.flags &= ~FLAG_INSTALLED;
1557       }
1558     }
1559 
1560     if ((flags & MATCH_ALL) != 0 && Build.VERSION.SDK_INT >= 23) {
1561       return;
1562     }
1563     if ((flags & MATCH_UNINSTALLED_PACKAGES) == 0 && (appInfo.flags & FLAG_INSTALLED) == 0) {
1564       throw new NameNotFoundException("Package not installed: " + packageName);
1565     }
1566     if ((flags & MATCH_UNINSTALLED_PACKAGES) == 0 && hiddenPackages.contains(packageName)) {
1567       throw new NameNotFoundException("Package hidden: " + packageName);
1568     }
1569   }
1570 
1571   /**
1572    * Returns all the values added via {@link
1573    * ShadowPackageManager#addSystemSharedLibraryName(String)}.
1574    */
1575   @Implementation
getSystemSharedLibraryNames()1576   protected String[] getSystemSharedLibraryNames() {
1577     return systemSharedLibraryNames.toArray(new String[systemSharedLibraryNames.size()]);
1578   }
1579 
1580   @Implementation(minSdk = N)
getServicesSystemSharedLibraryPackageName()1581   protected @NonNull String getServicesSystemSharedLibraryPackageName() {
1582     return null;
1583   }
1584 
1585   @Implementation(minSdk = N)
getSharedSystemSharedLibraryPackageName()1586   protected @NonNull String getSharedSystemSharedLibraryPackageName() {
1587     return "";
1588   }
1589 
1590   @Implementation(minSdk = N)
hasSystemFeature(String name, int version)1591   protected boolean hasSystemFeature(String name, int version) {
1592     return false;
1593   }
1594 
1595   @Implementation(minSdk = M)
isPermissionRevokedByPolicy(String permName, String pkgName)1596   protected boolean isPermissionRevokedByPolicy(String permName, String pkgName) {
1597     return false;
1598   }
1599 
1600   @Implementation
addPermission(PermissionInfo info)1601   protected boolean addPermission(PermissionInfo info) {
1602     return false;
1603   }
1604 
1605   @Implementation
addPermissionAsync(PermissionInfo info)1606   protected boolean addPermissionAsync(PermissionInfo info) {
1607     return false;
1608   }
1609 
1610   @Implementation
removePermission(String name)1611   protected void removePermission(String name) {}
1612 
1613   @Implementation(minSdk = M)
grantRuntimePermission( String packageName, String permissionName, UserHandle user)1614   protected void grantRuntimePermission(
1615       String packageName, String permissionName, UserHandle user) {
1616     Integer uid;
1617     synchronized (lock) {
1618       if (!packageInfos.containsKey(packageName)) {
1619         throw new SecurityException("Package not found: " + packageName);
1620       }
1621       PackageInfo packageInfo = packageInfos.get(packageName);
1622       checkPermissionGrantStateInitialized(packageInfo);
1623 
1624       int permissionIndex = getPermissionIndex(packageInfo, permissionName);
1625       if (permissionIndex < 0) {
1626         throw new SecurityException(
1627             "Permission " + permissionName + " not requested by package " + packageName);
1628       }
1629 
1630       packageInfo.requestedPermissionsFlags[permissionIndex] |= REQUESTED_PERMISSION_GRANTED;
1631 
1632       uid = uidForPackage.get(packageName);
1633     }
1634 
1635     if (RuntimeEnvironment.getApiLevel() >= VERSION_CODES.M && uid != null) {
1636       for (Object listener : permissionListeners) {
1637         ((OnPermissionsChangedListener) listener).onPermissionsChanged(uid);
1638       }
1639     }
1640   }
1641 
1642   @Implementation(minSdk = M)
revokeRuntimePermission( String packageName, String permissionName, UserHandle user)1643   protected void revokeRuntimePermission(
1644       String packageName, String permissionName, UserHandle user) {
1645     Integer uid;
1646     synchronized (lock) {
1647       if (!packageInfos.containsKey(packageName)) {
1648         throw new SecurityException("Package not found: " + packageName);
1649       }
1650       PackageInfo packageInfo = packageInfos.get(packageName);
1651       checkPermissionGrantStateInitialized(packageInfo);
1652 
1653       int permissionIndex = getPermissionIndex(packageInfo, permissionName);
1654       if (permissionIndex < 0) {
1655         throw new SecurityException(
1656             "Permission " + permissionName + " not requested by package " + packageName);
1657       }
1658 
1659       packageInfo.requestedPermissionsFlags[permissionIndex] &= ~REQUESTED_PERMISSION_GRANTED;
1660 
1661       uid = uidForPackage.get(packageName);
1662     }
1663 
1664     if (RuntimeEnvironment.getApiLevel() >= VERSION_CODES.M && uid != null) {
1665       for (Object listener : permissionListeners) {
1666         ((OnPermissionsChangedListener) listener).onPermissionsChanged(uid);
1667       }
1668     }
1669   }
1670 
checkPermissionGrantStateInitialized(PackageInfo packageInfo)1671   private void checkPermissionGrantStateInitialized(PackageInfo packageInfo) {
1672     if (packageInfo.requestedPermissionsFlags == null) {
1673       // In the real OS this would never be null, but tests don't necessarily initialize this
1674       // structure.
1675       throw new SecurityException(
1676           "Permission grant state (PackageInfo.requestedPermissionFlags) "
1677               + "is null. This operation requires this variable to be initialized.");
1678     }
1679   }
1680 
1681   /**
1682    * Returns the index of the given permission in the PackageInfo.requestedPermissions array, or -1
1683    * if it's not found.
1684    */
getPermissionIndex(PackageInfo packageInfo, String permissionName)1685   private int getPermissionIndex(PackageInfo packageInfo, String permissionName) {
1686     if (packageInfo.requestedPermissions != null) {
1687       for (int i = 0; i < packageInfo.requestedPermissions.length; i++) {
1688         if (permissionName.equals(packageInfo.requestedPermissions[i])) {
1689           return i;
1690         }
1691       }
1692     }
1693 
1694     return -1;
1695   }
1696 
1697   /**
1698    * This method differs from the real implementation in that we only return the permission flags
1699    * that were added via updatePermissionFlags, and do not perform any verification of permissions,
1700    * packages or users.
1701    */
1702   @Implementation(minSdk = M)
getPermissionFlags(String permissionName, String packageName, UserHandle user)1703   protected int getPermissionFlags(String permissionName, String packageName, UserHandle user) {
1704     if (permissionFlags.containsKey(packageName)) {
1705       return permissionFlags.get(packageName).getOrDefault(permissionName, /* defaultValue= */ 0);
1706     }
1707 
1708     return 0;
1709   }
1710 
1711   /**
1712    * This method differs from the real implementation in that no permission checking or package
1713    * existent checks are performed here.
1714    */
1715   @Implementation(minSdk = M)
updatePermissionFlags( String permissionName, String packageName, @PackageManager.PermissionFlags int flagMask, @PackageManager.PermissionFlags int flagValues, UserHandle user)1716   protected void updatePermissionFlags(
1717       String permissionName,
1718       String packageName,
1719       @PackageManager.PermissionFlags int flagMask,
1720       @PackageManager.PermissionFlags int flagValues,
1721       UserHandle user) {
1722     if (!permissionFlags.containsKey(packageName)) {
1723       permissionFlags.put(packageName, new HashMap<String, Integer>());
1724     }
1725 
1726     int existingFlags =
1727         permissionFlags.get(packageName).getOrDefault(permissionName, /* defaultValue= */ 0);
1728     int flagsToKeep = ~flagMask & existingFlags;
1729     int flagsToChange = flagMask & flagValues;
1730     int newFlags = flagsToKeep | flagsToChange;
1731 
1732     permissionFlags.get(packageName).put(permissionName, newFlags);
1733   }
1734 
1735   @Implementation
getUidForSharedUser(String sharedUserName)1736   protected int getUidForSharedUser(String sharedUserName) throws NameNotFoundException {
1737     return 0;
1738   }
1739 
1740   @Implementation(minSdk = N)
getInstalledPackagesAsUser(int flags, int userId)1741   protected List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
1742     return null;
1743   }
1744 
1745   @Implementation
getPackagesHoldingPermissions(String[] permissions, int flags)1746   protected List<PackageInfo> getPackagesHoldingPermissions(String[] permissions, int flags) {
1747     synchronized (lock) {
1748       List<PackageInfo> packageInfosWithPermissions = new ArrayList<>();
1749       for (PackageInfo packageInfo : packageInfos.values()) {
1750         for (String permission : permissions) {
1751           int permissionIndex = getPermissionIndex(packageInfo, permission);
1752           if (permissionIndex >= 0) {
1753             packageInfosWithPermissions.add(packageInfo);
1754             break;
1755           }
1756         }
1757       }
1758       return packageInfosWithPermissions;
1759     }
1760   }
1761 
1762   /**
1763    * This implementation relies on the limited list of platform permissions defined in {@link
1764    * ShadowPackageManager#AOSP_PLATFORM_PERMISSIONS} and on permissions added using the
1765    * {ShadowPackageManager#addPermission} API (if they have a platform permission prefix). It will
1766    * not return an accurate grouping for all platform permissions that can be found on different
1767    * AOSP versions.
1768    */
1769   @Implementation(minSdk = S)
getGroupOfPlatformPermission( String permissionName, Executor executor, Consumer<String> callback)1770   protected void getGroupOfPlatformPermission(
1771       String permissionName, Executor executor, Consumer<String> callback) {
1772     if (!AOSP_PLATFORM_PERMISSIONS.containsKey(permissionName)
1773         && !permissionName.startsWith(AOSP_PLATFORM_PERMISSION_PREFIX)) {
1774       executor.execute(() -> callback.accept(null));
1775       return;
1776     }
1777 
1778     String permissionGroup = null;
1779     try {
1780       // Use getPermissionInfo to allow for overrides of platform permissions.
1781       // Note that overrides may remove or change the group of a permission.
1782       PermissionInfo permissionInfo = getPermissionInfo(permissionName, /* flags= */ 0);
1783       permissionGroup = permissionInfo.group;
1784     } catch (NameNotFoundException ignored) {
1785       // Ignore permissions that are not found.
1786     }
1787     final String finalPermissionGroup = permissionGroup;
1788     executor.execute(() -> callback.accept(finalPermissionGroup));
1789   }
1790 
1791   /**
1792    * This implementation relies on the limited list of platform permissions defined in {@link
1793    * ShadowPackageManager#AOSP_PLATFORM_PERMISSIONS} and on permissions added using the
1794    * {ShadowPackageManager#addPermission} API (if they have a platform permission prefix). It will
1795    * not return an accurate grouping for all platform permissions that can be found on different
1796    * AOSP versions.
1797    */
1798   @Implementation(minSdk = S)
getPlatformPermissionsForGroup( String permissionGroupName, Executor executor, Consumer<List<String>> callback)1799   protected void getPlatformPermissionsForGroup(
1800       String permissionGroupName, Executor executor, Consumer<List<String>> callback) {
1801     List<String> permissions = new ArrayList<>();
1802 
1803     if (!AOSP_PLATFORM_PERMISSION_GROUPS.containsKey(permissionGroupName)
1804         && !permissionGroupName.startsWith(AOSP_PLATFORM_PERMISSION_GROUP_PREFIX)) {
1805       executor.execute(() -> callback.accept(permissions));
1806       return;
1807     }
1808 
1809     Set<String> permissionNames = new HashSet<>();
1810     permissionNames.addAll(AOSP_PLATFORM_PERMISSIONS.keySet());
1811     permissionNames.addAll(extraPermissions.keySet());
1812 
1813     for (String permissionName : permissionNames) {
1814       // Only check platform permissions.
1815       if (!AOSP_PLATFORM_PERMISSIONS.containsKey(permissionName)
1816           && !permissionName.startsWith(AOSP_PLATFORM_PERMISSION_PREFIX)) {
1817         continue;
1818       }
1819       try {
1820         // Use getPermissionInfo to allow for overrides of platform permissions.
1821         // Note that overrides may remove or change the group of a permission.
1822         PermissionInfo permissionInfo = getPermissionInfo(permissionName, /* flags= */ 0);
1823         if (permissionGroupName.equals(permissionInfo.group)) {
1824           permissions.add(permissionInfo.name);
1825         }
1826       } catch (NameNotFoundException ignored) {
1827         // Ignore permissions that are not found.
1828       }
1829     }
1830 
1831     executor.execute(() -> callback.accept(permissions));
1832   }
1833 
1834   /** Behaves as {@link #resolveActivity(Intent, int)} and currently ignores userId. */
1835   @Implementation
resolveActivityAsUser(Intent intent, int flags, int userId)1836   protected ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId) {
1837     return resolveActivity(intent, flags);
1838   }
1839 
1840   @Implementation(minSdk = TIRAMISU)
resolveActivityAsUser( Intent intent, @ClassName("android.content.pm.PackageManager$ResolveInfoFlags") Object flags, int userId)1841   protected ResolveInfo resolveActivityAsUser(
1842       Intent intent,
1843       @ClassName("android.content.pm.PackageManager$ResolveInfoFlags") Object flags,
1844       int userId) {
1845     return resolveActivity(intent, (int) ((ResolveInfoFlags) flags).getValue());
1846   }
1847 
1848   @Implementation(minSdk = TIRAMISU)
resolveServiceAsUser( Intent intent, @ClassName("android.content.pm.PackageManager$ResolveInfoFlags") Object flags, int userId)1849   protected ResolveInfo resolveServiceAsUser(
1850       Intent intent,
1851       @ClassName("android.content.pm.PackageManager$ResolveInfoFlags") Object flags,
1852       int userId) {
1853     return resolveService(intent, (int) ((ResolveInfoFlags) flags).getValue());
1854   }
1855 
1856   @Implementation
queryIntentActivityOptions( ComponentName caller, Intent[] specifics, Intent intent, int flags)1857   protected List<ResolveInfo> queryIntentActivityOptions(
1858       ComponentName caller, Intent[] specifics, Intent intent, int flags) {
1859     return null;
1860   }
1861 
1862   @Implementation(minSdk = N)
queryBroadcastReceiversAsUser(Intent intent, int flags, int userId)1863   protected List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
1864     return null;
1865   }
1866 
1867   @Implementation
queryContentProviders(String processName, int uid, int flags)1868   protected List<ProviderInfo> queryContentProviders(String processName, int uid, int flags) {
1869     return null;
1870   }
1871 
1872   @Implementation
getInstrumentationInfo(ComponentName className, int flags)1873   protected InstrumentationInfo getInstrumentationInfo(ComponentName className, int flags)
1874       throws NameNotFoundException {
1875     return null;
1876   }
1877 
1878   @Implementation
queryInstrumentation(String targetPackage, int flags)1879   protected List<InstrumentationInfo> queryInstrumentation(String targetPackage, int flags) {
1880     return null;
1881   }
1882 
1883   @Nullable
1884   @Implementation
getDrawable( String packageName, @DrawableRes int resId, @Nullable ApplicationInfo appInfo)1885   protected Drawable getDrawable(
1886       String packageName, @DrawableRes int resId, @Nullable ApplicationInfo appInfo) {
1887     Drawable result = drawables.get(new Pair<>(packageName, resId));
1888     if (result != null) {
1889       return result;
1890     }
1891     return reflector(ReflectorApplicationPackageManager.class, realObject)
1892         .getDrawable(packageName, resId, appInfo);
1893   }
1894 
1895   /**
1896    * Returns a user stored String resource with {@code resId} corresponding to {@code packageName}.
1897    * User can store this String via {@link #addStringResource(String, int, String)}.
1898    *
1899    * <p>Real method is called if the user has not stored a String corresponding to {@code resId} and
1900    * {@code packageName}.
1901    */
1902   @Nullable
1903   @Implementation
getText(String packageName, int resId, ApplicationInfo appInfo)1904   protected CharSequence getText(String packageName, int resId, ApplicationInfo appInfo) {
1905     if (stringResources.containsKey(packageName)
1906         && stringResources.get(packageName).containsKey(resId)) {
1907       return stringResources.get(packageName).get(resId);
1908     }
1909     return reflector(ReflectorApplicationPackageManager.class, realObject)
1910         .getText(packageName, resId, appInfo);
1911   }
1912 
1913   @Implementation
getActivityIcon(ComponentName activityName)1914   protected Drawable getActivityIcon(ComponentName activityName) throws NameNotFoundException {
1915     Drawable result = drawableList.get(activityName);
1916     if (result != null) {
1917       return result;
1918     }
1919     return reflector(ReflectorApplicationPackageManager.class, realObject)
1920         .getActivityIcon(activityName);
1921   }
1922 
1923   @Implementation
getDefaultActivityIcon()1924   protected Drawable getDefaultActivityIcon() {
1925     return Resources.getSystem().getDrawable(com.android.internal.R.drawable.sym_def_app_icon);
1926   }
1927 
1928   @Implementation
getResourcesForActivity(ComponentName activityName)1929   protected Resources getResourcesForActivity(ComponentName activityName)
1930       throws NameNotFoundException {
1931     return getResourcesForApplication(activityName.getPackageName());
1932   }
1933 
1934   @Implementation
getResourcesForApplication(String appPackageName)1935   protected Resources getResourcesForApplication(String appPackageName)
1936       throws NameNotFoundException {
1937     synchronized (lock) {
1938       if (getContext().getPackageName().equals(appPackageName)) {
1939         return getContext().getResources();
1940       } else if (packageInfos.containsKey(appPackageName)) {
1941         Resources appResources = resources.get(appPackageName);
1942         if (appResources == null) {
1943           appResources = new Resources(new AssetManager(), null, null);
1944           resources.put(appPackageName, appResources);
1945         }
1946         return appResources;
1947       }
1948       throw new NameNotFoundException(appPackageName);
1949     }
1950   }
1951 
1952   @Implementation
getResourcesForApplicationAsUser(String appPackageName, int userId)1953   protected Resources getResourcesForApplicationAsUser(String appPackageName, int userId)
1954       throws NameNotFoundException {
1955     return null;
1956   }
1957 
1958   @Implementation(minSdk = M)
addOnPermissionsChangeListener( @lassName"android.content.pm.PackageManager$OnPermissionsChangedListener") Object listener)1959   protected void addOnPermissionsChangeListener(
1960       @ClassName("android.content.pm.PackageManager$OnPermissionsChangedListener")
1961           Object listener) {
1962     permissionListeners.add(listener);
1963   }
1964 
1965   @Implementation(minSdk = M)
removeOnPermissionsChangeListener( @lassName"android.content.pm.PackageManager$OnPermissionsChangedListener") Object listener)1966   protected void removeOnPermissionsChangeListener(
1967       @ClassName("android.content.pm.PackageManager$OnPermissionsChangedListener")
1968           Object listener) {
1969     permissionListeners.remove(listener);
1970   }
1971 
1972   @Implementation(maxSdk = O_MR1)
installPackage( Uri packageURI, @ClassName("android.content.pm.IPackageInstallObserver") Object observer, int flags, String installerPackageName)1973   protected void installPackage(
1974       Uri packageURI,
1975       @ClassName("android.content.pm.IPackageInstallObserver") Object observer,
1976       int flags,
1977       String installerPackageName) {}
1978 
1979   @Implementation
installExistingPackage(String packageName)1980   protected int installExistingPackage(String packageName) throws NameNotFoundException {
1981     return 0;
1982   }
1983 
1984   @Implementation(minSdk = N)
installExistingPackageAsUser(String packageName, int userId)1985   protected int installExistingPackageAsUser(String packageName, int userId)
1986       throws NameNotFoundException {
1987     return 0;
1988   }
1989 
1990   @Implementation(minSdk = M)
verifyIntentFilter(int id, int verificationCode, List<String> failedDomains)1991   protected void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {}
1992 
1993   @Implementation(minSdk = N)
getIntentVerificationStatusAsUser(String packageName, int userId)1994   protected int getIntentVerificationStatusAsUser(String packageName, int userId) {
1995     return 0;
1996   }
1997 
1998   @Implementation(minSdk = N)
updateIntentVerificationStatusAsUser( String packageName, int status, int userId)1999   protected boolean updateIntentVerificationStatusAsUser(
2000       String packageName, int status, int userId) {
2001     return false;
2002   }
2003 
2004   @Implementation(minSdk = M)
getIntentFilterVerifications(String packageName)2005   protected List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) {
2006     return null;
2007   }
2008 
2009   @Implementation(minSdk = M)
getAllIntentFilters(String packageName)2010   protected List<IntentFilter> getAllIntentFilters(String packageName) {
2011     return null;
2012   }
2013 
2014   @Implementation(minSdk = N)
getDefaultBrowserPackageNameAsUser(int userId)2015   protected String getDefaultBrowserPackageNameAsUser(int userId) {
2016     return defaultBrowsers.get(userId);
2017   }
2018 
2019   @Implementation(minSdk = N)
setDefaultBrowserPackageNameAsUser(String packageName, int userId)2020   protected boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
2021     defaultBrowsers.put(userId, packageName);
2022     return true;
2023   }
2024 
2025   @Implementation(minSdk = M)
getMoveStatus(int moveId)2026   protected int getMoveStatus(int moveId) {
2027     return 0;
2028   }
2029 
2030   @Implementation(minSdk = M)
registerMoveCallback( @lassName"android.content.pm.PackageManager$MoveCallback") Object callback, Handler handler)2031   protected void registerMoveCallback(
2032       @ClassName("android.content.pm.PackageManager$MoveCallback") Object callback,
2033       Handler handler) {}
2034 
2035   @Implementation(minSdk = M)
unregisterMoveCallback( @lassName"android.content.pm.PackageManager$MoveCallback") Object callback)2036   protected void unregisterMoveCallback(
2037       @ClassName("android.content.pm.PackageManager$MoveCallback") Object callback) {}
2038 
2039   @Implementation(minSdk = M)
movePackage( String packageName, @ClassName("android.os.storage.VolumeInfo") Object vol)2040   protected int movePackage(
2041       String packageName, @ClassName("android.os.storage.VolumeInfo") Object vol) {
2042     return 0;
2043   }
2044 
2045   @Implementation(minSdk = M)
getPackageCurrentVolume( @lassName"android.content.pm.ApplicationInfo") Object app)2046   protected @ClassName("android.os.storage.VolumeInfo") Object getPackageCurrentVolume(
2047       @ClassName("android.content.pm.ApplicationInfo") Object app) {
2048     return null;
2049   }
2050 
2051   @Implementation(minSdk = M)
getPackageCandidateVolumes(ApplicationInfo app)2052   protected List<VolumeInfo> getPackageCandidateVolumes(ApplicationInfo app) {
2053     return null;
2054   }
2055 
2056   @Implementation(minSdk = M)
movePrimaryStorage(@lassName"android.os.storage.VolumeInfo") Object vol)2057   protected int movePrimaryStorage(@ClassName("android.os.storage.VolumeInfo") Object vol) {
2058     return 0;
2059   }
2060 
2061   @Implementation(minSdk = M)
2062   protected @Nullable @ClassName("android.os.storage.VolumeInfo") Object
getPrimaryStorageCurrentVolume()2063       getPrimaryStorageCurrentVolume() {
2064     return null;
2065   }
2066 
2067   @Implementation(minSdk = M)
getPrimaryStorageCandidateVolumes()2068   protected @NonNull List<VolumeInfo> getPrimaryStorageCandidateVolumes() {
2069     return null;
2070   }
2071 
2072   @Implementation(minSdk = N)
deletePackageAsUser( String packageName, IPackageDeleteObserver observer, int flags, int userId)2073   protected void deletePackageAsUser(
2074       String packageName, IPackageDeleteObserver observer, int flags, int userId) {}
2075 
2076   @Implementation
clearApplicationUserData(String packageName, IPackageDataObserver observer)2077   protected void clearApplicationUserData(String packageName, IPackageDataObserver observer) {
2078     clearedApplicationUserDataPackages.add(packageName);
2079   }
2080 
2081   @Implementation
deleteApplicationCacheFiles(String packageName, IPackageDataObserver observer)2082   protected void deleteApplicationCacheFiles(String packageName, IPackageDataObserver observer) {}
2083 
2084   @Implementation(minSdk = N)
deleteApplicationCacheFilesAsUser( String packageName, int userId, IPackageDataObserver observer)2085   protected void deleteApplicationCacheFilesAsUser(
2086       String packageName, int userId, IPackageDataObserver observer) {}
2087 
2088   @Implementation(minSdk = M)
freeStorage(String volumeUuid, long freeStorageSize, IntentSender pi)2089   protected void freeStorage(String volumeUuid, long freeStorageSize, IntentSender pi) {}
2090 
2091   @Implementation(minSdk = N, maxSdk = O_MR1)
setPackagesSuspendedAsUser( String[] packageNames, boolean suspended, int userId)2092   protected String[] setPackagesSuspendedAsUser(
2093       String[] packageNames, boolean suspended, int userId) {
2094     return null;
2095   }
2096 
2097   @Implementation(minSdk = N)
isPackageSuspendedForUser(String packageName, int userId)2098   protected boolean isPackageSuspendedForUser(String packageName, int userId) {
2099     return false;
2100   }
2101 
2102   @Implementation
addPackageToPreferred(String packageName)2103   protected void addPackageToPreferred(String packageName) {}
2104 
2105   @Implementation
removePackageFromPreferred(String packageName)2106   protected void removePackageFromPreferred(String packageName) {}
2107 
2108   @Implementation
getPreferredPackages(int flags)2109   protected List<PackageInfo> getPreferredPackages(int flags) {
2110     return null;
2111   }
2112 
2113   @Implementation
addPreferredActivity( IntentFilter filter, int match, ComponentName[] set, ComponentName activity)2114   public void addPreferredActivity(
2115       IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
2116     addPreferredActivityInternal(filter, activity, preferredActivities);
2117   }
2118 
2119   @Implementation
replacePreferredActivity( IntentFilter filter, int match, ComponentName[] set, ComponentName activity)2120   protected void replacePreferredActivity(
2121       IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
2122     addPreferredActivity(filter, match, set, activity);
2123   }
2124 
2125   @Implementation
getPreferredActivities( List<IntentFilter> outFilters, List<ComponentName> outActivities, String packageName)2126   public int getPreferredActivities(
2127       List<IntentFilter> outFilters, List<ComponentName> outActivities, String packageName) {
2128     return getPreferredActivitiesInternal(
2129         outFilters, outActivities, packageName, preferredActivities);
2130   }
2131 
2132   @Implementation
clearPackagePreferredActivities(String packageName)2133   protected void clearPackagePreferredActivities(String packageName) {
2134     clearPackagePreferredActivitiesInternal(packageName, preferredActivities);
2135   }
2136 
2137   @Implementation
getHomeActivities(List<ResolveInfo> outActivities)2138   protected ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
2139     return null;
2140   }
2141 
2142   @Implementation(minSdk = N)
flushPackageRestrictionsAsUser(int userId)2143   protected void flushPackageRestrictionsAsUser(int userId) {}
2144 
2145   @Implementation
setApplicationHiddenSettingAsUser( String packageName, boolean hidden, UserHandle user)2146   protected boolean setApplicationHiddenSettingAsUser(
2147       String packageName, boolean hidden, UserHandle user) {
2148     synchronized (lock) {
2149       // Note that this ignores the UserHandle parameter
2150       if (!packageInfos.containsKey(packageName)) {
2151         // Package doesn't exist
2152         return false;
2153       }
2154       if (hidden) {
2155         hiddenPackages.add(packageName);
2156       } else {
2157         hiddenPackages.remove(packageName);
2158       }
2159 
2160       return true;
2161     }
2162   }
2163 
2164   @Implementation
getApplicationHiddenSettingAsUser(String packageName, UserHandle user)2165   protected boolean getApplicationHiddenSettingAsUser(String packageName, UserHandle user) {
2166     // Note that this ignores the UserHandle parameter
2167     synchronized (lock) {
2168       if (!packageInfos.containsKey(packageName)) {
2169         // Match Android behaviour of returning true if package isn't found
2170         return true;
2171       }
2172       return hiddenPackages.contains(packageName);
2173     }
2174   }
2175 
2176   @Implementation
getVerifierDeviceIdentity()2177   protected VerifierDeviceIdentity getVerifierDeviceIdentity() {
2178     return null;
2179   }
2180 
2181   @Implementation(minSdk = LOLLIPOP_MR1)
isUpgrade()2182   protected boolean isUpgrade() {
2183     return false;
2184   }
2185 
2186   @Implementation
isPackageAvailable(String packageName)2187   protected boolean isPackageAvailable(String packageName) {
2188     return false;
2189   }
2190 
2191   @Implementation
addCrossProfileIntentFilter( IntentFilter filter, int sourceUserId, int targetUserId, int flags)2192   protected void addCrossProfileIntentFilter(
2193       IntentFilter filter, int sourceUserId, int targetUserId, int flags) {}
2194 
2195   @Implementation
clearCrossProfileIntentFilters(int sourceUserId)2196   protected void clearCrossProfileIntentFilters(int sourceUserId) {}
2197 
2198   /**
2199    * Gets the unbadged icon based on the values set by {@link
2200    * ShadowPackageManager#setUnbadgedApplicationIcon} or returns null if nothing has been set.
2201    */
2202   @Implementation(minSdk = LOLLIPOP_MR1)
loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo)2203   protected Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
2204     Drawable result = unbadgedApplicationIcons.get(itemInfo.packageName);
2205     if (result != null) {
2206       return result;
2207     }
2208     return reflector(ReflectorApplicationPackageManager.class, realObject)
2209         .loadUnbadgedItemIcon(itemInfo, appInfo);
2210   }
2211 
2212   /**
2213    * Adds a profile badge to the icon.
2214    *
2215    * <p>This implementation just returns the unbadged icon, as some default implementations add an
2216    * internal resource to the icon that is unavailable to Robolectric.
2217    */
2218   @Implementation
getUserBadgedIcon(Drawable icon, UserHandle user)2219   protected Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
2220     return icon;
2221   }
2222 
2223   @Implementation(minSdk = O)
canRequestPackageInstalls()2224   protected boolean canRequestPackageInstalls() {
2225     return canRequestPackageInstalls;
2226   }
2227 
2228   @Implementation(minSdk = O)
getChangedPackages( int sequenceNumber)2229   protected @ClassName("android.content.pm.ChangedPackages") Object getChangedPackages(
2230       int sequenceNumber) {
2231     if (sequenceNumber < 0 || sequenceNumberChangedPackagesMap.get(sequenceNumber).isEmpty()) {
2232       return null;
2233     }
2234     return new ChangedPackages(
2235         sequenceNumber + 1, new ArrayList<>(sequenceNumberChangedPackagesMap.get(sequenceNumber)));
2236   }
2237 
2238   @Implementation(minSdk = P)
getSystemTextClassifierPackageName()2239   public String getSystemTextClassifierPackageName() {
2240     return "";
2241   }
2242 
2243   @Implementation(minSdk = P)
2244   @HiddenApi
setPackagesSuspended( String[] packageNames, boolean suspended, PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage)2245   protected String[] setPackagesSuspended(
2246       String[] packageNames,
2247       boolean suspended,
2248       PersistableBundle appExtras,
2249       PersistableBundle launcherExtras,
2250       String dialogMessage) {
2251     return setPackagesSuspended(
2252         packageNames, suspended, appExtras, launcherExtras, dialogMessage, /* dialogInfo= */ null);
2253   }
2254 
2255   @Implementation(minSdk = Q)
2256   @HiddenApi
setPackagesSuspended( String[] packageNames, boolean suspended, PersistableBundle appExtras, PersistableBundle launcherExtras, @ClassName("android.content.pm.SuspendDialogInfo") Object dialogInfo)2257   protected String[] setPackagesSuspended(
2258       String[] packageNames,
2259       boolean suspended,
2260       PersistableBundle appExtras,
2261       PersistableBundle launcherExtras,
2262       @ClassName("android.content.pm.SuspendDialogInfo") Object dialogInfo) {
2263     return setPackagesSuspended(
2264         packageNames, suspended, appExtras, launcherExtras, /* dialogMessage= */ null, dialogInfo);
2265   }
2266 
2267   @Implementation(minSdk = R)
isAutoRevokeWhitelisted()2268   protected boolean isAutoRevokeWhitelisted() {
2269     return whitelisted;
2270   }
2271 
2272   /**
2273    * Sets {@code packageNames} suspension status to {@code suspended} in the package manager.
2274    *
2275    * <p>At least one of {@code dialogMessage} and {@code dialogInfo} should be null.
2276    */
setPackagesSuspended( String[] packageNames, boolean suspended, PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage, Object dialogInfo)2277   private String[] setPackagesSuspended(
2278       String[] packageNames,
2279       boolean suspended,
2280       PersistableBundle appExtras,
2281       PersistableBundle launcherExtras,
2282       String dialogMessage,
2283       Object dialogInfo) {
2284     if (hasProfileOwnerOrDeviceOwnerOnCurrentUser()
2285         && (VERSION.SDK_INT < VERSION_CODES.Q
2286             || !isCurrentApplicationProfileOwnerOrDeviceOwner())) {
2287       throw new UnsupportedOperationException();
2288     }
2289     ArrayList<String> unupdatedPackages = new ArrayList<>();
2290     for (String packageName : packageNames) {
2291       if (!canSuspendPackage(packageName)) {
2292         unupdatedPackages.add(packageName);
2293         continue;
2294       }
2295       PackageSetting setting = packageSettings.get(packageName);
2296       if (setting == null) {
2297         unupdatedPackages.add(packageName);
2298         continue;
2299       }
2300       setting.setSuspended(suspended, dialogMessage, dialogInfo, appExtras, launcherExtras);
2301     }
2302     return unupdatedPackages.toArray(new String[0]);
2303   }
2304 
2305   /** Returns whether the current user profile has a profile owner or a device owner. */
isCurrentApplicationProfileOwnerOrDeviceOwner()2306   private boolean isCurrentApplicationProfileOwnerOrDeviceOwner() {
2307     String currentApplication = getContext().getPackageName();
2308     DevicePolicyManager devicePolicyManager =
2309         (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
2310     return devicePolicyManager.isProfileOwnerApp(currentApplication)
2311         || devicePolicyManager.isDeviceOwnerApp(currentApplication);
2312   }
2313 
2314   /** Returns whether the current user profile has a profile owner or a device owner. */
hasProfileOwnerOrDeviceOwnerOnCurrentUser()2315   private boolean hasProfileOwnerOrDeviceOwnerOnCurrentUser() {
2316     DevicePolicyManager devicePolicyManager =
2317         (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
2318     return devicePolicyManager.getProfileOwner() != null
2319         || (UserHandle.of(UserHandle.myUserId()).isSystem()
2320             && devicePolicyManager.getDeviceOwner() != null);
2321   }
2322 
canSuspendPackage(String packageName)2323   private boolean canSuspendPackage(String packageName) {
2324     // This code approximately mirrors PackageManagerService#canSuspendPackageForUserLocked.
2325     return !packageName.equals(getContext().getPackageName())
2326         && !isPackageDeviceAdmin(packageName)
2327         && !isPackageActiveLauncher(packageName)
2328         && !isPackageRequiredInstaller(packageName)
2329         && !isPackageRequiredUninstaller(packageName)
2330         && !isPackageRequiredVerifier(packageName)
2331         && !isPackageDefaultDialer(packageName)
2332         && !packageName.equals(PLATFORM_PACKAGE_NAME);
2333   }
2334 
isPackageDeviceAdmin(String packageName)2335   private boolean isPackageDeviceAdmin(String packageName) {
2336     DevicePolicyManager devicePolicyManager =
2337         (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
2338     // Strictly speaking, this should be devicePolicyManager.getDeviceOwnerComponentOnAnyUser(),
2339     // but that method is currently not shadowed.
2340     return packageName.equals(devicePolicyManager.getDeviceOwner());
2341   }
2342 
isPackageActiveLauncher(String packageName)2343   private boolean isPackageActiveLauncher(String packageName) {
2344     Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
2345     ResolveInfo info = resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
2346     return info != null && packageName.equals(info.activityInfo.packageName);
2347   }
2348 
isPackageRequiredInstaller(String packageName)2349   private boolean isPackageRequiredInstaller(String packageName) {
2350     Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
2351     intent.addCategory(Intent.CATEGORY_DEFAULT);
2352     intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
2353     ResolveInfo info =
2354         resolveActivity(
2355             intent,
2356             PackageManager.MATCH_SYSTEM_ONLY
2357                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
2358                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
2359     return info != null && packageName.equals(info.activityInfo.packageName);
2360   }
2361 
isPackageRequiredUninstaller(String packageName)2362   private boolean isPackageRequiredUninstaller(String packageName) {
2363     final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
2364     intent.addCategory(Intent.CATEGORY_DEFAULT);
2365     intent.setData(Uri.fromParts(PACKAGE_SCHEME, "foo.bar", null));
2366     ResolveInfo info =
2367         resolveActivity(
2368             intent,
2369             PackageManager.MATCH_SYSTEM_ONLY
2370                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
2371                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
2372     return info != null && packageName.equals(info.activityInfo.packageName);
2373   }
2374 
isPackageRequiredVerifier(String packageName)2375   private boolean isPackageRequiredVerifier(String packageName) {
2376     final Intent intent = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
2377     List<ResolveInfo> infos =
2378         queryBroadcastReceivers(
2379             intent,
2380             PackageManager.MATCH_SYSTEM_ONLY
2381                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
2382                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
2383     if (infos != null) {
2384       for (ResolveInfo info : infos) {
2385         if (packageName.equals(info.activityInfo.packageName)) {
2386           return true;
2387         }
2388       }
2389     }
2390     return false;
2391   }
2392 
isPackageDefaultDialer(String packageName)2393   private boolean isPackageDefaultDialer(String packageName) {
2394     TelecomManager telecomManager =
2395         (TelecomManager) getContext().getSystemService(Context.TELECOM_SERVICE);
2396     return packageName.equals(telecomManager.getDefaultDialerPackage());
2397   }
2398 
2399   @HiddenApi
2400   @Implementation(minSdk = Q)
2401   @RequiresPermission(permission.SUSPEND_APPS)
getUnsuspendablePackages(String[] packageNames)2402   protected String[] getUnsuspendablePackages(String[] packageNames) {
2403     checkNotNull(packageNames, "packageNames cannot be null");
2404     if (getContext().checkSelfPermission(permission.SUSPEND_APPS)
2405         != PackageManager.PERMISSION_GRANTED) {
2406       throw new SecurityException("Current process does not have " + permission.SUSPEND_APPS);
2407     }
2408     ArrayList<String> unsuspendablePackages = new ArrayList<>();
2409     for (String packageName : packageNames) {
2410       if (!canSuspendPackage(packageName)) {
2411         unsuspendablePackages.add(packageName);
2412       }
2413     }
2414     return unsuspendablePackages.toArray(new String[0]);
2415   }
2416 
2417   @HiddenApi
2418   @Implementation(minSdk = P)
isPackageSuspended(String packageName)2419   protected boolean isPackageSuspended(String packageName) throws NameNotFoundException {
2420     PackageSetting setting = packageSettings.get(packageName);
2421     if (setting == null) {
2422       throw new NameNotFoundException(packageName);
2423     }
2424     return setting.isSuspended();
2425   }
2426 
2427   @Implementation(minSdk = O)
isInstantApp(String packageName)2428   protected boolean isInstantApp(String packageName) {
2429     synchronized (lock) {
2430       PackageInfo pi = packageInfos.get(packageName);
2431       if (pi == null) {
2432         return false;
2433       }
2434       ApplicationInfo ai = pi.applicationInfo;
2435       if (ai == null) {
2436         return false;
2437       }
2438       return ai.isInstantApp();
2439     }
2440   }
2441 
2442   @HiddenApi
2443   @Implementation(minSdk = Q)
setDistractingPackageRestrictions(String[] packages, int restrictionFlags)2444   protected String[] setDistractingPackageRestrictions(String[] packages, int restrictionFlags) {
2445     for (String pkg : packages) {
2446       distractingPackageRestrictions.put(pkg, restrictionFlags);
2447     }
2448     return new String[0];
2449   }
2450 
getContext()2451   private Context getContext() {
2452     return reflector(ReflectorApplicationPackageManager.class, realObject).getContext();
2453   }
2454 
2455   /** Stub that will always throw. */
2456   @Implementation(minSdk = S)
getProperty( String propertyName, String packageName)2457   protected @ClassName("android.content.pm.PackageManager$Property") Object getProperty(
2458       String propertyName, String packageName) throws NameNotFoundException {
2459     // TODO: in future read this value from parsed manifest
2460     throw new NameNotFoundException("unsupported");
2461   }
2462 
2463   /** Stub that will always throw. */
2464   @Implementation(minSdk = S)
getProperty( String propertyName, ComponentName name)2465   protected @ClassName("android.content.pm.PackageManager$Property") Object getProperty(
2466       String propertyName, ComponentName name) throws NameNotFoundException {
2467     // TODO: in future read this value from parsed manifest
2468     throw new NameNotFoundException("unsupported");
2469   }
2470 
2471   /** Reflector interface for {@link ApplicationPackageManager}'s internals. */
2472   @ForType(ApplicationPackageManager.class)
2473   private interface ReflectorApplicationPackageManager {
2474 
2475     @Direct
getResourcesForApplication(@onNull ApplicationInfo applicationInfo)2476     Resources getResourcesForApplication(@NonNull ApplicationInfo applicationInfo);
2477 
2478     @Direct
getDrawable( String packageName, @DrawableRes int resId, @Nullable ApplicationInfo appInfo)2479     Drawable getDrawable(
2480         String packageName, @DrawableRes int resId, @Nullable ApplicationInfo appInfo);
2481 
2482     @Direct
getText(String packageName, @StringRes int resId, ApplicationInfo appInfo)2483     CharSequence getText(String packageName, @StringRes int resId, ApplicationInfo appInfo);
2484 
2485     @Direct
getActivityIcon(ComponentName activityName)2486     Drawable getActivityIcon(ComponentName activityName);
2487 
2488     @Direct
loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo)2489     Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo);
2490 
2491     @Direct
getPackageArchiveInfo(String archiveFilePath, int flags)2492     PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags);
2493 
2494     @Accessor("mContext")
getContext()2495     Context getContext();
2496   }
2497 
2498   /** Returns the list of package names that were requested to be cleared. */
getClearedApplicationUserDataPackages()2499   public List<String> getClearedApplicationUserDataPackages() {
2500     return Collections.unmodifiableList(clearedApplicationUserDataPackages);
2501   }
2502 }
2503