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