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