1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.content.pm; 18 19 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; 20 import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; 21 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; 22 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; 23 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 24 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; 25 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 26 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 27 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; 28 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 29 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED; 30 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE; 31 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 32 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE; 33 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; 34 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 35 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; 36 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; 37 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 38 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; 39 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; 40 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; 41 import static android.os.Build.VERSION_CODES.O; 42 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; 43 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; 44 45 import android.annotation.IntRange; 46 import android.annotation.NonNull; 47 import android.annotation.Nullable; 48 import android.annotation.TestApi; 49 import android.app.ActivityManager; 50 import android.content.ComponentName; 51 import android.content.Intent; 52 import android.content.IntentFilter; 53 import android.content.pm.PackageParserCacheHelper.ReadHelper; 54 import android.content.pm.PackageParserCacheHelper.WriteHelper; 55 import android.content.pm.split.DefaultSplitAssetLoader; 56 import android.content.pm.split.SplitAssetDependencyLoader; 57 import android.content.pm.split.SplitAssetLoader; 58 import android.content.res.AssetManager; 59 import android.content.res.Configuration; 60 import android.content.res.Resources; 61 import android.content.res.TypedArray; 62 import android.content.res.XmlResourceParser; 63 import android.os.Build; 64 import android.os.Bundle; 65 import android.os.FileUtils; 66 import android.os.Parcel; 67 import android.os.Parcelable; 68 import android.os.PatternMatcher; 69 import android.os.SystemClock; 70 import android.os.SystemProperties; 71 import android.os.Trace; 72 import android.os.UserHandle; 73 import android.os.storage.StorageManager; 74 import android.system.ErrnoException; 75 import android.system.OsConstants; 76 import android.system.StructStat; 77 import android.text.TextUtils; 78 import android.util.ArrayMap; 79 import android.util.ArraySet; 80 import android.util.AttributeSet; 81 import android.util.Base64; 82 import android.util.DisplayMetrics; 83 import android.util.Log; 84 import android.util.Pair; 85 import android.util.Slog; 86 import android.util.SparseArray; 87 import android.util.TypedValue; 88 import android.util.apk.ApkSignatureSchemeV2Verifier; 89 import android.util.jar.StrictJarFile; 90 import android.view.Gravity; 91 92 import com.android.internal.R; 93 import com.android.internal.annotations.VisibleForTesting; 94 import com.android.internal.os.ClassLoaderFactory; 95 import com.android.internal.util.ArrayUtils; 96 import com.android.internal.util.XmlUtils; 97 98 import libcore.io.IoUtils; 99 100 import libcore.util.EmptyArray; 101 import org.xmlpull.v1.XmlPullParser; 102 import org.xmlpull.v1.XmlPullParserException; 103 104 import java.io.File; 105 import java.io.FileOutputStream; 106 import java.io.IOException; 107 import java.io.InputStream; 108 import java.io.PrintWriter; 109 import java.lang.reflect.Constructor; 110 import java.security.GeneralSecurityException; 111 import java.security.KeyFactory; 112 import java.security.NoSuchAlgorithmException; 113 import java.security.PublicKey; 114 import java.security.cert.Certificate; 115 import java.security.cert.CertificateEncodingException; 116 import java.security.spec.EncodedKeySpec; 117 import java.security.spec.InvalidKeySpecException; 118 import java.security.spec.X509EncodedKeySpec; 119 import java.util.ArrayList; 120 import java.util.Arrays; 121 import java.util.Collections; 122 import java.util.Comparator; 123 import java.util.Iterator; 124 import java.util.List; 125 import java.util.Set; 126 import java.util.UUID; 127 import java.util.concurrent.atomic.AtomicInteger; 128 import java.util.concurrent.atomic.AtomicReference; 129 import java.util.zip.ZipEntry; 130 131 /** 132 * Parser for package files (APKs) on disk. This supports apps packaged either 133 * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple 134 * APKs in a single directory. 135 * <p> 136 * Apps packaged as multiple APKs always consist of a single "base" APK (with a 137 * {@code null} split name) and zero or more "split" APKs (with unique split 138 * names). Any subset of those split APKs are a valid install, as long as the 139 * following constraints are met: 140 * <ul> 141 * <li>All APKs must have the exact same package name, version code, and signing 142 * certificates. 143 * <li>All APKs must have unique split names. 144 * <li>All installations must contain a single base APK. 145 * </ul> 146 * 147 * @hide 148 */ 149 public class PackageParser { 150 private static final boolean DEBUG_JAR = false; 151 private static final boolean DEBUG_PARSER = false; 152 private static final boolean DEBUG_BACKUP = false; 153 private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE; 154 private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100; 155 156 private static final String PROPERTY_CHILD_PACKAGES_ENABLED = 157 "persist.sys.child_packages_enabled"; 158 159 private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE && 160 SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false); 161 162 private static final int MAX_PACKAGES_PER_APK = 5; 163 164 public static final int APK_SIGNING_UNKNOWN = 0; 165 public static final int APK_SIGNING_V1 = 1; 166 public static final int APK_SIGNING_V2 = 2; 167 168 private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f; 169 170 // TODO: switch outError users to PackageParserException 171 // TODO: refactor "codePath" to "apkPath" 172 173 /** File name in an APK for the Android manifest. */ 174 private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; 175 176 /** Path prefix for apps on expanded storage */ 177 private static final String MNT_EXPAND = "/mnt/expand/"; 178 179 private static final String TAG_MANIFEST = "manifest"; 180 private static final String TAG_APPLICATION = "application"; 181 private static final String TAG_PACKAGE_VERIFIER = "package-verifier"; 182 private static final String TAG_OVERLAY = "overlay"; 183 private static final String TAG_KEY_SETS = "key-sets"; 184 private static final String TAG_PERMISSION_GROUP = "permission-group"; 185 private static final String TAG_PERMISSION = "permission"; 186 private static final String TAG_PERMISSION_TREE = "permission-tree"; 187 private static final String TAG_USES_PERMISSION = "uses-permission"; 188 private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; 189 private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23"; 190 private static final String TAG_USES_CONFIGURATION = "uses-configuration"; 191 private static final String TAG_USES_FEATURE = "uses-feature"; 192 private static final String TAG_FEATURE_GROUP = "feature-group"; 193 private static final String TAG_USES_SDK = "uses-sdk"; 194 private static final String TAG_SUPPORT_SCREENS = "supports-screens"; 195 private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast"; 196 private static final String TAG_INSTRUMENTATION = "instrumentation"; 197 private static final String TAG_ORIGINAL_PACKAGE = "original-package"; 198 private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; 199 private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture"; 200 private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens"; 201 private static final String TAG_SUPPORTS_INPUT = "supports-input"; 202 private static final String TAG_EAT_COMMENT = "eat-comment"; 203 private static final String TAG_PACKAGE = "package"; 204 private static final String TAG_RESTRICT_UPDATE = "restrict-update"; 205 private static final String TAG_USES_SPLIT = "uses-split"; 206 207 // [b/36551762] STOPSHIP remove the ability to expose components via meta-data 208 // Temporary workaround; allow meta-data to expose components to instant apps 209 private static final String META_DATA_INSTANT_APPS = "instantapps.clients.allowed"; 210 211 private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect"; 212 213 /** 214 * Bit mask of all the valid bits that can be set in recreateOnConfigChanges. 215 * @hide 216 */ 217 private static final int RECREATE_ON_CONFIG_CHANGES_MASK = 218 ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC; 219 220 // These are the tags supported by child packages 221 private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>(); 222 static { 223 CHILD_PACKAGE_TAGS.add(TAG_APPLICATION); 224 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION); 225 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M); 226 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23); 227 CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION); 228 CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE); 229 CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP); 230 CHILD_PACKAGE_TAGS.add(TAG_USES_SDK); 231 CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS); 232 CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION); 233 CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE); 234 CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS); 235 CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT); 236 CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT); 237 } 238 239 private static final boolean LOG_UNSAFE_BROADCASTS = false; 240 241 /** 242 * Total number of packages that were read from the cache. We use it only for logging. 243 */ 244 public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger(); 245 246 // Set of broadcast actions that are safe for manifest receivers 247 private static final Set<String> SAFE_BROADCASTS = new ArraySet<>(); 248 static { 249 SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED); 250 } 251 252 /** @hide */ 253 public static class NewPermissionInfo { 254 public final String name; 255 public final int sdkVersion; 256 public final int fileVersion; 257 258 public NewPermissionInfo(String name, int sdkVersion, int fileVersion) { 259 this.name = name; 260 this.sdkVersion = sdkVersion; 261 this.fileVersion = fileVersion; 262 } 263 } 264 265 /** @hide */ 266 public static class SplitPermissionInfo { 267 public final String rootPerm; 268 public final String[] newPerms; 269 public final int targetSdk; 270 271 public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) { 272 this.rootPerm = rootPerm; 273 this.newPerms = newPerms; 274 this.targetSdk = targetSdk; 275 } 276 } 277 278 /** 279 * List of new permissions that have been added since 1.0. 280 * NOTE: These must be declared in SDK version order, with permissions 281 * added to older SDKs appearing before those added to newer SDKs. 282 * If sdkVersion is 0, then this is not a permission that we want to 283 * automatically add to older apps, but we do want to allow it to be 284 * granted during a platform update. 285 * @hide 286 */ 287 public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] = 288 new PackageParser.NewPermissionInfo[] { 289 new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 290 android.os.Build.VERSION_CODES.DONUT, 0), 291 new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE, 292 android.os.Build.VERSION_CODES.DONUT, 0) 293 }; 294 295 /** 296 * List of permissions that have been split into more granular or dependent 297 * permissions. 298 * @hide 299 */ 300 public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] = 301 new PackageParser.SplitPermissionInfo[] { 302 // READ_EXTERNAL_STORAGE is always required when an app requests 303 // WRITE_EXTERNAL_STORAGE, because we can't have an app that has 304 // write access without read access. The hack here with the target 305 // target SDK version ensures that this grant is always done. 306 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 307 new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE }, 308 android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1), 309 new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS, 310 new String[] { android.Manifest.permission.READ_CALL_LOG }, 311 android.os.Build.VERSION_CODES.JELLY_BEAN), 312 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS, 313 new String[] { android.Manifest.permission.WRITE_CALL_LOG }, 314 android.os.Build.VERSION_CODES.JELLY_BEAN) 315 }; 316 317 /** 318 * @deprecated callers should move to explicitly passing around source path. 319 */ 320 @Deprecated 321 private String mArchiveSourcePath; 322 323 private String[] mSeparateProcesses; 324 private boolean mOnlyCoreApps; 325 private DisplayMetrics mMetrics; 326 private Callback mCallback; 327 private File mCacheDir; 328 329 private static final int SDK_VERSION = Build.VERSION.SDK_INT; 330 private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES; 331 332 private int mParseError = PackageManager.INSTALL_SUCCEEDED; 333 334 private static boolean sCompatibilityModeEnabled = true; 335 private static final int PARSE_DEFAULT_INSTALL_LOCATION = 336 PackageInfo.INSTALL_LOCATION_UNSPECIFIED; 337 private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1; 338 339 static class ParsePackageItemArgs { 340 final Package owner; 341 final String[] outError; 342 final int nameRes; 343 final int labelRes; 344 final int iconRes; 345 final int roundIconRes; 346 final int logoRes; 347 final int bannerRes; 348 349 String tag; 350 TypedArray sa; 351 352 ParsePackageItemArgs(Package _owner, String[] _outError, 353 int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes, 354 int _bannerRes) { 355 owner = _owner; 356 outError = _outError; 357 nameRes = _nameRes; 358 labelRes = _labelRes; 359 iconRes = _iconRes; 360 logoRes = _logoRes; 361 bannerRes = _bannerRes; 362 roundIconRes = _roundIconRes; 363 } 364 } 365 366 /** @hide */ 367 @VisibleForTesting 368 public static class ParseComponentArgs extends ParsePackageItemArgs { 369 final String[] sepProcesses; 370 final int processRes; 371 final int descriptionRes; 372 final int enabledRes; 373 int flags; 374 375 public ParseComponentArgs(Package _owner, String[] _outError, 376 int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes, 377 int _bannerRes, 378 String[] _sepProcesses, int _processRes, 379 int _descriptionRes, int _enabledRes) { 380 super(_owner, _outError, _nameRes, _labelRes, _iconRes, _roundIconRes, _logoRes, 381 _bannerRes); 382 sepProcesses = _sepProcesses; 383 processRes = _processRes; 384 descriptionRes = _descriptionRes; 385 enabledRes = _enabledRes; 386 } 387 } 388 389 /** 390 * Lightweight parsed details about a single package. 391 */ 392 public static class PackageLite { 393 public final String packageName; 394 public final int versionCode; 395 public final int installLocation; 396 public final VerifierInfo[] verifiers; 397 398 /** Names of any split APKs, ordered by parsed splitName */ 399 public final String[] splitNames; 400 401 /** Names of any split APKs that are features. Ordered by splitName */ 402 public final boolean[] isFeatureSplits; 403 404 /** Dependencies of any split APKs, ordered by parsed splitName */ 405 public final String[] usesSplitNames; 406 public final String[] configForSplit; 407 408 /** 409 * Path where this package was found on disk. For monolithic packages 410 * this is path to single base APK file; for cluster packages this is 411 * path to the cluster directory. 412 */ 413 public final String codePath; 414 415 /** Path of base APK */ 416 public final String baseCodePath; 417 /** Paths of any split APKs, ordered by parsed splitName */ 418 public final String[] splitCodePaths; 419 420 /** Revision code of base APK */ 421 public final int baseRevisionCode; 422 /** Revision codes of any split APKs, ordered by parsed splitName */ 423 public final int[] splitRevisionCodes; 424 425 public final boolean coreApp; 426 public final boolean debuggable; 427 public final boolean multiArch; 428 public final boolean use32bitAbi; 429 public final boolean extractNativeLibs; 430 public final boolean isolatedSplits; 431 432 public PackageLite(String codePath, ApkLite baseApk, String[] splitNames, 433 boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit, 434 String[] splitCodePaths, int[] splitRevisionCodes) { 435 this.packageName = baseApk.packageName; 436 this.versionCode = baseApk.versionCode; 437 this.installLocation = baseApk.installLocation; 438 this.verifiers = baseApk.verifiers; 439 this.splitNames = splitNames; 440 this.isFeatureSplits = isFeatureSplits; 441 this.usesSplitNames = usesSplitNames; 442 this.configForSplit = configForSplit; 443 this.codePath = codePath; 444 this.baseCodePath = baseApk.codePath; 445 this.splitCodePaths = splitCodePaths; 446 this.baseRevisionCode = baseApk.revisionCode; 447 this.splitRevisionCodes = splitRevisionCodes; 448 this.coreApp = baseApk.coreApp; 449 this.debuggable = baseApk.debuggable; 450 this.multiArch = baseApk.multiArch; 451 this.use32bitAbi = baseApk.use32bitAbi; 452 this.extractNativeLibs = baseApk.extractNativeLibs; 453 this.isolatedSplits = baseApk.isolatedSplits; 454 } 455 456 public List<String> getAllCodePaths() { 457 ArrayList<String> paths = new ArrayList<>(); 458 paths.add(baseCodePath); 459 if (!ArrayUtils.isEmpty(splitCodePaths)) { 460 Collections.addAll(paths, splitCodePaths); 461 } 462 return paths; 463 } 464 } 465 466 /** 467 * Lightweight parsed details about a single APK file. 468 */ 469 public static class ApkLite { 470 public final String codePath; 471 public final String packageName; 472 public final String splitName; 473 public boolean isFeatureSplit; 474 public final String configForSplit; 475 public final String usesSplitName; 476 public final int versionCode; 477 public final int revisionCode; 478 public final int installLocation; 479 public final VerifierInfo[] verifiers; 480 public final Signature[] signatures; 481 public final Certificate[][] certificates; 482 public final boolean coreApp; 483 public final boolean debuggable; 484 public final boolean multiArch; 485 public final boolean use32bitAbi; 486 public final boolean extractNativeLibs; 487 public final boolean isolatedSplits; 488 489 public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit, 490 String configForSplit, String usesSplitName, int versionCode, int revisionCode, 491 int installLocation, List<VerifierInfo> verifiers, Signature[] signatures, 492 Certificate[][] certificates, boolean coreApp, boolean debuggable, 493 boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs, 494 boolean isolatedSplits) { 495 this.codePath = codePath; 496 this.packageName = packageName; 497 this.splitName = splitName; 498 this.isFeatureSplit = isFeatureSplit; 499 this.configForSplit = configForSplit; 500 this.usesSplitName = usesSplitName; 501 this.versionCode = versionCode; 502 this.revisionCode = revisionCode; 503 this.installLocation = installLocation; 504 this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]); 505 this.signatures = signatures; 506 this.certificates = certificates; 507 this.coreApp = coreApp; 508 this.debuggable = debuggable; 509 this.multiArch = multiArch; 510 this.use32bitAbi = use32bitAbi; 511 this.extractNativeLibs = extractNativeLibs; 512 this.isolatedSplits = isolatedSplits; 513 } 514 } 515 516 /** 517 * Cached parse state for new components. 518 * 519 * Allows reuse of the same parse argument records to avoid GC pressure. Lifetime is carefully 520 * scoped to the parsing of a single application element. 521 */ 522 private static class CachedComponentArgs { 523 ParseComponentArgs mActivityArgs; 524 ParseComponentArgs mActivityAliasArgs; 525 ParseComponentArgs mServiceArgs; 526 ParseComponentArgs mProviderArgs; 527 } 528 529 /** 530 * Cached state for parsing instrumentation to avoid GC pressure. 531 * 532 * Must be manually reset to null for each new manifest. 533 */ 534 private ParsePackageItemArgs mParseInstrumentationArgs; 535 536 /** If set to true, we will only allow package files that exactly match 537 * the DTD. Otherwise, we try to get as much from the package as we 538 * can without failing. This should normally be set to false, to 539 * support extensions to the DTD in future versions. */ 540 private static final boolean RIGID_PARSER = false; 541 542 private static final String TAG = "PackageParser"; 543 544 public PackageParser() { 545 mMetrics = new DisplayMetrics(); 546 mMetrics.setToDefaults(); 547 } 548 549 public void setSeparateProcesses(String[] procs) { 550 mSeparateProcesses = procs; 551 } 552 553 /** 554 * Flag indicating this parser should only consider apps with 555 * {@code coreApp} manifest attribute to be valid apps. This is useful when 556 * creating a minimalist boot environment. 557 */ 558 public void setOnlyCoreApps(boolean onlyCoreApps) { 559 mOnlyCoreApps = onlyCoreApps; 560 } 561 562 public void setDisplayMetrics(DisplayMetrics metrics) { 563 mMetrics = metrics; 564 } 565 566 /** 567 * Sets the cache directory for this package parser. 568 */ 569 public void setCacheDir(File cacheDir) { 570 mCacheDir = cacheDir; 571 } 572 573 /** 574 * Callback interface for retrieving information that may be needed while parsing 575 * a package. 576 */ 577 public interface Callback { 578 boolean hasFeature(String feature); 579 String[] getOverlayPaths(String targetPackageName, String targetPath); 580 String[] getOverlayApks(String targetPackageName); 581 } 582 583 /** 584 * Standard implementation of {@link Callback} on top of the public {@link PackageManager} 585 * class. 586 */ 587 public static final class CallbackImpl implements Callback { 588 private final PackageManager mPm; 589 590 public CallbackImpl(PackageManager pm) { 591 mPm = pm; 592 } 593 594 @Override public boolean hasFeature(String feature) { 595 return mPm.hasSystemFeature(feature); 596 } 597 598 @Override public String[] getOverlayPaths(String targetPackageName, String targetPath) { 599 return null; 600 } 601 602 @Override public String[] getOverlayApks(String targetPackageName) { 603 return null; 604 } 605 } 606 607 /** 608 * Set the {@link Callback} that can be used while parsing. 609 */ 610 public void setCallback(Callback cb) { 611 mCallback = cb; 612 } 613 614 public static final boolean isApkFile(File file) { 615 return isApkPath(file.getName()); 616 } 617 618 public static boolean isApkPath(String path) { 619 return path.endsWith(".apk"); 620 } 621 622 /** 623 * Generate and return the {@link PackageInfo} for a parsed package. 624 * 625 * @param p the parsed package. 626 * @param flags indicating which optional information is included. 627 */ 628 public static PackageInfo generatePackageInfo(PackageParser.Package p, 629 int gids[], int flags, long firstInstallTime, long lastUpdateTime, 630 Set<String> grantedPermissions, PackageUserState state) { 631 632 return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, 633 grantedPermissions, state, UserHandle.getCallingUserId()); 634 } 635 636 /** 637 * Returns true if the package is installed and not hidden, or if the caller 638 * explicitly wanted all uninstalled and hidden packages as well. 639 * @param appInfo The applicationInfo of the app being checked. 640 */ 641 private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state, 642 ApplicationInfo appInfo) { 643 // If available for the target user, or trying to match uninstalled packages and it's 644 // a system app. 645 return state.isAvailable(flags) 646 || (appInfo != null && appInfo.isSystemApp() 647 && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0); 648 } 649 650 public static boolean isAvailable(PackageUserState state) { 651 return checkUseInstalledOrHidden(0, state, null); 652 } 653 654 public static PackageInfo generatePackageInfo(PackageParser.Package p, 655 int gids[], int flags, long firstInstallTime, long lastUpdateTime, 656 Set<String> grantedPermissions, PackageUserState state, int userId) { 657 if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) { 658 return null; 659 } 660 PackageInfo pi = new PackageInfo(); 661 pi.packageName = p.packageName; 662 pi.splitNames = p.splitNames; 663 pi.versionCode = p.mVersionCode; 664 pi.baseRevisionCode = p.baseRevisionCode; 665 pi.splitRevisionCodes = p.splitRevisionCodes; 666 pi.versionName = p.mVersionName; 667 pi.sharedUserId = p.mSharedUserId; 668 pi.sharedUserLabel = p.mSharedUserLabel; 669 pi.applicationInfo = generateApplicationInfo(p, flags, state, userId); 670 pi.installLocation = p.installLocation; 671 pi.isStub = p.isStub; 672 pi.coreApp = p.coreApp; 673 if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0 674 || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { 675 pi.requiredForAllUsers = p.mRequiredForAllUsers; 676 } 677 pi.restrictedAccountType = p.mRestrictedAccountType; 678 pi.requiredAccountType = p.mRequiredAccountType; 679 pi.overlayTarget = p.mOverlayTarget; 680 pi.overlayPriority = p.mOverlayPriority; 681 pi.isStaticOverlay = p.mIsStaticOverlay; 682 pi.firstInstallTime = firstInstallTime; 683 pi.lastUpdateTime = lastUpdateTime; 684 if ((flags&PackageManager.GET_GIDS) != 0) { 685 pi.gids = gids; 686 } 687 if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) { 688 int N = p.configPreferences != null ? p.configPreferences.size() : 0; 689 if (N > 0) { 690 pi.configPreferences = new ConfigurationInfo[N]; 691 p.configPreferences.toArray(pi.configPreferences); 692 } 693 N = p.reqFeatures != null ? p.reqFeatures.size() : 0; 694 if (N > 0) { 695 pi.reqFeatures = new FeatureInfo[N]; 696 p.reqFeatures.toArray(pi.reqFeatures); 697 } 698 N = p.featureGroups != null ? p.featureGroups.size() : 0; 699 if (N > 0) { 700 pi.featureGroups = new FeatureGroupInfo[N]; 701 p.featureGroups.toArray(pi.featureGroups); 702 } 703 } 704 if ((flags & PackageManager.GET_ACTIVITIES) != 0) { 705 final int N = p.activities.size(); 706 if (N > 0) { 707 int num = 0; 708 final ActivityInfo[] res = new ActivityInfo[N]; 709 for (int i = 0; i < N; i++) { 710 final Activity a = p.activities.get(i); 711 if (state.isMatch(a.info, flags)) { 712 res[num++] = generateActivityInfo(a, flags, state, userId); 713 } 714 } 715 pi.activities = ArrayUtils.trimToSize(res, num); 716 } 717 } 718 if ((flags & PackageManager.GET_RECEIVERS) != 0) { 719 final int N = p.receivers.size(); 720 if (N > 0) { 721 int num = 0; 722 final ActivityInfo[] res = new ActivityInfo[N]; 723 for (int i = 0; i < N; i++) { 724 final Activity a = p.receivers.get(i); 725 if (state.isMatch(a.info, flags)) { 726 res[num++] = generateActivityInfo(a, flags, state, userId); 727 } 728 } 729 pi.receivers = ArrayUtils.trimToSize(res, num); 730 } 731 } 732 if ((flags & PackageManager.GET_SERVICES) != 0) { 733 final int N = p.services.size(); 734 if (N > 0) { 735 int num = 0; 736 final ServiceInfo[] res = new ServiceInfo[N]; 737 for (int i = 0; i < N; i++) { 738 final Service s = p.services.get(i); 739 if (state.isMatch(s.info, flags)) { 740 res[num++] = generateServiceInfo(s, flags, state, userId); 741 } 742 } 743 pi.services = ArrayUtils.trimToSize(res, num); 744 } 745 } 746 if ((flags & PackageManager.GET_PROVIDERS) != 0) { 747 final int N = p.providers.size(); 748 if (N > 0) { 749 int num = 0; 750 final ProviderInfo[] res = new ProviderInfo[N]; 751 for (int i = 0; i < N; i++) { 752 final Provider pr = p.providers.get(i); 753 if (state.isMatch(pr.info, flags)) { 754 res[num++] = generateProviderInfo(pr, flags, state, userId); 755 } 756 } 757 pi.providers = ArrayUtils.trimToSize(res, num); 758 } 759 } 760 if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) { 761 int N = p.instrumentation.size(); 762 if (N > 0) { 763 pi.instrumentation = new InstrumentationInfo[N]; 764 for (int i=0; i<N; i++) { 765 pi.instrumentation[i] = generateInstrumentationInfo( 766 p.instrumentation.get(i), flags); 767 } 768 } 769 } 770 if ((flags&PackageManager.GET_PERMISSIONS) != 0) { 771 int N = p.permissions.size(); 772 if (N > 0) { 773 pi.permissions = new PermissionInfo[N]; 774 for (int i=0; i<N; i++) { 775 pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags); 776 } 777 } 778 N = p.requestedPermissions.size(); 779 if (N > 0) { 780 pi.requestedPermissions = new String[N]; 781 pi.requestedPermissionsFlags = new int[N]; 782 for (int i=0; i<N; i++) { 783 final String perm = p.requestedPermissions.get(i); 784 pi.requestedPermissions[i] = perm; 785 // The notion of required permissions is deprecated but for compatibility. 786 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED; 787 if (grantedPermissions != null && grantedPermissions.contains(perm)) { 788 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED; 789 } 790 } 791 } 792 } 793 if ((flags&PackageManager.GET_SIGNATURES) != 0) { 794 int N = (p.mSignatures != null) ? p.mSignatures.length : 0; 795 if (N > 0) { 796 pi.signatures = new Signature[N]; 797 System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N); 798 } 799 } 800 return pi; 801 } 802 803 private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry) 804 throws PackageParserException { 805 InputStream is = null; 806 try { 807 // We must read the stream for the JarEntry to retrieve 808 // its certificates. 809 is = jarFile.getInputStream(entry); 810 readFullyIgnoringContents(is); 811 return jarFile.getCertificateChains(entry); 812 } catch (IOException | RuntimeException e) { 813 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 814 "Failed reading " + entry.getName() + " in " + jarFile, e); 815 } finally { 816 IoUtils.closeQuietly(is); 817 } 818 } 819 820 public final static int PARSE_IS_SYSTEM = 1<<0; 821 public final static int PARSE_CHATTY = 1<<1; 822 public final static int PARSE_MUST_BE_APK = 1<<2; 823 public final static int PARSE_IGNORE_PROCESSES = 1<<3; 824 public final static int PARSE_FORWARD_LOCK = 1<<4; 825 public final static int PARSE_EXTERNAL_STORAGE = 1<<5; 826 public final static int PARSE_IS_SYSTEM_DIR = 1<<6; 827 public final static int PARSE_IS_PRIVILEGED = 1<<7; 828 public final static int PARSE_COLLECT_CERTIFICATES = 1<<8; 829 public final static int PARSE_TRUSTED_OVERLAY = 1<<9; 830 public final static int PARSE_ENFORCE_CODE = 1<<10; 831 /** @deprecated remove when fixing b/34761192 */ 832 @Deprecated 833 public final static int PARSE_IS_EPHEMERAL = 1<<11; 834 public final static int PARSE_FORCE_SDK = 1<<12; 835 836 private static final Comparator<String> sSplitNameComparator = new SplitNameComparator(); 837 838 /** 839 * Used to sort a set of APKs based on their split names, always placing the 840 * base APK (with {@code null} split name) first. 841 */ 842 private static class SplitNameComparator implements Comparator<String> { 843 @Override 844 public int compare(String lhs, String rhs) { 845 if (lhs == null) { 846 return -1; 847 } else if (rhs == null) { 848 return 1; 849 } else { 850 return lhs.compareTo(rhs); 851 } 852 } 853 } 854 855 /** 856 * Parse only lightweight details about the package at the given location. 857 * Automatically detects if the package is a monolithic style (single APK 858 * file) or cluster style (directory of APKs). 859 * <p> 860 * This performs sanity checking on cluster style packages, such as 861 * requiring identical package name and version codes, a single base APK, 862 * and unique split names. 863 * 864 * @see PackageParser#parsePackage(File, int) 865 */ 866 public static PackageLite parsePackageLite(File packageFile, int flags) 867 throws PackageParserException { 868 if (packageFile.isDirectory()) { 869 return parseClusterPackageLite(packageFile, flags); 870 } else { 871 return parseMonolithicPackageLite(packageFile, flags); 872 } 873 } 874 875 private static PackageLite parseMonolithicPackageLite(File packageFile, int flags) 876 throws PackageParserException { 877 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite"); 878 final ApkLite baseApk = parseApkLite(packageFile, flags); 879 final String packagePath = packageFile.getAbsolutePath(); 880 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 881 return new PackageLite(packagePath, baseApk, null, null, null, null, null, null); 882 } 883 884 static PackageLite parseClusterPackageLite(File packageDir, int flags) 885 throws PackageParserException { 886 final File[] files = packageDir.listFiles(); 887 if (ArrayUtils.isEmpty(files)) { 888 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 889 "No packages found in split"); 890 } 891 892 String packageName = null; 893 int versionCode = 0; 894 895 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite"); 896 final ArrayMap<String, ApkLite> apks = new ArrayMap<>(); 897 for (File file : files) { 898 if (isApkFile(file)) { 899 final ApkLite lite = parseApkLite(file, flags); 900 901 // Assert that all package names and version codes are 902 // consistent with the first one we encounter. 903 if (packageName == null) { 904 packageName = lite.packageName; 905 versionCode = lite.versionCode; 906 } else { 907 if (!packageName.equals(lite.packageName)) { 908 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 909 "Inconsistent package " + lite.packageName + " in " + file 910 + "; expected " + packageName); 911 } 912 if (versionCode != lite.versionCode) { 913 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 914 "Inconsistent version " + lite.versionCode + " in " + file 915 + "; expected " + versionCode); 916 } 917 } 918 919 // Assert that each split is defined only once 920 if (apks.put(lite.splitName, lite) != null) { 921 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 922 "Split name " + lite.splitName 923 + " defined more than once; most recent was " + file); 924 } 925 } 926 } 927 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 928 929 final ApkLite baseApk = apks.remove(null); 930 if (baseApk == null) { 931 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 932 "Missing base APK in " + packageDir); 933 } 934 935 // Always apply deterministic ordering based on splitName 936 final int size = apks.size(); 937 938 String[] splitNames = null; 939 boolean[] isFeatureSplits = null; 940 String[] usesSplitNames = null; 941 String[] configForSplits = null; 942 String[] splitCodePaths = null; 943 int[] splitRevisionCodes = null; 944 String[] splitClassLoaderNames = null; 945 if (size > 0) { 946 splitNames = new String[size]; 947 isFeatureSplits = new boolean[size]; 948 usesSplitNames = new String[size]; 949 configForSplits = new String[size]; 950 splitCodePaths = new String[size]; 951 splitRevisionCodes = new int[size]; 952 953 splitNames = apks.keySet().toArray(splitNames); 954 Arrays.sort(splitNames, sSplitNameComparator); 955 956 for (int i = 0; i < size; i++) { 957 final ApkLite apk = apks.get(splitNames[i]); 958 usesSplitNames[i] = apk.usesSplitName; 959 isFeatureSplits[i] = apk.isFeatureSplit; 960 configForSplits[i] = apk.configForSplit; 961 splitCodePaths[i] = apk.codePath; 962 splitRevisionCodes[i] = apk.revisionCode; 963 } 964 } 965 966 final String codePath = packageDir.getAbsolutePath(); 967 return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames, 968 configForSplits, splitCodePaths, splitRevisionCodes); 969 } 970 971 /** 972 * Parse the package at the given location. Automatically detects if the 973 * package is a monolithic style (single APK file) or cluster style 974 * (directory of APKs). 975 * <p> 976 * This performs sanity checking on cluster style packages, such as 977 * requiring identical package name and version codes, a single base APK, 978 * and unique split names. 979 * <p> 980 * Note that this <em>does not</em> perform signature verification; that 981 * must be done separately in {@link #collectCertificates(Package, int)}. 982 * 983 * If {@code useCaches} is true, the package parser might return a cached 984 * result from a previous parse of the same {@code packageFile} with the same 985 * {@code flags}. Note that this method does not check whether {@code packageFile} 986 * has changed since the last parse, it's up to callers to do so. 987 * 988 * @see #parsePackageLite(File, int) 989 */ 990 public Package parsePackage(File packageFile, int flags, boolean useCaches) 991 throws PackageParserException { 992 Package parsed = useCaches ? getCachedResult(packageFile, flags) : null; 993 if (parsed != null) { 994 return parsed; 995 } 996 997 long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; 998 if (packageFile.isDirectory()) { 999 parsed = parseClusterPackage(packageFile, flags); 1000 } else { 1001 parsed = parseMonolithicPackage(packageFile, flags); 1002 } 1003 1004 long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; 1005 cacheResult(packageFile, flags, parsed); 1006 if (LOG_PARSE_TIMINGS) { 1007 parseTime = cacheTime - parseTime; 1008 cacheTime = SystemClock.uptimeMillis() - cacheTime; 1009 if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) { 1010 Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime 1011 + "ms, update_cache=" + cacheTime + " ms"); 1012 } 1013 } 1014 return parsed; 1015 } 1016 1017 /** 1018 * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}. 1019 */ 1020 public Package parsePackage(File packageFile, int flags) throws PackageParserException { 1021 return parsePackage(packageFile, flags, false /* useCaches */); 1022 } 1023 1024 /** 1025 * Returns the cache key for a specificied {@code packageFile} and {@code flags}. 1026 */ 1027 private String getCacheKey(File packageFile, int flags) { 1028 StringBuilder sb = new StringBuilder(packageFile.getName()); 1029 sb.append('-'); 1030 sb.append(flags); 1031 1032 return sb.toString(); 1033 } 1034 1035 @VisibleForTesting 1036 protected Package fromCacheEntry(byte[] bytes) { 1037 return fromCacheEntryStatic(bytes); 1038 } 1039 1040 /** static version of {@link #fromCacheEntry} for unit tests. */ 1041 @VisibleForTesting 1042 public static Package fromCacheEntryStatic(byte[] bytes) { 1043 final Parcel p = Parcel.obtain(); 1044 p.unmarshall(bytes, 0, bytes.length); 1045 p.setDataPosition(0); 1046 1047 final ReadHelper helper = new ReadHelper(p); 1048 helper.startAndInstall(); 1049 1050 PackageParser.Package pkg = new PackageParser.Package(p); 1051 1052 p.recycle(); 1053 1054 sCachedPackageReadCount.incrementAndGet(); 1055 1056 return pkg; 1057 } 1058 1059 @VisibleForTesting 1060 protected byte[] toCacheEntry(Package pkg) { 1061 return toCacheEntryStatic(pkg); 1062 1063 } 1064 1065 /** static version of {@link #toCacheEntry} for unit tests. */ 1066 @VisibleForTesting 1067 public static byte[] toCacheEntryStatic(Package pkg) { 1068 final Parcel p = Parcel.obtain(); 1069 final WriteHelper helper = new WriteHelper(p); 1070 1071 pkg.writeToParcel(p, 0 /* flags */); 1072 1073 helper.finishAndUninstall(); 1074 1075 byte[] serialized = p.marshall(); 1076 p.recycle(); 1077 1078 return serialized; 1079 } 1080 1081 /** 1082 * Given a {@code packageFile} and a {@code cacheFile} returns whether the 1083 * cache file is up to date based on the mod-time of both files. 1084 */ 1085 private static boolean isCacheUpToDate(File packageFile, File cacheFile) { 1086 try { 1087 // NOTE: We don't use the File.lastModified API because it has the very 1088 // non-ideal failure mode of returning 0 with no excepions thrown. 1089 // The nio2 Files API is a little better but is considerably more expensive. 1090 final StructStat pkg = android.system.Os.stat(packageFile.getAbsolutePath()); 1091 final StructStat cache = android.system.Os.stat(cacheFile.getAbsolutePath()); 1092 return pkg.st_mtime < cache.st_mtime; 1093 } catch (ErrnoException ee) { 1094 // The most common reason why stat fails is that a given cache file doesn't 1095 // exist. We ignore that here. It's easy to reason that it's safe to say the 1096 // cache isn't up to date if we see any sort of exception here. 1097 // 1098 // (1) Exception while stating the package file : This should never happen, 1099 // and if it does, we do a full package parse (which is likely to throw the 1100 // same exception). 1101 // (2) Exception while stating the cache file : If the file doesn't exist, the 1102 // cache is obviously out of date. If the file *does* exist, we can't read it. 1103 // We will attempt to delete and recreate it after parsing the package. 1104 if (ee.errno != OsConstants.ENOENT) { 1105 Slog.w("Error while stating package cache : ", ee); 1106 } 1107 1108 return false; 1109 } 1110 } 1111 1112 /** 1113 * Returns the cached parse result for {@code packageFile} for parse flags {@code flags}, 1114 * or {@code null} if no cached result exists. 1115 */ 1116 private Package getCachedResult(File packageFile, int flags) { 1117 if (mCacheDir == null) { 1118 return null; 1119 } 1120 1121 final String cacheKey = getCacheKey(packageFile, flags); 1122 final File cacheFile = new File(mCacheDir, cacheKey); 1123 1124 try { 1125 // If the cache is not up to date, return null. 1126 if (!isCacheUpToDate(packageFile, cacheFile)) { 1127 return null; 1128 } 1129 1130 final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath()); 1131 Package p = fromCacheEntry(bytes); 1132 if (mCallback != null) { 1133 String[] overlayApks = mCallback.getOverlayApks(p.packageName); 1134 if (overlayApks != null && overlayApks.length > 0) { 1135 for (String overlayApk : overlayApks) { 1136 // If a static RRO is updated, return null. 1137 if (!isCacheUpToDate(new File(overlayApk), cacheFile)) { 1138 return null; 1139 } 1140 } 1141 } 1142 } 1143 return p; 1144 } catch (Throwable e) { 1145 Slog.w(TAG, "Error reading package cache: ", e); 1146 1147 // If something went wrong while reading the cache entry, delete the cache file 1148 // so that we regenerate it the next time. 1149 cacheFile.delete(); 1150 return null; 1151 } 1152 } 1153 1154 /** 1155 * Caches the parse result for {@code packageFile} with flags {@code flags}. 1156 */ 1157 private void cacheResult(File packageFile, int flags, Package parsed) { 1158 if (mCacheDir == null) { 1159 return; 1160 } 1161 1162 try { 1163 final String cacheKey = getCacheKey(packageFile, flags); 1164 final File cacheFile = new File(mCacheDir, cacheKey); 1165 1166 if (cacheFile.exists()) { 1167 if (!cacheFile.delete()) { 1168 Slog.e(TAG, "Unable to delete cache file: " + cacheFile); 1169 } 1170 } 1171 1172 final byte[] cacheEntry = toCacheEntry(parsed); 1173 1174 if (cacheEntry == null) { 1175 return; 1176 } 1177 1178 try (FileOutputStream fos = new FileOutputStream(cacheFile)) { 1179 fos.write(cacheEntry); 1180 } catch (IOException ioe) { 1181 Slog.w(TAG, "Error writing cache entry.", ioe); 1182 cacheFile.delete(); 1183 } 1184 } catch (Throwable e) { 1185 Slog.w(TAG, "Error saving package cache.", e); 1186 } 1187 } 1188 1189 /** 1190 * Parse all APKs contained in the given directory, treating them as a 1191 * single package. This also performs sanity checking, such as requiring 1192 * identical package name and version codes, a single base APK, and unique 1193 * split names. 1194 * <p> 1195 * Note that this <em>does not</em> perform signature verification; that 1196 * must be done separately in {@link #collectCertificates(Package, int)}. 1197 */ 1198 private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException { 1199 final PackageLite lite = parseClusterPackageLite(packageDir, 0); 1200 if (mOnlyCoreApps && !lite.coreApp) { 1201 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 1202 "Not a coreApp: " + packageDir); 1203 } 1204 1205 // Build the split dependency tree. 1206 SparseArray<int[]> splitDependencies = null; 1207 final SplitAssetLoader assetLoader; 1208 if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) { 1209 try { 1210 splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite); 1211 assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags); 1212 } catch (SplitAssetDependencyLoader.IllegalDependencyException e) { 1213 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage()); 1214 } 1215 } else { 1216 assetLoader = new DefaultSplitAssetLoader(lite, flags); 1217 } 1218 1219 try { 1220 final AssetManager assets = assetLoader.getBaseAssetManager(); 1221 final File baseApk = new File(lite.baseCodePath); 1222 final Package pkg = parseBaseApk(baseApk, assets, flags); 1223 if (pkg == null) { 1224 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 1225 "Failed to parse base APK: " + baseApk); 1226 } 1227 1228 if (!ArrayUtils.isEmpty(lite.splitNames)) { 1229 final int num = lite.splitNames.length; 1230 pkg.splitNames = lite.splitNames; 1231 pkg.splitCodePaths = lite.splitCodePaths; 1232 pkg.splitRevisionCodes = lite.splitRevisionCodes; 1233 pkg.splitFlags = new int[num]; 1234 pkg.splitPrivateFlags = new int[num]; 1235 pkg.applicationInfo.splitNames = pkg.splitNames; 1236 pkg.applicationInfo.splitDependencies = splitDependencies; 1237 pkg.applicationInfo.splitClassLoaderNames = new String[num]; 1238 1239 for (int i = 0; i < num; i++) { 1240 final AssetManager splitAssets = assetLoader.getSplitAssetManager(i); 1241 parseSplitApk(pkg, i, splitAssets, flags); 1242 } 1243 } 1244 1245 pkg.setCodePath(packageDir.getAbsolutePath()); 1246 pkg.setUse32bitAbi(lite.use32bitAbi); 1247 return pkg; 1248 } finally { 1249 IoUtils.closeQuietly(assetLoader); 1250 } 1251 } 1252 1253 /** 1254 * Parse the given APK file, treating it as as a single monolithic package. 1255 * <p> 1256 * Note that this <em>does not</em> perform signature verification; that 1257 * must be done separately in {@link #collectCertificates(Package, int)}. 1258 * 1259 * @deprecated external callers should move to 1260 * {@link #parsePackage(File, int)}. Eventually this method will 1261 * be marked private. 1262 */ 1263 @Deprecated 1264 public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException { 1265 final AssetManager assets = newConfiguredAssetManager(); 1266 final PackageLite lite = parseMonolithicPackageLite(apkFile, flags); 1267 if (mOnlyCoreApps) { 1268 if (!lite.coreApp) { 1269 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 1270 "Not a coreApp: " + apkFile); 1271 } 1272 } 1273 1274 try { 1275 final Package pkg = parseBaseApk(apkFile, assets, flags); 1276 pkg.setCodePath(apkFile.getAbsolutePath()); 1277 pkg.setUse32bitAbi(lite.use32bitAbi); 1278 return pkg; 1279 } finally { 1280 IoUtils.closeQuietly(assets); 1281 } 1282 } 1283 1284 private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags) 1285 throws PackageParserException { 1286 if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) { 1287 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 1288 "Invalid package file: " + apkPath); 1289 } 1290 1291 // The AssetManager guarantees uniqueness for asset paths, so if this asset path 1292 // already exists in the AssetManager, addAssetPath will only return the cookie 1293 // assigned to it. 1294 int cookie = assets.addAssetPath(apkPath); 1295 if (cookie == 0) { 1296 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 1297 "Failed adding asset path: " + apkPath); 1298 } 1299 return cookie; 1300 } 1301 1302 private Package parseBaseApk(File apkFile, AssetManager assets, int flags) 1303 throws PackageParserException { 1304 final String apkPath = apkFile.getAbsolutePath(); 1305 1306 String volumeUuid = null; 1307 if (apkPath.startsWith(MNT_EXPAND)) { 1308 final int end = apkPath.indexOf('/', MNT_EXPAND.length()); 1309 volumeUuid = apkPath.substring(MNT_EXPAND.length(), end); 1310 } 1311 1312 mParseError = PackageManager.INSTALL_SUCCEEDED; 1313 mArchiveSourcePath = apkFile.getAbsolutePath(); 1314 1315 if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); 1316 1317 final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); 1318 1319 Resources res = null; 1320 XmlResourceParser parser = null; 1321 try { 1322 res = new Resources(assets, mMetrics, null); 1323 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 1324 1325 final String[] outError = new String[1]; 1326 final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError); 1327 if (pkg == null) { 1328 throw new PackageParserException(mParseError, 1329 apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]); 1330 } 1331 1332 pkg.setVolumeUuid(volumeUuid); 1333 pkg.setApplicationVolumeUuid(volumeUuid); 1334 pkg.setBaseCodePath(apkPath); 1335 pkg.setSignatures(null); 1336 1337 return pkg; 1338 1339 } catch (PackageParserException e) { 1340 throw e; 1341 } catch (Exception e) { 1342 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 1343 "Failed to read manifest from " + apkPath, e); 1344 } finally { 1345 IoUtils.closeQuietly(parser); 1346 } 1347 } 1348 1349 private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags) 1350 throws PackageParserException { 1351 final String apkPath = pkg.splitCodePaths[splitIndex]; 1352 1353 mParseError = PackageManager.INSTALL_SUCCEEDED; 1354 mArchiveSourcePath = apkPath; 1355 1356 if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); 1357 1358 final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); 1359 1360 final Resources res; 1361 XmlResourceParser parser = null; 1362 try { 1363 res = new Resources(assets, mMetrics, null); 1364 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1365 Build.VERSION.RESOURCES_SDK_INT); 1366 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 1367 1368 final String[] outError = new String[1]; 1369 pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError); 1370 if (pkg == null) { 1371 throw new PackageParserException(mParseError, 1372 apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]); 1373 } 1374 1375 } catch (PackageParserException e) { 1376 throw e; 1377 } catch (Exception e) { 1378 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 1379 "Failed to read manifest from " + apkPath, e); 1380 } finally { 1381 IoUtils.closeQuietly(parser); 1382 } 1383 } 1384 1385 /** 1386 * Parse the manifest of a <em>split APK</em>. 1387 * <p> 1388 * Note that split APKs have many more restrictions on what they're capable 1389 * of doing, so many valid features of a base APK have been carefully 1390 * omitted here. 1391 */ 1392 private Package parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags, 1393 int splitIndex, String[] outError) throws XmlPullParserException, IOException, 1394 PackageParserException { 1395 AttributeSet attrs = parser; 1396 1397 // We parsed manifest tag earlier; just skip past it 1398 parsePackageSplitNames(parser, attrs); 1399 1400 mParseInstrumentationArgs = null; 1401 1402 int type; 1403 1404 boolean foundApp = false; 1405 1406 int outerDepth = parser.getDepth(); 1407 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1408 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1409 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1410 continue; 1411 } 1412 1413 String tagName = parser.getName(); 1414 if (tagName.equals(TAG_APPLICATION)) { 1415 if (foundApp) { 1416 if (RIGID_PARSER) { 1417 outError[0] = "<manifest> has more than one <application>"; 1418 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1419 return null; 1420 } else { 1421 Slog.w(TAG, "<manifest> has more than one <application>"); 1422 XmlUtils.skipCurrentTag(parser); 1423 continue; 1424 } 1425 } 1426 1427 foundApp = true; 1428 if (!parseSplitApplication(pkg, res, parser, flags, splitIndex, outError)) { 1429 return null; 1430 } 1431 1432 } else if (RIGID_PARSER) { 1433 outError[0] = "Bad element under <manifest>: " 1434 + parser.getName(); 1435 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1436 return null; 1437 1438 } else { 1439 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() 1440 + " at " + mArchiveSourcePath + " " 1441 + parser.getPositionDescription()); 1442 XmlUtils.skipCurrentTag(parser); 1443 continue; 1444 } 1445 } 1446 1447 if (!foundApp) { 1448 outError[0] = "<manifest> does not contain an <application>"; 1449 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; 1450 } 1451 1452 return pkg; 1453 } 1454 1455 public static int getApkSigningVersion(Package pkg) { 1456 try { 1457 if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) { 1458 return APK_SIGNING_V2; 1459 } 1460 return APK_SIGNING_V1; 1461 } catch (IOException e) { 1462 } 1463 return APK_SIGNING_UNKNOWN; 1464 } 1465 1466 /** 1467 * Populates the correct packages fields with the given certificates. 1468 * <p> 1469 * This is useful when we've already processed the certificates [such as during package 1470 * installation through an installer session]. We don't re-process the archive and 1471 * simply populate the correct fields. 1472 */ 1473 public static void populateCertificates(Package pkg, Certificate[][] certificates) 1474 throws PackageParserException { 1475 pkg.mCertificates = null; 1476 pkg.mSignatures = null; 1477 pkg.mSigningKeys = null; 1478 1479 pkg.mCertificates = certificates; 1480 try { 1481 pkg.mSignatures = convertToSignatures(certificates); 1482 } catch (CertificateEncodingException e) { 1483 // certificates weren't encoded properly; something went wrong 1484 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1485 "Failed to collect certificates from " + pkg.baseCodePath, e); 1486 } 1487 pkg.mSigningKeys = new ArraySet<>(certificates.length); 1488 for (int i = 0; i < certificates.length; i++) { 1489 Certificate[] signerCerts = certificates[i]; 1490 Certificate signerCert = signerCerts[0]; 1491 pkg.mSigningKeys.add(signerCert.getPublicKey()); 1492 } 1493 // add signatures to child packages 1494 final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; 1495 for (int i = 0; i < childCount; i++) { 1496 Package childPkg = pkg.childPackages.get(i); 1497 childPkg.mCertificates = pkg.mCertificates; 1498 childPkg.mSignatures = pkg.mSignatures; 1499 childPkg.mSigningKeys = pkg.mSigningKeys; 1500 } 1501 } 1502 1503 /** 1504 * Collect certificates from all the APKs described in the given package, 1505 * populating {@link Package#mSignatures}. Also asserts that all APK 1506 * contents are signed correctly and consistently. 1507 */ 1508 public static void collectCertificates(Package pkg, int parseFlags) 1509 throws PackageParserException { 1510 collectCertificatesInternal(pkg, parseFlags); 1511 final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; 1512 for (int i = 0; i < childCount; i++) { 1513 Package childPkg = pkg.childPackages.get(i); 1514 childPkg.mCertificates = pkg.mCertificates; 1515 childPkg.mSignatures = pkg.mSignatures; 1516 childPkg.mSigningKeys = pkg.mSigningKeys; 1517 } 1518 } 1519 1520 private static void collectCertificatesInternal(Package pkg, int parseFlags) 1521 throws PackageParserException { 1522 pkg.mCertificates = null; 1523 pkg.mSignatures = null; 1524 pkg.mSigningKeys = null; 1525 1526 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); 1527 try { 1528 collectCertificates(pkg, new File(pkg.baseCodePath), parseFlags); 1529 1530 if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { 1531 for (int i = 0; i < pkg.splitCodePaths.length; i++) { 1532 collectCertificates(pkg, new File(pkg.splitCodePaths[i]), parseFlags); 1533 } 1534 } 1535 } finally { 1536 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1537 } 1538 } 1539 1540 private static void collectCertificates(Package pkg, File apkFile, int parseFlags) 1541 throws PackageParserException { 1542 final String apkPath = apkFile.getAbsolutePath(); 1543 1544 // Try to verify the APK using APK Signature Scheme v2. 1545 boolean verified = false; 1546 { 1547 Certificate[][] allSignersCerts = null; 1548 Signature[] signatures = null; 1549 try { 1550 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2"); 1551 allSignersCerts = ApkSignatureSchemeV2Verifier.verify(apkPath); 1552 signatures = convertToSignatures(allSignersCerts); 1553 // APK verified using APK Signature Scheme v2. 1554 verified = true; 1555 } catch (ApkSignatureSchemeV2Verifier.SignatureNotFoundException e) { 1556 // No APK Signature Scheme v2 signature found 1557 if ((parseFlags & PARSE_IS_EPHEMERAL) != 0) { 1558 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1559 "No APK Signature Scheme v2 signature in ephemeral package " + apkPath, 1560 e); 1561 } 1562 // Static shared libraries must use only the V2 signing scheme 1563 if (pkg.applicationInfo.isStaticSharedLibrary()) { 1564 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1565 "Static shared libs must use v2 signature scheme " + apkPath); 1566 } 1567 } catch (Exception e) { 1568 // APK Signature Scheme v2 signature was found but did not verify 1569 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1570 "Failed to collect certificates from " + apkPath 1571 + " using APK Signature Scheme v2", 1572 e); 1573 } finally { 1574 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1575 } 1576 1577 if (verified) { 1578 if (pkg.mCertificates == null) { 1579 pkg.mCertificates = allSignersCerts; 1580 pkg.mSignatures = signatures; 1581 pkg.mSigningKeys = new ArraySet<>(allSignersCerts.length); 1582 for (int i = 0; i < allSignersCerts.length; i++) { 1583 Certificate[] signerCerts = allSignersCerts[i]; 1584 Certificate signerCert = signerCerts[0]; 1585 pkg.mSigningKeys.add(signerCert.getPublicKey()); 1586 } 1587 } else { 1588 if (!Signature.areExactMatch(pkg.mSignatures, signatures)) { 1589 throw new PackageParserException( 1590 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, 1591 apkPath + " has mismatched certificates"); 1592 } 1593 } 1594 // Not yet done, because we need to confirm that AndroidManifest.xml exists and, 1595 // if requested, that classes.dex exists. 1596 } 1597 } 1598 1599 StrictJarFile jarFile = null; 1600 try { 1601 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor"); 1602 // Ignore signature stripping protections when verifying APKs from system partition. 1603 // For those APKs we only care about extracting signer certificates, and don't care 1604 // about verifying integrity. 1605 boolean signatureSchemeRollbackProtectionsEnforced = 1606 (parseFlags & PARSE_IS_SYSTEM_DIR) == 0; 1607 jarFile = new StrictJarFile( 1608 apkPath, 1609 !verified, // whether to verify JAR signature 1610 signatureSchemeRollbackProtectionsEnforced); 1611 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1612 1613 // Always verify manifest, regardless of source 1614 final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME); 1615 if (manifestEntry == null) { 1616 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 1617 "Package " + apkPath + " has no manifest"); 1618 } 1619 1620 // Optimization: early termination when APK already verified 1621 if (verified) { 1622 return; 1623 } 1624 1625 // APK's integrity needs to be verified using JAR signature scheme. 1626 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV1"); 1627 final List<ZipEntry> toVerify = new ArrayList<>(); 1628 toVerify.add(manifestEntry); 1629 1630 // If we're parsing an untrusted package, verify all contents 1631 if ((parseFlags & PARSE_IS_SYSTEM_DIR) == 0) { 1632 final Iterator<ZipEntry> i = jarFile.iterator(); 1633 while (i.hasNext()) { 1634 final ZipEntry entry = i.next(); 1635 1636 if (entry.isDirectory()) continue; 1637 1638 final String entryName = entry.getName(); 1639 if (entryName.startsWith("META-INF/")) continue; 1640 if (entryName.equals(ANDROID_MANIFEST_FILENAME)) continue; 1641 1642 toVerify.add(entry); 1643 } 1644 } 1645 1646 // Verify that entries are signed consistently with the first entry 1647 // we encountered. Note that for splits, certificates may have 1648 // already been populated during an earlier parse of a base APK. 1649 for (ZipEntry entry : toVerify) { 1650 final Certificate[][] entryCerts = loadCertificates(jarFile, entry); 1651 if (ArrayUtils.isEmpty(entryCerts)) { 1652 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1653 "Package " + apkPath + " has no certificates at entry " 1654 + entry.getName()); 1655 } 1656 final Signature[] entrySignatures = convertToSignatures(entryCerts); 1657 1658 if (pkg.mCertificates == null) { 1659 pkg.mCertificates = entryCerts; 1660 pkg.mSignatures = entrySignatures; 1661 pkg.mSigningKeys = new ArraySet<PublicKey>(); 1662 for (int i=0; i < entryCerts.length; i++) { 1663 pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey()); 1664 } 1665 } else { 1666 if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) { 1667 throw new PackageParserException( 1668 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath 1669 + " has mismatched certificates at entry " 1670 + entry.getName()); 1671 } 1672 } 1673 } 1674 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1675 } catch (GeneralSecurityException e) { 1676 throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING, 1677 "Failed to collect certificates from " + apkPath, e); 1678 } catch (IOException | RuntimeException e) { 1679 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1680 "Failed to collect certificates from " + apkPath, e); 1681 } finally { 1682 closeQuietly(jarFile); 1683 } 1684 } 1685 1686 private static Signature[] convertToSignatures(Certificate[][] certs) 1687 throws CertificateEncodingException { 1688 final Signature[] res = new Signature[certs.length]; 1689 for (int i = 0; i < certs.length; i++) { 1690 res[i] = new Signature(certs[i]); 1691 } 1692 return res; 1693 } 1694 1695 private static AssetManager newConfiguredAssetManager() { 1696 AssetManager assetManager = new AssetManager(); 1697 assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1698 Build.VERSION.RESOURCES_SDK_INT); 1699 return assetManager; 1700 } 1701 1702 /** 1703 * Utility method that retrieves lightweight details about a single APK 1704 * file, including package name, split name, and install location. 1705 * 1706 * @param apkFile path to a single APK 1707 * @param flags optional parse flags, such as 1708 * {@link #PARSE_COLLECT_CERTIFICATES} 1709 */ 1710 public static ApkLite parseApkLite(File apkFile, int flags) 1711 throws PackageParserException { 1712 final String apkPath = apkFile.getAbsolutePath(); 1713 1714 AssetManager assets = null; 1715 XmlResourceParser parser = null; 1716 try { 1717 assets = newConfiguredAssetManager(); 1718 int cookie = assets.addAssetPath(apkPath); 1719 if (cookie == 0) { 1720 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 1721 "Failed to parse " + apkPath); 1722 } 1723 1724 final DisplayMetrics metrics = new DisplayMetrics(); 1725 metrics.setToDefaults(); 1726 1727 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 1728 1729 final Signature[] signatures; 1730 final Certificate[][] certificates; 1731 if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { 1732 // TODO: factor signature related items out of Package object 1733 final Package tempPkg = new Package((String) null); 1734 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); 1735 try { 1736 collectCertificates(tempPkg, apkFile, flags); 1737 } finally { 1738 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1739 } 1740 signatures = tempPkg.mSignatures; 1741 certificates = tempPkg.mCertificates; 1742 } else { 1743 signatures = null; 1744 certificates = null; 1745 } 1746 1747 final AttributeSet attrs = parser; 1748 return parseApkLite(apkPath, parser, attrs, signatures, certificates); 1749 1750 } catch (XmlPullParserException | IOException | RuntimeException e) { 1751 Slog.w(TAG, "Failed to parse " + apkPath, e); 1752 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 1753 "Failed to parse " + apkPath, e); 1754 } finally { 1755 IoUtils.closeQuietly(parser); 1756 IoUtils.closeQuietly(assets); 1757 } 1758 } 1759 1760 private static String validateName(String name, boolean requireSeparator, 1761 boolean requireFilename) { 1762 final int N = name.length(); 1763 boolean hasSep = false; 1764 boolean front = true; 1765 for (int i=0; i<N; i++) { 1766 final char c = name.charAt(i); 1767 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { 1768 front = false; 1769 continue; 1770 } 1771 if (!front) { 1772 if ((c >= '0' && c <= '9') || c == '_') { 1773 continue; 1774 } 1775 } 1776 if (c == '.') { 1777 hasSep = true; 1778 front = true; 1779 continue; 1780 } 1781 return "bad character '" + c + "'"; 1782 } 1783 if (requireFilename && !FileUtils.isValidExtFilename(name)) { 1784 return "Invalid filename"; 1785 } 1786 return hasSep || !requireSeparator 1787 ? null : "must have at least one '.' separator"; 1788 } 1789 1790 private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser, 1791 AttributeSet attrs) throws IOException, XmlPullParserException, 1792 PackageParserException { 1793 1794 int type; 1795 while ((type = parser.next()) != XmlPullParser.START_TAG 1796 && type != XmlPullParser.END_DOCUMENT) { 1797 } 1798 1799 if (type != XmlPullParser.START_TAG) { 1800 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 1801 "No start tag found"); 1802 } 1803 if (!parser.getName().equals(TAG_MANIFEST)) { 1804 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 1805 "No <manifest> tag"); 1806 } 1807 1808 final String packageName = attrs.getAttributeValue(null, "package"); 1809 if (!"android".equals(packageName)) { 1810 final String error = validateName(packageName, true, true); 1811 if (error != null) { 1812 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, 1813 "Invalid manifest package: " + error); 1814 } 1815 } 1816 1817 String splitName = attrs.getAttributeValue(null, "split"); 1818 if (splitName != null) { 1819 if (splitName.length() == 0) { 1820 splitName = null; 1821 } else { 1822 final String error = validateName(splitName, false, false); 1823 if (error != null) { 1824 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, 1825 "Invalid manifest split: " + error); 1826 } 1827 } 1828 } 1829 1830 return Pair.create(packageName.intern(), 1831 (splitName != null) ? splitName.intern() : splitName); 1832 } 1833 1834 private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs, 1835 Signature[] signatures, Certificate[][] certificates) 1836 throws IOException, XmlPullParserException, PackageParserException { 1837 final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs); 1838 1839 int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; 1840 int versionCode = 0; 1841 int revisionCode = 0; 1842 boolean coreApp = false; 1843 boolean debuggable = false; 1844 boolean multiArch = false; 1845 boolean use32bitAbi = false; 1846 boolean extractNativeLibs = true; 1847 boolean isolatedSplits = false; 1848 boolean isFeatureSplit = false; 1849 String configForSplit = null; 1850 String usesSplitName = null; 1851 1852 for (int i = 0; i < attrs.getAttributeCount(); i++) { 1853 final String attr = attrs.getAttributeName(i); 1854 if (attr.equals("installLocation")) { 1855 installLocation = attrs.getAttributeIntValue(i, 1856 PARSE_DEFAULT_INSTALL_LOCATION); 1857 } else if (attr.equals("versionCode")) { 1858 versionCode = attrs.getAttributeIntValue(i, 0); 1859 } else if (attr.equals("revisionCode")) { 1860 revisionCode = attrs.getAttributeIntValue(i, 0); 1861 } else if (attr.equals("coreApp")) { 1862 coreApp = attrs.getAttributeBooleanValue(i, false); 1863 } else if (attr.equals("isolatedSplits")) { 1864 isolatedSplits = attrs.getAttributeBooleanValue(i, false); 1865 } else if (attr.equals("configForSplit")) { 1866 configForSplit = attrs.getAttributeValue(i); 1867 } else if (attr.equals("isFeatureSplit")) { 1868 isFeatureSplit = attrs.getAttributeBooleanValue(i, false); 1869 } 1870 } 1871 1872 // Only search the tree when the tag is directly below <manifest> 1873 int type; 1874 final int searchDepth = parser.getDepth() + 1; 1875 1876 final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>(); 1877 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1878 && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) { 1879 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1880 continue; 1881 } 1882 1883 if (parser.getDepth() != searchDepth) { 1884 continue; 1885 } 1886 1887 if (TAG_PACKAGE_VERIFIER.equals(parser.getName())) { 1888 final VerifierInfo verifier = parseVerifier(attrs); 1889 if (verifier != null) { 1890 verifiers.add(verifier); 1891 } 1892 } else if (TAG_APPLICATION.equals(parser.getName())) { 1893 for (int i = 0; i < attrs.getAttributeCount(); ++i) { 1894 final String attr = attrs.getAttributeName(i); 1895 if ("debuggable".equals(attr)) { 1896 debuggable = attrs.getAttributeBooleanValue(i, false); 1897 } 1898 if ("multiArch".equals(attr)) { 1899 multiArch = attrs.getAttributeBooleanValue(i, false); 1900 } 1901 if ("use32bitAbi".equals(attr)) { 1902 use32bitAbi = attrs.getAttributeBooleanValue(i, false); 1903 } 1904 if ("extractNativeLibs".equals(attr)) { 1905 extractNativeLibs = attrs.getAttributeBooleanValue(i, true); 1906 } 1907 } 1908 } else if (TAG_USES_SPLIT.equals(parser.getName())) { 1909 if (usesSplitName != null) { 1910 Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others."); 1911 continue; 1912 } 1913 1914 usesSplitName = attrs.getAttributeValue(ANDROID_RESOURCES, "name"); 1915 if (usesSplitName == null) { 1916 throw new PackageParserException( 1917 PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 1918 "<uses-split> tag requires 'android:name' attribute"); 1919 } 1920 } 1921 } 1922 1923 return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit, 1924 configForSplit, usesSplitName, versionCode, revisionCode, installLocation, 1925 verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi, 1926 extractNativeLibs, isolatedSplits); 1927 } 1928 1929 /** 1930 * Parses a child package and adds it to the parent if successful. If you add 1931 * new tags that need to be supported by child packages make sure to add them 1932 * to {@link #CHILD_PACKAGE_TAGS}. 1933 * 1934 * @param parentPkg The parent that contains the child 1935 * @param res Resources against which to resolve values 1936 * @param parser Parser of the manifest 1937 * @param flags Flags about how to parse 1938 * @param outError Human readable error if parsing fails 1939 * @return True of parsing succeeded. 1940 * 1941 * @throws XmlPullParserException 1942 * @throws IOException 1943 */ 1944 private boolean parseBaseApkChild(Package parentPkg, Resources res, XmlResourceParser parser, 1945 int flags, String[] outError) throws XmlPullParserException, IOException { 1946 // Let ppl not abuse this mechanism by limiting the packages per APK 1947 if (parentPkg.childPackages != null && parentPkg.childPackages.size() + 2 1948 > MAX_PACKAGES_PER_APK) { 1949 outError[0] = "Maximum number of packages per APK is: " + MAX_PACKAGES_PER_APK; 1950 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1951 return false; 1952 } 1953 1954 // Make sure we have a valid child package name 1955 String childPackageName = parser.getAttributeValue(null, "package"); 1956 if (validateName(childPackageName, true, false) != null) { 1957 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 1958 return false; 1959 } 1960 1961 // Child packages must be unique 1962 if (childPackageName.equals(parentPkg.packageName)) { 1963 String message = "Child package name cannot be equal to parent package name: " 1964 + parentPkg.packageName; 1965 Slog.w(TAG, message); 1966 outError[0] = message; 1967 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1968 return false; 1969 } 1970 1971 // Child packages must be unique 1972 if (parentPkg.hasChildPackage(childPackageName)) { 1973 String message = "Duplicate child package:" + childPackageName; 1974 Slog.w(TAG, message); 1975 outError[0] = message; 1976 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1977 return false; 1978 } 1979 1980 // Go ahead and parse the child 1981 Package childPkg = new Package(childPackageName); 1982 1983 // Child package inherits parent version code/name/target SDK 1984 childPkg.mVersionCode = parentPkg.mVersionCode; 1985 childPkg.baseRevisionCode = parentPkg.baseRevisionCode; 1986 childPkg.mVersionName = parentPkg.mVersionName; 1987 childPkg.applicationInfo.targetSdkVersion = parentPkg.applicationInfo.targetSdkVersion; 1988 childPkg.applicationInfo.minSdkVersion = parentPkg.applicationInfo.minSdkVersion; 1989 1990 childPkg = parseBaseApkCommon(childPkg, CHILD_PACKAGE_TAGS, res, parser, flags, outError); 1991 if (childPkg == null) { 1992 // If we got null then error was set during child parsing 1993 return false; 1994 } 1995 1996 // Set the parent-child relation 1997 if (parentPkg.childPackages == null) { 1998 parentPkg.childPackages = new ArrayList<>(); 1999 } 2000 parentPkg.childPackages.add(childPkg); 2001 childPkg.parentPackage = parentPkg; 2002 2003 return true; 2004 } 2005 2006 /** 2007 * Parse the manifest of a <em>base APK</em>. When adding new features you 2008 * need to consider whether they should be supported by split APKs and child 2009 * packages. 2010 * 2011 * @param apkPath The package apk file path 2012 * @param res The resources from which to resolve values 2013 * @param parser The manifest parser 2014 * @param flags Flags how to parse 2015 * @param outError Human readable error message 2016 * @return Parsed package or null on error. 2017 * 2018 * @throws XmlPullParserException 2019 * @throws IOException 2020 */ 2021 private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags, 2022 String[] outError) throws XmlPullParserException, IOException { 2023 final String splitName; 2024 final String pkgName; 2025 2026 try { 2027 Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser); 2028 pkgName = packageSplit.first; 2029 splitName = packageSplit.second; 2030 2031 if (!TextUtils.isEmpty(splitName)) { 2032 outError[0] = "Expected base APK, but found split " + splitName; 2033 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 2034 return null; 2035 } 2036 } catch (PackageParserException e) { 2037 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 2038 return null; 2039 } 2040 2041 if (mCallback != null) { 2042 String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath); 2043 if (overlayPaths != null && overlayPaths.length > 0) { 2044 for (String overlayPath : overlayPaths) { 2045 res.getAssets().addOverlayPath(overlayPath); 2046 } 2047 } 2048 } 2049 2050 final Package pkg = new Package(pkgName); 2051 2052 TypedArray sa = res.obtainAttributes(parser, 2053 com.android.internal.R.styleable.AndroidManifest); 2054 2055 pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger( 2056 com.android.internal.R.styleable.AndroidManifest_versionCode, 0); 2057 pkg.baseRevisionCode = sa.getInteger( 2058 com.android.internal.R.styleable.AndroidManifest_revisionCode, 0); 2059 pkg.mVersionName = sa.getNonConfigurationString( 2060 com.android.internal.R.styleable.AndroidManifest_versionName, 0); 2061 if (pkg.mVersionName != null) { 2062 pkg.mVersionName = pkg.mVersionName.intern(); 2063 } 2064 2065 pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false); 2066 2067 sa.recycle(); 2068 2069 return parseBaseApkCommon(pkg, null, res, parser, flags, outError); 2070 } 2071 2072 /** 2073 * This is the common parsing routing for handling parent and child 2074 * packages in a base APK. The difference between parent and child 2075 * parsing is that some tags are not supported by child packages as 2076 * well as some manifest attributes are ignored. The implementation 2077 * assumes the calling code has already handled the manifest tag if needed 2078 * (this applies to the parent only). 2079 * 2080 * @param pkg The package which to populate 2081 * @param acceptedTags Which tags to handle, null to handle all 2082 * @param res Resources against which to resolve values 2083 * @param parser Parser of the manifest 2084 * @param flags Flags about how to parse 2085 * @param outError Human readable error if parsing fails 2086 * @return The package if parsing succeeded or null. 2087 * 2088 * @throws XmlPullParserException 2089 * @throws IOException 2090 */ 2091 private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res, 2092 XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, 2093 IOException { 2094 mParseInstrumentationArgs = null; 2095 2096 int type; 2097 boolean foundApp = false; 2098 2099 TypedArray sa = res.obtainAttributes(parser, 2100 com.android.internal.R.styleable.AndroidManifest); 2101 2102 String str = sa.getNonConfigurationString( 2103 com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); 2104 if (str != null && str.length() > 0) { 2105 if ((flags & PARSE_IS_EPHEMERAL) != 0) { 2106 outError[0] = "sharedUserId not allowed in ephemeral application"; 2107 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; 2108 return null; 2109 } 2110 String nameError = validateName(str, true, false); 2111 if (nameError != null && !"android".equals(pkg.packageName)) { 2112 outError[0] = "<manifest> specifies bad sharedUserId name \"" 2113 + str + "\": " + nameError; 2114 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; 2115 return null; 2116 } 2117 pkg.mSharedUserId = str.intern(); 2118 pkg.mSharedUserLabel = sa.getResourceId( 2119 com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0); 2120 } 2121 2122 pkg.installLocation = sa.getInteger( 2123 com.android.internal.R.styleable.AndroidManifest_installLocation, 2124 PARSE_DEFAULT_INSTALL_LOCATION); 2125 pkg.applicationInfo.installLocation = pkg.installLocation; 2126 2127 final int targetSandboxVersion = sa.getInteger( 2128 com.android.internal.R.styleable.AndroidManifest_targetSandboxVersion, 2129 PARSE_DEFAULT_TARGET_SANDBOX); 2130 pkg.applicationInfo.targetSandboxVersion = targetSandboxVersion; 2131 2132 /* Set the global "forward lock" flag */ 2133 if ((flags & PARSE_FORWARD_LOCK) != 0) { 2134 pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK; 2135 } 2136 2137 /* Set the global "on SD card" flag */ 2138 if ((flags & PARSE_EXTERNAL_STORAGE) != 0) { 2139 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; 2140 } 2141 2142 if (sa.getBoolean(com.android.internal.R.styleable.AndroidManifest_isolatedSplits, false)) { 2143 pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING; 2144 } 2145 2146 // Resource boolean are -1, so 1 means we don't know the value. 2147 int supportsSmallScreens = 1; 2148 int supportsNormalScreens = 1; 2149 int supportsLargeScreens = 1; 2150 int supportsXLargeScreens = 1; 2151 int resizeable = 1; 2152 int anyDensity = 1; 2153 2154 int outerDepth = parser.getDepth(); 2155 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 2156 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 2157 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2158 continue; 2159 } 2160 2161 String tagName = parser.getName(); 2162 2163 if (acceptedTags != null && !acceptedTags.contains(tagName)) { 2164 Slog.w(TAG, "Skipping unsupported element under <manifest>: " 2165 + tagName + " at " + mArchiveSourcePath + " " 2166 + parser.getPositionDescription()); 2167 XmlUtils.skipCurrentTag(parser); 2168 continue; 2169 } 2170 2171 if (tagName.equals(TAG_APPLICATION)) { 2172 if (foundApp) { 2173 if (RIGID_PARSER) { 2174 outError[0] = "<manifest> has more than one <application>"; 2175 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2176 return null; 2177 } else { 2178 Slog.w(TAG, "<manifest> has more than one <application>"); 2179 XmlUtils.skipCurrentTag(parser); 2180 continue; 2181 } 2182 } 2183 2184 foundApp = true; 2185 if (!parseBaseApplication(pkg, res, parser, flags, outError)) { 2186 return null; 2187 } 2188 } else if (tagName.equals(TAG_OVERLAY)) { 2189 sa = res.obtainAttributes(parser, 2190 com.android.internal.R.styleable.AndroidManifestResourceOverlay); 2191 pkg.mOverlayTarget = sa.getString( 2192 com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage); 2193 pkg.mOverlayPriority = sa.getInt( 2194 com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority, 2195 0); 2196 pkg.mIsStaticOverlay = sa.getBoolean( 2197 com.android.internal.R.styleable.AndroidManifestResourceOverlay_isStatic, 2198 false); 2199 final String propName = sa.getString( 2200 com.android.internal.R.styleable 2201 .AndroidManifestResourceOverlay_requiredSystemPropertyName); 2202 final String propValue = sa.getString( 2203 com.android.internal.R.styleable 2204 .AndroidManifestResourceOverlay_requiredSystemPropertyValue); 2205 sa.recycle(); 2206 2207 if (pkg.mOverlayTarget == null) { 2208 outError[0] = "<overlay> does not specify a target package"; 2209 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2210 return null; 2211 } 2212 2213 if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) { 2214 outError[0] = "<overlay> priority must be between 0 and 9999"; 2215 mParseError = 2216 PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2217 return null; 2218 } 2219 2220 // check to see if overlay should be excluded based on system property condition 2221 if (!checkOverlayRequiredSystemProperty(propName, propValue)) { 2222 Slog.i(TAG, "Skipping target and overlay pair " + pkg.mOverlayTarget + " and " 2223 + pkg.baseCodePath+ ": overlay ignored due to required system property: " 2224 + propName + " with value: " + propValue); 2225 return null; 2226 } 2227 2228 XmlUtils.skipCurrentTag(parser); 2229 2230 } else if (tagName.equals(TAG_KEY_SETS)) { 2231 if (!parseKeySets(pkg, res, parser, outError)) { 2232 return null; 2233 } 2234 } else if (tagName.equals(TAG_PERMISSION_GROUP)) { 2235 if (!parsePermissionGroup(pkg, flags, res, parser, outError)) { 2236 return null; 2237 } 2238 } else if (tagName.equals(TAG_PERMISSION)) { 2239 if (!parsePermission(pkg, res, parser, outError)) { 2240 return null; 2241 } 2242 } else if (tagName.equals(TAG_PERMISSION_TREE)) { 2243 if (!parsePermissionTree(pkg, res, parser, outError)) { 2244 return null; 2245 } 2246 } else if (tagName.equals(TAG_USES_PERMISSION)) { 2247 if (!parseUsesPermission(pkg, res, parser)) { 2248 return null; 2249 } 2250 } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M) 2251 || tagName.equals(TAG_USES_PERMISSION_SDK_23)) { 2252 if (!parseUsesPermission(pkg, res, parser)) { 2253 return null; 2254 } 2255 } else if (tagName.equals(TAG_USES_CONFIGURATION)) { 2256 ConfigurationInfo cPref = new ConfigurationInfo(); 2257 sa = res.obtainAttributes(parser, 2258 com.android.internal.R.styleable.AndroidManifestUsesConfiguration); 2259 cPref.reqTouchScreen = sa.getInt( 2260 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, 2261 Configuration.TOUCHSCREEN_UNDEFINED); 2262 cPref.reqKeyboardType = sa.getInt( 2263 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, 2264 Configuration.KEYBOARD_UNDEFINED); 2265 if (sa.getBoolean( 2266 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, 2267 false)) { 2268 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; 2269 } 2270 cPref.reqNavigation = sa.getInt( 2271 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation, 2272 Configuration.NAVIGATION_UNDEFINED); 2273 if (sa.getBoolean( 2274 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, 2275 false)) { 2276 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; 2277 } 2278 sa.recycle(); 2279 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref); 2280 2281 XmlUtils.skipCurrentTag(parser); 2282 2283 } else if (tagName.equals(TAG_USES_FEATURE)) { 2284 FeatureInfo fi = parseUsesFeature(res, parser); 2285 pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi); 2286 2287 if (fi.name == null) { 2288 ConfigurationInfo cPref = new ConfigurationInfo(); 2289 cPref.reqGlEsVersion = fi.reqGlEsVersion; 2290 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref); 2291 } 2292 2293 XmlUtils.skipCurrentTag(parser); 2294 2295 } else if (tagName.equals(TAG_FEATURE_GROUP)) { 2296 FeatureGroupInfo group = new FeatureGroupInfo(); 2297 ArrayList<FeatureInfo> features = null; 2298 final int innerDepth = parser.getDepth(); 2299 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 2300 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 2301 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2302 continue; 2303 } 2304 2305 final String innerTagName = parser.getName(); 2306 if (innerTagName.equals("uses-feature")) { 2307 FeatureInfo featureInfo = parseUsesFeature(res, parser); 2308 // FeatureGroups are stricter and mandate that 2309 // any <uses-feature> declared are mandatory. 2310 featureInfo.flags |= FeatureInfo.FLAG_REQUIRED; 2311 features = ArrayUtils.add(features, featureInfo); 2312 } else { 2313 Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName + 2314 " at " + mArchiveSourcePath + " " + 2315 parser.getPositionDescription()); 2316 } 2317 XmlUtils.skipCurrentTag(parser); 2318 } 2319 2320 if (features != null) { 2321 group.features = new FeatureInfo[features.size()]; 2322 group.features = features.toArray(group.features); 2323 } 2324 pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group); 2325 2326 } else if (tagName.equals(TAG_USES_SDK)) { 2327 if (SDK_VERSION > 0) { 2328 sa = res.obtainAttributes(parser, 2329 com.android.internal.R.styleable.AndroidManifestUsesSdk); 2330 2331 int minVers = 1; 2332 String minCode = null; 2333 int targetVers = 0; 2334 String targetCode = null; 2335 2336 TypedValue val = sa.peekValue( 2337 com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); 2338 if (val != null) { 2339 if (val.type == TypedValue.TYPE_STRING && val.string != null) { 2340 targetCode = minCode = val.string.toString(); 2341 } else { 2342 // If it's not a string, it's an integer. 2343 targetVers = minVers = val.data; 2344 } 2345 } 2346 2347 val = sa.peekValue( 2348 com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); 2349 if (val != null) { 2350 if (val.type == TypedValue.TYPE_STRING && val.string != null) { 2351 targetCode = val.string.toString(); 2352 if (minCode == null) { 2353 minCode = targetCode; 2354 } 2355 } else { 2356 // If it's not a string, it's an integer. 2357 targetVers = val.data; 2358 } 2359 } 2360 2361 sa.recycle(); 2362 2363 final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode, 2364 SDK_VERSION, SDK_CODENAMES, outError); 2365 if (minSdkVersion < 0) { 2366 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 2367 return null; 2368 } 2369 2370 final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers, 2371 targetCode, SDK_VERSION, SDK_CODENAMES, outError); 2372 if (targetSdkVersion < 0) { 2373 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 2374 return null; 2375 } 2376 2377 pkg.applicationInfo.minSdkVersion = minSdkVersion; 2378 pkg.applicationInfo.targetSdkVersion = targetSdkVersion; 2379 } 2380 2381 XmlUtils.skipCurrentTag(parser); 2382 2383 } else if (tagName.equals(TAG_SUPPORT_SCREENS)) { 2384 sa = res.obtainAttributes(parser, 2385 com.android.internal.R.styleable.AndroidManifestSupportsScreens); 2386 2387 pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger( 2388 com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, 2389 0); 2390 pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger( 2391 com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, 2392 0); 2393 pkg.applicationInfo.largestWidthLimitDp = sa.getInteger( 2394 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, 2395 0); 2396 2397 // This is a trick to get a boolean and still able to detect 2398 // if a value was actually set. 2399 supportsSmallScreens = sa.getInteger( 2400 com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens, 2401 supportsSmallScreens); 2402 supportsNormalScreens = sa.getInteger( 2403 com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens, 2404 supportsNormalScreens); 2405 supportsLargeScreens = sa.getInteger( 2406 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens, 2407 supportsLargeScreens); 2408 supportsXLargeScreens = sa.getInteger( 2409 com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 2410 supportsXLargeScreens); 2411 resizeable = sa.getInteger( 2412 com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable, 2413 resizeable); 2414 anyDensity = sa.getInteger( 2415 com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity, 2416 anyDensity); 2417 2418 sa.recycle(); 2419 2420 XmlUtils.skipCurrentTag(parser); 2421 2422 } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) { 2423 sa = res.obtainAttributes(parser, 2424 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast); 2425 2426 // Note: don't allow this value to be a reference to a resource 2427 // that may change. 2428 String name = sa.getNonResourceString( 2429 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name); 2430 2431 sa.recycle(); 2432 2433 if (name != null && (flags&PARSE_IS_SYSTEM) != 0) { 2434 if (pkg.protectedBroadcasts == null) { 2435 pkg.protectedBroadcasts = new ArrayList<String>(); 2436 } 2437 if (!pkg.protectedBroadcasts.contains(name)) { 2438 pkg.protectedBroadcasts.add(name.intern()); 2439 } 2440 } 2441 2442 XmlUtils.skipCurrentTag(parser); 2443 2444 } else if (tagName.equals(TAG_INSTRUMENTATION)) { 2445 if (parseInstrumentation(pkg, res, parser, outError) == null) { 2446 return null; 2447 } 2448 } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) { 2449 sa = res.obtainAttributes(parser, 2450 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 2451 2452 String orig =sa.getNonConfigurationString( 2453 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 2454 if (!pkg.packageName.equals(orig)) { 2455 if (pkg.mOriginalPackages == null) { 2456 pkg.mOriginalPackages = new ArrayList<String>(); 2457 pkg.mRealPackage = pkg.packageName; 2458 } 2459 pkg.mOriginalPackages.add(orig); 2460 } 2461 2462 sa.recycle(); 2463 2464 XmlUtils.skipCurrentTag(parser); 2465 2466 } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) { 2467 sa = res.obtainAttributes(parser, 2468 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 2469 2470 String name = sa.getNonConfigurationString( 2471 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 2472 2473 sa.recycle(); 2474 2475 if (name != null) { 2476 if (pkg.mAdoptPermissions == null) { 2477 pkg.mAdoptPermissions = new ArrayList<String>(); 2478 } 2479 pkg.mAdoptPermissions.add(name); 2480 } 2481 2482 XmlUtils.skipCurrentTag(parser); 2483 2484 } else if (tagName.equals(TAG_USES_GL_TEXTURE)) { 2485 // Just skip this tag 2486 XmlUtils.skipCurrentTag(parser); 2487 continue; 2488 2489 } else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) { 2490 // Just skip this tag 2491 XmlUtils.skipCurrentTag(parser); 2492 continue; 2493 } else if (tagName.equals(TAG_SUPPORTS_INPUT)) {// 2494 XmlUtils.skipCurrentTag(parser); 2495 continue; 2496 2497 } else if (tagName.equals(TAG_EAT_COMMENT)) { 2498 // Just skip this tag 2499 XmlUtils.skipCurrentTag(parser); 2500 continue; 2501 2502 } else if (tagName.equals(TAG_PACKAGE)) { 2503 if (!MULTI_PACKAGE_APK_ENABLED) { 2504 XmlUtils.skipCurrentTag(parser); 2505 continue; 2506 } 2507 if (!parseBaseApkChild(pkg, res, parser, flags, outError)) { 2508 // If parsing a child failed the error is already set 2509 return null; 2510 } 2511 2512 } else if (tagName.equals(TAG_RESTRICT_UPDATE)) { 2513 if ((flags & PARSE_IS_SYSTEM_DIR) != 0) { 2514 sa = res.obtainAttributes(parser, 2515 com.android.internal.R.styleable.AndroidManifestRestrictUpdate); 2516 final String hash = sa.getNonConfigurationString( 2517 com.android.internal.R.styleable.AndroidManifestRestrictUpdate_hash, 0); 2518 sa.recycle(); 2519 2520 pkg.restrictUpdateHash = null; 2521 if (hash != null) { 2522 final int hashLength = hash.length(); 2523 final byte[] hashBytes = new byte[hashLength / 2]; 2524 for (int i = 0; i < hashLength; i += 2){ 2525 hashBytes[i/2] = (byte) ((Character.digit(hash.charAt(i), 16) << 4) 2526 + Character.digit(hash.charAt(i + 1), 16)); 2527 } 2528 pkg.restrictUpdateHash = hashBytes; 2529 } 2530 } 2531 2532 XmlUtils.skipCurrentTag(parser); 2533 2534 } else if (RIGID_PARSER) { 2535 outError[0] = "Bad element under <manifest>: " 2536 + parser.getName(); 2537 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2538 return null; 2539 2540 } else { 2541 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() 2542 + " at " + mArchiveSourcePath + " " 2543 + parser.getPositionDescription()); 2544 XmlUtils.skipCurrentTag(parser); 2545 continue; 2546 } 2547 } 2548 2549 if (!foundApp && pkg.instrumentation.size() == 0) { 2550 outError[0] = "<manifest> does not contain an <application> or <instrumentation>"; 2551 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; 2552 } 2553 2554 final int NP = PackageParser.NEW_PERMISSIONS.length; 2555 StringBuilder implicitPerms = null; 2556 for (int ip=0; ip<NP; ip++) { 2557 final PackageParser.NewPermissionInfo npi 2558 = PackageParser.NEW_PERMISSIONS[ip]; 2559 if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) { 2560 break; 2561 } 2562 if (!pkg.requestedPermissions.contains(npi.name)) { 2563 if (implicitPerms == null) { 2564 implicitPerms = new StringBuilder(128); 2565 implicitPerms.append(pkg.packageName); 2566 implicitPerms.append(": compat added "); 2567 } else { 2568 implicitPerms.append(' '); 2569 } 2570 implicitPerms.append(npi.name); 2571 pkg.requestedPermissions.add(npi.name); 2572 } 2573 } 2574 if (implicitPerms != null) { 2575 Slog.i(TAG, implicitPerms.toString()); 2576 } 2577 2578 final int NS = PackageParser.SPLIT_PERMISSIONS.length; 2579 for (int is=0; is<NS; is++) { 2580 final PackageParser.SplitPermissionInfo spi 2581 = PackageParser.SPLIT_PERMISSIONS[is]; 2582 if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk 2583 || !pkg.requestedPermissions.contains(spi.rootPerm)) { 2584 continue; 2585 } 2586 for (int in=0; in<spi.newPerms.length; in++) { 2587 final String perm = spi.newPerms[in]; 2588 if (!pkg.requestedPermissions.contains(perm)) { 2589 pkg.requestedPermissions.add(perm); 2590 } 2591 } 2592 } 2593 2594 if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 2595 && pkg.applicationInfo.targetSdkVersion 2596 >= android.os.Build.VERSION_CODES.DONUT)) { 2597 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; 2598 } 2599 if (supportsNormalScreens != 0) { 2600 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; 2601 } 2602 if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 2603 && pkg.applicationInfo.targetSdkVersion 2604 >= android.os.Build.VERSION_CODES.DONUT)) { 2605 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; 2606 } 2607 if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 2608 && pkg.applicationInfo.targetSdkVersion 2609 >= android.os.Build.VERSION_CODES.GINGERBREAD)) { 2610 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; 2611 } 2612 if (resizeable < 0 || (resizeable > 0 2613 && pkg.applicationInfo.targetSdkVersion 2614 >= android.os.Build.VERSION_CODES.DONUT)) { 2615 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; 2616 } 2617 if (anyDensity < 0 || (anyDensity > 0 2618 && pkg.applicationInfo.targetSdkVersion 2619 >= android.os.Build.VERSION_CODES.DONUT)) { 2620 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; 2621 } 2622 2623 // At this point we can check if an application is not supporting densities and hence 2624 // cannot be windowed / resized. Note that an SDK version of 0 is common for 2625 // pre-Doughnut applications. 2626 if (pkg.applicationInfo.usesCompatibilityMode()) { 2627 adjustPackageToBeUnresizeableAndUnpipable(pkg); 2628 } 2629 return pkg; 2630 } 2631 2632 private boolean checkOverlayRequiredSystemProperty(String propName, String propValue) { 2633 2634 if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) { 2635 if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) { 2636 // malformed condition - incomplete 2637 Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName 2638 + "=" + propValue + "' - require both requiredSystemPropertyName" 2639 + " AND requiredSystemPropertyValue to be specified."); 2640 return false; 2641 } 2642 // no valid condition set - so no exclusion criteria, overlay will be included. 2643 return true; 2644 } 2645 2646 // check property value - make sure it is both set and equal to expected value 2647 final String currValue = SystemProperties.get(propName); 2648 return (currValue != null && currValue.equals(propValue)); 2649 } 2650 2651 /** 2652 * This is a pre-density application which will get scaled - instead of being pixel perfect. 2653 * This type of application is not resizable. 2654 * 2655 * @param pkg The package which needs to be marked as unresizable. 2656 */ 2657 private void adjustPackageToBeUnresizeableAndUnpipable(Package pkg) { 2658 for (Activity a : pkg.activities) { 2659 a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; 2660 a.info.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE; 2661 } 2662 } 2663 2664 /** 2665 * Computes the targetSdkVersion to use at runtime. If the package is not 2666 * compatible with this platform, populates {@code outError[0]} with an 2667 * error message. 2668 * <p> 2669 * If {@code targetCode} is not specified, e.g. the value is {@code null}, 2670 * then the {@code targetVers} will be returned unmodified. 2671 * <p> 2672 * Otherwise, the behavior varies based on whether the current platform 2673 * is a pre-release version, e.g. the {@code platformSdkCodenames} array 2674 * has length > 0: 2675 * <ul> 2676 * <li>If this is a pre-release platform and the value specified by 2677 * {@code targetCode} is contained within the array of allowed pre-release 2678 * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}. 2679 * <li>If this is a released platform, this method will return -1 to 2680 * indicate that the package is not compatible with this platform. 2681 * </ul> 2682 * 2683 * @param targetVers targetSdkVersion number, if specified in the 2684 * application manifest, or 0 otherwise 2685 * @param targetCode targetSdkVersion code, if specified in the application 2686 * manifest, or {@code null} otherwise 2687 * @param platformSdkVersion platform SDK version number, typically 2688 * Build.VERSION.SDK_INT 2689 * @param platformSdkCodenames array of allowed pre-release SDK codenames 2690 * for this platform 2691 * @param outError output array to populate with error, if applicable 2692 * @return the targetSdkVersion to use at runtime, or -1 if the package is 2693 * not compatible with this platform 2694 * @hide Exposed for unit testing only. 2695 */ 2696 @TestApi 2697 public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers, 2698 @Nullable String targetCode, @IntRange(from = 1) int platformSdkVersion, 2699 @NonNull String[] platformSdkCodenames, @NonNull String[] outError) { 2700 // If it's a release SDK, return the version number unmodified. 2701 if (targetCode == null) { 2702 return targetVers; 2703 } 2704 2705 // If it's a pre-release SDK and the codename matches this platform, it 2706 // definitely targets this SDK. 2707 if (ArrayUtils.contains(platformSdkCodenames, targetCode)) { 2708 return Build.VERSION_CODES.CUR_DEVELOPMENT; 2709 } 2710 2711 // Otherwise, we're looking at an incompatible pre-release SDK. 2712 if (platformSdkCodenames.length > 0) { 2713 outError[0] = "Requires development platform " + targetCode 2714 + " (current platform is any of " 2715 + Arrays.toString(platformSdkCodenames) + ")"; 2716 } else { 2717 outError[0] = "Requires development platform " + targetCode 2718 + " but this is a release platform."; 2719 } 2720 return -1; 2721 } 2722 2723 /** 2724 * Computes the minSdkVersion to use at runtime. If the package is not 2725 * compatible with this platform, populates {@code outError[0]} with an 2726 * error message. 2727 * <p> 2728 * If {@code minCode} is not specified, e.g. the value is {@code null}, 2729 * then behavior varies based on the {@code platformSdkVersion}: 2730 * <ul> 2731 * <li>If the platform SDK version is greater than or equal to the 2732 * {@code minVers}, returns the {@code mniVers} unmodified. 2733 * <li>Otherwise, returns -1 to indicate that the package is not 2734 * compatible with this platform. 2735 * </ul> 2736 * <p> 2737 * Otherwise, the behavior varies based on whether the current platform 2738 * is a pre-release version, e.g. the {@code platformSdkCodenames} array 2739 * has length > 0: 2740 * <ul> 2741 * <li>If this is a pre-release platform and the value specified by 2742 * {@code targetCode} is contained within the array of allowed pre-release 2743 * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}. 2744 * <li>If this is a released platform, this method will return -1 to 2745 * indicate that the package is not compatible with this platform. 2746 * </ul> 2747 * 2748 * @param minVers minSdkVersion number, if specified in the application 2749 * manifest, or 1 otherwise 2750 * @param minCode minSdkVersion code, if specified in the application 2751 * manifest, or {@code null} otherwise 2752 * @param platformSdkVersion platform SDK version number, typically 2753 * Build.VERSION.SDK_INT 2754 * @param platformSdkCodenames array of allowed prerelease SDK codenames 2755 * for this platform 2756 * @param outError output array to populate with error, if applicable 2757 * @return the minSdkVersion to use at runtime, or -1 if the package is not 2758 * compatible with this platform 2759 * @hide Exposed for unit testing only. 2760 */ 2761 @TestApi 2762 public static int computeMinSdkVersion(@IntRange(from = 1) int minVers, 2763 @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion, 2764 @NonNull String[] platformSdkCodenames, @NonNull String[] outError) { 2765 // If it's a release SDK, make sure we meet the minimum SDK requirement. 2766 if (minCode == null) { 2767 if (minVers <= platformSdkVersion) { 2768 return minVers; 2769 } 2770 2771 // We don't meet the minimum SDK requirement. 2772 outError[0] = "Requires newer sdk version #" + minVers 2773 + " (current version is #" + platformSdkVersion + ")"; 2774 return -1; 2775 } 2776 2777 // If it's a pre-release SDK and the codename matches this platform, we 2778 // definitely meet the minimum SDK requirement. 2779 if (ArrayUtils.contains(platformSdkCodenames, minCode)) { 2780 return Build.VERSION_CODES.CUR_DEVELOPMENT; 2781 } 2782 2783 // Otherwise, we're looking at an incompatible pre-release SDK. 2784 if (platformSdkCodenames.length > 0) { 2785 outError[0] = "Requires development platform " + minCode 2786 + " (current platform is any of " 2787 + Arrays.toString(platformSdkCodenames) + ")"; 2788 } else { 2789 outError[0] = "Requires development platform " + minCode 2790 + " but this is a release platform."; 2791 } 2792 return -1; 2793 } 2794 2795 private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs) { 2796 FeatureInfo fi = new FeatureInfo(); 2797 TypedArray sa = res.obtainAttributes(attrs, 2798 com.android.internal.R.styleable.AndroidManifestUsesFeature); 2799 // Note: don't allow this value to be a reference to a resource 2800 // that may change. 2801 fi.name = sa.getNonResourceString( 2802 com.android.internal.R.styleable.AndroidManifestUsesFeature_name); 2803 fi.version = sa.getInt( 2804 com.android.internal.R.styleable.AndroidManifestUsesFeature_version, 0); 2805 if (fi.name == null) { 2806 fi.reqGlEsVersion = sa.getInt( 2807 com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion, 2808 FeatureInfo.GL_ES_VERSION_UNDEFINED); 2809 } 2810 if (sa.getBoolean( 2811 com.android.internal.R.styleable.AndroidManifestUsesFeature_required, true)) { 2812 fi.flags |= FeatureInfo.FLAG_REQUIRED; 2813 } 2814 sa.recycle(); 2815 return fi; 2816 } 2817 2818 private boolean parseUsesStaticLibrary(Package pkg, Resources res, XmlResourceParser parser, 2819 String[] outError) throws XmlPullParserException, IOException { 2820 TypedArray sa = res.obtainAttributes(parser, 2821 com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary); 2822 2823 // Note: don't allow this value to be a reference to a resource that may change. 2824 String lname = sa.getNonResourceString( 2825 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 2826 final int version = sa.getInt( 2827 com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary_version, -1); 2828 String certSha256Digest = sa.getNonResourceString(com.android.internal.R.styleable 2829 .AndroidManifestUsesStaticLibrary_certDigest); 2830 sa.recycle(); 2831 2832 // Since an APK providing a static shared lib can only provide the lib - fail if malformed 2833 if (lname == null || version < 0 || certSha256Digest == null) { 2834 outError[0] = "Bad uses-static-library declaration name: " + lname + " version: " 2835 + version + " certDigest" + certSha256Digest; 2836 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2837 XmlUtils.skipCurrentTag(parser); 2838 return false; 2839 } 2840 2841 // Can depend only on one version of the same library 2842 if (pkg.usesStaticLibraries != null && pkg.usesStaticLibraries.contains(lname)) { 2843 outError[0] = "Depending on multiple versions of static library " + lname; 2844 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2845 XmlUtils.skipCurrentTag(parser); 2846 return false; 2847 } 2848 2849 lname = lname.intern(); 2850 // We allow ":" delimiters in the SHA declaration as this is the format 2851 // emitted by the certtool making it easy for developers to copy/paste. 2852 certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); 2853 2854 // Fot apps targeting O-MR1 we require explicit enumeration of all certs. 2855 String[] additionalCertSha256Digests = EmptyArray.STRING; 2856 if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.O) { 2857 additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError); 2858 if (additionalCertSha256Digests == null) { 2859 return false; 2860 } 2861 } else { 2862 XmlUtils.skipCurrentTag(parser); 2863 } 2864 2865 final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1]; 2866 certSha256Digests[0] = certSha256Digest; 2867 System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, 2868 1, additionalCertSha256Digests.length); 2869 2870 pkg.usesStaticLibraries = ArrayUtils.add(pkg.usesStaticLibraries, lname); 2871 pkg.usesStaticLibrariesVersions = ArrayUtils.appendInt( 2872 pkg.usesStaticLibrariesVersions, version, true); 2873 pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class, 2874 pkg.usesStaticLibrariesCertDigests, certSha256Digests, true); 2875 2876 return true; 2877 } 2878 2879 private String[] parseAdditionalCertificates(Resources resources, XmlResourceParser parser, 2880 String[] outError) throws XmlPullParserException, IOException { 2881 String[] certSha256Digests = EmptyArray.STRING; 2882 2883 int outerDepth = parser.getDepth(); 2884 int type; 2885 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 2886 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 2887 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2888 continue; 2889 } 2890 2891 final String nodeName = parser.getName(); 2892 if (nodeName.equals("additional-certificate")) { 2893 final TypedArray sa = resources.obtainAttributes(parser, com.android.internal. 2894 R.styleable.AndroidManifestAdditionalCertificate); 2895 String certSha256Digest = sa.getNonResourceString(com.android.internal. 2896 R.styleable.AndroidManifestAdditionalCertificate_certDigest); 2897 sa.recycle(); 2898 2899 if (TextUtils.isEmpty(certSha256Digest)) { 2900 outError[0] = "Bad additional-certificate declaration with empty" 2901 + " certDigest:" + certSha256Digest; 2902 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2903 XmlUtils.skipCurrentTag(parser); 2904 sa.recycle(); 2905 return null; 2906 } 2907 2908 // We allow ":" delimiters in the SHA declaration as this is the format 2909 // emitted by the certtool making it easy for developers to copy/paste. 2910 certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); 2911 certSha256Digests = ArrayUtils.appendElement(String.class, 2912 certSha256Digests, certSha256Digest); 2913 } else { 2914 XmlUtils.skipCurrentTag(parser); 2915 } 2916 } 2917 2918 return certSha256Digests; 2919 } 2920 2921 private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser) 2922 throws XmlPullParserException, IOException { 2923 TypedArray sa = res.obtainAttributes(parser, 2924 com.android.internal.R.styleable.AndroidManifestUsesPermission); 2925 2926 // Note: don't allow this value to be a reference to a resource 2927 // that may change. 2928 String name = sa.getNonResourceString( 2929 com.android.internal.R.styleable.AndroidManifestUsesPermission_name); 2930 2931 int maxSdkVersion = 0; 2932 TypedValue val = sa.peekValue( 2933 com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion); 2934 if (val != null) { 2935 if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) { 2936 maxSdkVersion = val.data; 2937 } 2938 } 2939 2940 final String requiredFeature = sa.getNonConfigurationString( 2941 com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature, 0); 2942 2943 final String requiredNotfeature = sa.getNonConfigurationString( 2944 com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredNotFeature, 0); 2945 2946 sa.recycle(); 2947 2948 XmlUtils.skipCurrentTag(parser); 2949 2950 if (name == null) { 2951 return true; 2952 } 2953 2954 if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) { 2955 return true; 2956 } 2957 2958 // Only allow requesting this permission if the platform supports the given feature. 2959 if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(requiredFeature)) { 2960 return true; 2961 } 2962 2963 // Only allow requesting this permission if the platform doesn't support the given feature. 2964 if (requiredNotfeature != null && mCallback != null 2965 && mCallback.hasFeature(requiredNotfeature)) { 2966 return true; 2967 } 2968 2969 int index = pkg.requestedPermissions.indexOf(name); 2970 if (index == -1) { 2971 pkg.requestedPermissions.add(name.intern()); 2972 } else { 2973 Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: " 2974 + name + " in package: " + pkg.packageName + " at: " 2975 + parser.getPositionDescription()); 2976 } 2977 2978 return true; 2979 } 2980 2981 private static String buildClassName(String pkg, CharSequence clsSeq, 2982 String[] outError) { 2983 if (clsSeq == null || clsSeq.length() <= 0) { 2984 outError[0] = "Empty class name in package " + pkg; 2985 return null; 2986 } 2987 String cls = clsSeq.toString(); 2988 char c = cls.charAt(0); 2989 if (c == '.') { 2990 return pkg + cls; 2991 } 2992 if (cls.indexOf('.') < 0) { 2993 StringBuilder b = new StringBuilder(pkg); 2994 b.append('.'); 2995 b.append(cls); 2996 return b.toString(); 2997 } 2998 return cls; 2999 } 3000 3001 private static String buildCompoundName(String pkg, 3002 CharSequence procSeq, String type, String[] outError) { 3003 String proc = procSeq.toString(); 3004 char c = proc.charAt(0); 3005 if (pkg != null && c == ':') { 3006 if (proc.length() < 2) { 3007 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg 3008 + ": must be at least two characters"; 3009 return null; 3010 } 3011 String subName = proc.substring(1); 3012 String nameError = validateName(subName, false, false); 3013 if (nameError != null) { 3014 outError[0] = "Invalid " + type + " name " + proc + " in package " 3015 + pkg + ": " + nameError; 3016 return null; 3017 } 3018 return pkg + proc; 3019 } 3020 String nameError = validateName(proc, true, false); 3021 if (nameError != null && !"system".equals(proc)) { 3022 outError[0] = "Invalid " + type + " name " + proc + " in package " 3023 + pkg + ": " + nameError; 3024 return null; 3025 } 3026 return proc; 3027 } 3028 3029 private static String buildProcessName(String pkg, String defProc, 3030 CharSequence procSeq, int flags, String[] separateProcesses, 3031 String[] outError) { 3032 if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) { 3033 return defProc != null ? defProc : pkg; 3034 } 3035 if (separateProcesses != null) { 3036 for (int i=separateProcesses.length-1; i>=0; i--) { 3037 String sp = separateProcesses[i]; 3038 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) { 3039 return pkg; 3040 } 3041 } 3042 } 3043 if (procSeq == null || procSeq.length() <= 0) { 3044 return defProc; 3045 } 3046 return TextUtils.safeIntern(buildCompoundName(pkg, procSeq, "process", outError)); 3047 } 3048 3049 private static String buildTaskAffinityName(String pkg, String defProc, 3050 CharSequence procSeq, String[] outError) { 3051 if (procSeq == null) { 3052 return defProc; 3053 } 3054 if (procSeq.length() <= 0) { 3055 return null; 3056 } 3057 return buildCompoundName(pkg, procSeq, "taskAffinity", outError); 3058 } 3059 3060 private boolean parseKeySets(Package owner, Resources res, 3061 XmlResourceParser parser, String[] outError) 3062 throws XmlPullParserException, IOException { 3063 // we've encountered the 'key-sets' tag 3064 // all the keys and keysets that we want must be defined here 3065 // so we're going to iterate over the parser and pull out the things we want 3066 int outerDepth = parser.getDepth(); 3067 int currentKeySetDepth = -1; 3068 int type; 3069 String currentKeySet = null; 3070 ArrayMap<String, PublicKey> publicKeys = new ArrayMap<String, PublicKey>(); 3071 ArraySet<String> upgradeKeySets = new ArraySet<String>(); 3072 ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<String, ArraySet<String>>(); 3073 ArraySet<String> improperKeySets = new ArraySet<String>(); 3074 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 3075 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 3076 if (type == XmlPullParser.END_TAG) { 3077 if (parser.getDepth() == currentKeySetDepth) { 3078 currentKeySet = null; 3079 currentKeySetDepth = -1; 3080 } 3081 continue; 3082 } 3083 String tagName = parser.getName(); 3084 if (tagName.equals("key-set")) { 3085 if (currentKeySet != null) { 3086 outError[0] = "Improperly nested 'key-set' tag at " 3087 + parser.getPositionDescription(); 3088 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3089 return false; 3090 } 3091 final TypedArray sa = res.obtainAttributes(parser, 3092 com.android.internal.R.styleable.AndroidManifestKeySet); 3093 final String keysetName = sa.getNonResourceString( 3094 com.android.internal.R.styleable.AndroidManifestKeySet_name); 3095 definedKeySets.put(keysetName, new ArraySet<String>()); 3096 currentKeySet = keysetName; 3097 currentKeySetDepth = parser.getDepth(); 3098 sa.recycle(); 3099 } else if (tagName.equals("public-key")) { 3100 if (currentKeySet == null) { 3101 outError[0] = "Improperly nested 'key-set' tag at " 3102 + parser.getPositionDescription(); 3103 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3104 return false; 3105 } 3106 final TypedArray sa = res.obtainAttributes(parser, 3107 com.android.internal.R.styleable.AndroidManifestPublicKey); 3108 final String publicKeyName = sa.getNonResourceString( 3109 com.android.internal.R.styleable.AndroidManifestPublicKey_name); 3110 final String encodedKey = sa.getNonResourceString( 3111 com.android.internal.R.styleable.AndroidManifestPublicKey_value); 3112 if (encodedKey == null && publicKeys.get(publicKeyName) == null) { 3113 outError[0] = "'public-key' " + publicKeyName + " must define a public-key value" 3114 + " on first use at " + parser.getPositionDescription(); 3115 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3116 sa.recycle(); 3117 return false; 3118 } else if (encodedKey != null) { 3119 PublicKey currentKey = parsePublicKey(encodedKey); 3120 if (currentKey == null) { 3121 Slog.w(TAG, "No recognized valid key in 'public-key' tag at " 3122 + parser.getPositionDescription() + " key-set " + currentKeySet 3123 + " will not be added to the package's defined key-sets."); 3124 sa.recycle(); 3125 improperKeySets.add(currentKeySet); 3126 XmlUtils.skipCurrentTag(parser); 3127 continue; 3128 } 3129 if (publicKeys.get(publicKeyName) == null 3130 || publicKeys.get(publicKeyName).equals(currentKey)) { 3131 3132 /* public-key first definition, or matches old definition */ 3133 publicKeys.put(publicKeyName, currentKey); 3134 } else { 3135 outError[0] = "Value of 'public-key' " + publicKeyName 3136 + " conflicts with previously defined value at " 3137 + parser.getPositionDescription(); 3138 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3139 sa.recycle(); 3140 return false; 3141 } 3142 } 3143 definedKeySets.get(currentKeySet).add(publicKeyName); 3144 sa.recycle(); 3145 XmlUtils.skipCurrentTag(parser); 3146 } else if (tagName.equals("upgrade-key-set")) { 3147 final TypedArray sa = res.obtainAttributes(parser, 3148 com.android.internal.R.styleable.AndroidManifestUpgradeKeySet); 3149 String name = sa.getNonResourceString( 3150 com.android.internal.R.styleable.AndroidManifestUpgradeKeySet_name); 3151 upgradeKeySets.add(name); 3152 sa.recycle(); 3153 XmlUtils.skipCurrentTag(parser); 3154 } else if (RIGID_PARSER) { 3155 outError[0] = "Bad element under <key-sets>: " + parser.getName() 3156 + " at " + mArchiveSourcePath + " " 3157 + parser.getPositionDescription(); 3158 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3159 return false; 3160 } else { 3161 Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName() 3162 + " at " + mArchiveSourcePath + " " 3163 + parser.getPositionDescription()); 3164 XmlUtils.skipCurrentTag(parser); 3165 continue; 3166 } 3167 } 3168 Set<String> publicKeyNames = publicKeys.keySet(); 3169 if (publicKeyNames.removeAll(definedKeySets.keySet())) { 3170 outError[0] = "Package" + owner.packageName + " AndroidManifext.xml " 3171 + "'key-set' and 'public-key' names must be distinct."; 3172 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3173 return false; 3174 } 3175 owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>(); 3176 for (ArrayMap.Entry<String, ArraySet<String>> e: definedKeySets.entrySet()) { 3177 final String keySetName = e.getKey(); 3178 if (e.getValue().size() == 0) { 3179 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml " 3180 + "'key-set' " + keySetName + " has no valid associated 'public-key'." 3181 + " Not including in package's defined key-sets."); 3182 continue; 3183 } else if (improperKeySets.contains(keySetName)) { 3184 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml " 3185 + "'key-set' " + keySetName + " contained improper 'public-key'" 3186 + " tags. Not including in package's defined key-sets."); 3187 continue; 3188 } 3189 owner.mKeySetMapping.put(keySetName, new ArraySet<PublicKey>()); 3190 for (String s : e.getValue()) { 3191 owner.mKeySetMapping.get(keySetName).add(publicKeys.get(s)); 3192 } 3193 } 3194 if (owner.mKeySetMapping.keySet().containsAll(upgradeKeySets)) { 3195 owner.mUpgradeKeySets = upgradeKeySets; 3196 } else { 3197 outError[0] ="Package" + owner.packageName + " AndroidManifext.xml " 3198 + "does not define all 'upgrade-key-set's ."; 3199 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3200 return false; 3201 } 3202 return true; 3203 } 3204 3205 private boolean parsePermissionGroup(Package owner, int flags, Resources res, 3206 XmlResourceParser parser, String[] outError) 3207 throws XmlPullParserException, IOException { 3208 PermissionGroup perm = new PermissionGroup(owner); 3209 3210 TypedArray sa = res.obtainAttributes(parser, 3211 com.android.internal.R.styleable.AndroidManifestPermissionGroup); 3212 if (!parsePackageItemInfo(owner, perm.info, outError, 3213 "<permission-group>", sa, true /*nameRequired*/, 3214 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name, 3215 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label, 3216 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon, 3217 com.android.internal.R.styleable.AndroidManifestPermissionGroup_roundIcon, 3218 com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo, 3219 com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) { 3220 sa.recycle(); 3221 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3222 return false; 3223 } 3224 3225 perm.info.descriptionRes = sa.getResourceId( 3226 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description, 3227 0); 3228 perm.info.flags = sa.getInt( 3229 com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0); 3230 perm.info.priority = sa.getInt( 3231 com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0); 3232 if (perm.info.priority > 0 && (flags&PARSE_IS_SYSTEM) == 0) { 3233 perm.info.priority = 0; 3234 } 3235 3236 sa.recycle(); 3237 3238 if (!parseAllMetaData(res, parser, "<permission-group>", perm, 3239 outError)) { 3240 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3241 return false; 3242 } 3243 3244 owner.permissionGroups.add(perm); 3245 3246 return true; 3247 } 3248 3249 private boolean parsePermission(Package owner, Resources res, 3250 XmlResourceParser parser, String[] outError) 3251 throws XmlPullParserException, IOException { 3252 3253 TypedArray sa = res.obtainAttributes(parser, 3254 com.android.internal.R.styleable.AndroidManifestPermission); 3255 3256 Permission perm = new Permission(owner); 3257 if (!parsePackageItemInfo(owner, perm.info, outError, 3258 "<permission>", sa, true /*nameRequired*/, 3259 com.android.internal.R.styleable.AndroidManifestPermission_name, 3260 com.android.internal.R.styleable.AndroidManifestPermission_label, 3261 com.android.internal.R.styleable.AndroidManifestPermission_icon, 3262 com.android.internal.R.styleable.AndroidManifestPermission_roundIcon, 3263 com.android.internal.R.styleable.AndroidManifestPermission_logo, 3264 com.android.internal.R.styleable.AndroidManifestPermission_banner)) { 3265 sa.recycle(); 3266 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3267 return false; 3268 } 3269 3270 // Note: don't allow this value to be a reference to a resource 3271 // that may change. 3272 perm.info.group = sa.getNonResourceString( 3273 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup); 3274 if (perm.info.group != null) { 3275 perm.info.group = perm.info.group.intern(); 3276 } 3277 3278 perm.info.descriptionRes = sa.getResourceId( 3279 com.android.internal.R.styleable.AndroidManifestPermission_description, 3280 0); 3281 3282 perm.info.protectionLevel = sa.getInt( 3283 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel, 3284 PermissionInfo.PROTECTION_NORMAL); 3285 3286 perm.info.flags = sa.getInt( 3287 com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0); 3288 3289 sa.recycle(); 3290 3291 if (perm.info.protectionLevel == -1) { 3292 outError[0] = "<permission> does not specify protectionLevel"; 3293 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3294 return false; 3295 } 3296 3297 perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel); 3298 3299 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) { 3300 if ( (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_INSTANT) == 0 3301 && (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) == 0 3302 && (perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) != 3303 PermissionInfo.PROTECTION_SIGNATURE) { 3304 outError[0] = "<permission> protectionLevel specifies a non-instnat flag but is " 3305 + "not based on signature type"; 3306 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3307 return false; 3308 } 3309 } 3310 3311 if (!parseAllMetaData(res, parser, "<permission>", perm, outError)) { 3312 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3313 return false; 3314 } 3315 3316 owner.permissions.add(perm); 3317 3318 return true; 3319 } 3320 3321 private boolean parsePermissionTree(Package owner, Resources res, 3322 XmlResourceParser parser, String[] outError) 3323 throws XmlPullParserException, IOException { 3324 Permission perm = new Permission(owner); 3325 3326 TypedArray sa = res.obtainAttributes(parser, 3327 com.android.internal.R.styleable.AndroidManifestPermissionTree); 3328 3329 if (!parsePackageItemInfo(owner, perm.info, outError, 3330 "<permission-tree>", sa, true /*nameRequired*/, 3331 com.android.internal.R.styleable.AndroidManifestPermissionTree_name, 3332 com.android.internal.R.styleable.AndroidManifestPermissionTree_label, 3333 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon, 3334 com.android.internal.R.styleable.AndroidManifestPermissionTree_roundIcon, 3335 com.android.internal.R.styleable.AndroidManifestPermissionTree_logo, 3336 com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) { 3337 sa.recycle(); 3338 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3339 return false; 3340 } 3341 3342 sa.recycle(); 3343 3344 int index = perm.info.name.indexOf('.'); 3345 if (index > 0) { 3346 index = perm.info.name.indexOf('.', index+1); 3347 } 3348 if (index < 0) { 3349 outError[0] = "<permission-tree> name has less than three segments: " 3350 + perm.info.name; 3351 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3352 return false; 3353 } 3354 3355 perm.info.descriptionRes = 0; 3356 perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL; 3357 perm.tree = true; 3358 3359 if (!parseAllMetaData(res, parser, "<permission-tree>", perm, 3360 outError)) { 3361 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3362 return false; 3363 } 3364 3365 owner.permissions.add(perm); 3366 3367 return true; 3368 } 3369 3370 private Instrumentation parseInstrumentation(Package owner, Resources res, 3371 XmlResourceParser parser, String[] outError) 3372 throws XmlPullParserException, IOException { 3373 TypedArray sa = res.obtainAttributes(parser, 3374 com.android.internal.R.styleable.AndroidManifestInstrumentation); 3375 3376 if (mParseInstrumentationArgs == null) { 3377 mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError, 3378 com.android.internal.R.styleable.AndroidManifestInstrumentation_name, 3379 com.android.internal.R.styleable.AndroidManifestInstrumentation_label, 3380 com.android.internal.R.styleable.AndroidManifestInstrumentation_icon, 3381 com.android.internal.R.styleable.AndroidManifestInstrumentation_roundIcon, 3382 com.android.internal.R.styleable.AndroidManifestInstrumentation_logo, 3383 com.android.internal.R.styleable.AndroidManifestInstrumentation_banner); 3384 mParseInstrumentationArgs.tag = "<instrumentation>"; 3385 } 3386 3387 mParseInstrumentationArgs.sa = sa; 3388 3389 Instrumentation a = new Instrumentation(mParseInstrumentationArgs, 3390 new InstrumentationInfo()); 3391 if (outError[0] != null) { 3392 sa.recycle(); 3393 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3394 return null; 3395 } 3396 3397 String str; 3398 // Note: don't allow this value to be a reference to a resource 3399 // that may change. 3400 str = sa.getNonResourceString( 3401 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage); 3402 a.info.targetPackage = str != null ? str.intern() : null; 3403 3404 str = sa.getNonResourceString( 3405 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetProcesses); 3406 a.info.targetProcesses = str != null ? str.intern() : null; 3407 3408 a.info.handleProfiling = sa.getBoolean( 3409 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling, 3410 false); 3411 3412 a.info.functionalTest = sa.getBoolean( 3413 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest, 3414 false); 3415 3416 sa.recycle(); 3417 3418 if (a.info.targetPackage == null) { 3419 outError[0] = "<instrumentation> does not specify targetPackage"; 3420 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3421 return null; 3422 } 3423 3424 if (!parseAllMetaData(res, parser, "<instrumentation>", a, 3425 outError)) { 3426 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3427 return null; 3428 } 3429 3430 owner.instrumentation.add(a); 3431 3432 return a; 3433 } 3434 3435 /** 3436 * Parse the {@code application} XML tree at the current parse location in a 3437 * <em>base APK</em> manifest. 3438 * <p> 3439 * When adding new features, carefully consider if they should also be 3440 * supported by split APKs. 3441 */ 3442 private boolean parseBaseApplication(Package owner, Resources res, 3443 XmlResourceParser parser, int flags, String[] outError) 3444 throws XmlPullParserException, IOException { 3445 final ApplicationInfo ai = owner.applicationInfo; 3446 final String pkgName = owner.applicationInfo.packageName; 3447 3448 TypedArray sa = res.obtainAttributes(parser, 3449 com.android.internal.R.styleable.AndroidManifestApplication); 3450 3451 if (!parsePackageItemInfo(owner, ai, outError, 3452 "<application>", sa, false /*nameRequired*/, 3453 com.android.internal.R.styleable.AndroidManifestApplication_name, 3454 com.android.internal.R.styleable.AndroidManifestApplication_label, 3455 com.android.internal.R.styleable.AndroidManifestApplication_icon, 3456 com.android.internal.R.styleable.AndroidManifestApplication_roundIcon, 3457 com.android.internal.R.styleable.AndroidManifestApplication_logo, 3458 com.android.internal.R.styleable.AndroidManifestApplication_banner)) { 3459 sa.recycle(); 3460 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3461 return false; 3462 } 3463 3464 if (ai.name != null) { 3465 ai.className = ai.name; 3466 } 3467 3468 String manageSpaceActivity = sa.getNonConfigurationString( 3469 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity, 3470 Configuration.NATIVE_CONFIG_VERSION); 3471 if (manageSpaceActivity != null) { 3472 ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity, 3473 outError); 3474 } 3475 3476 boolean allowBackup = sa.getBoolean( 3477 com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true); 3478 if (allowBackup) { 3479 ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; 3480 3481 // backupAgent, killAfterRestore, fullBackupContent, backupInForeground, 3482 // and restoreAnyVersion are only relevant if backup is possible for the 3483 // given application. 3484 String backupAgent = sa.getNonConfigurationString( 3485 com.android.internal.R.styleable.AndroidManifestApplication_backupAgent, 3486 Configuration.NATIVE_CONFIG_VERSION); 3487 if (backupAgent != null) { 3488 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError); 3489 if (DEBUG_BACKUP) { 3490 Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName 3491 + " from " + pkgName + "+" + backupAgent); 3492 } 3493 3494 if (sa.getBoolean( 3495 com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore, 3496 true)) { 3497 ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE; 3498 } 3499 if (sa.getBoolean( 3500 com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion, 3501 false)) { 3502 ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION; 3503 } 3504 if (sa.getBoolean( 3505 com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly, 3506 false)) { 3507 ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY; 3508 } 3509 if (sa.getBoolean( 3510 com.android.internal.R.styleable.AndroidManifestApplication_backupInForeground, 3511 false)) { 3512 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; 3513 } 3514 } 3515 3516 TypedValue v = sa.peekValue( 3517 com.android.internal.R.styleable.AndroidManifestApplication_fullBackupContent); 3518 if (v != null && (ai.fullBackupContent = v.resourceId) == 0) { 3519 if (DEBUG_BACKUP) { 3520 Slog.v(TAG, "fullBackupContent specified as boolean=" + 3521 (v.data == 0 ? "false" : "true")); 3522 } 3523 // "false" => -1, "true" => 0 3524 ai.fullBackupContent = (v.data == 0 ? -1 : 0); 3525 } 3526 if (DEBUG_BACKUP) { 3527 Slog.v(TAG, "fullBackupContent=" + ai.fullBackupContent + " for " + pkgName); 3528 } 3529 } 3530 3531 ai.theme = sa.getResourceId( 3532 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); 3533 ai.descriptionRes = sa.getResourceId( 3534 com.android.internal.R.styleable.AndroidManifestApplication_description, 0); 3535 3536 if ((flags&PARSE_IS_SYSTEM) != 0) { 3537 if (sa.getBoolean( 3538 com.android.internal.R.styleable.AndroidManifestApplication_persistent, 3539 false)) { 3540 // Check if persistence is based on a feature being present 3541 final String requiredFeature = sa.getNonResourceString( 3542 com.android.internal.R.styleable. 3543 AndroidManifestApplication_persistentWhenFeatureAvailable); 3544 if (requiredFeature == null || mCallback.hasFeature(requiredFeature)) { 3545 ai.flags |= ApplicationInfo.FLAG_PERSISTENT; 3546 } 3547 } 3548 } 3549 3550 if (sa.getBoolean( 3551 com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers, 3552 false)) { 3553 owner.mRequiredForAllUsers = true; 3554 } 3555 3556 String restrictedAccountType = sa.getString(com.android.internal.R.styleable 3557 .AndroidManifestApplication_restrictedAccountType); 3558 if (restrictedAccountType != null && restrictedAccountType.length() > 0) { 3559 owner.mRestrictedAccountType = restrictedAccountType; 3560 } 3561 3562 String requiredAccountType = sa.getString(com.android.internal.R.styleable 3563 .AndroidManifestApplication_requiredAccountType); 3564 if (requiredAccountType != null && requiredAccountType.length() > 0) { 3565 owner.mRequiredAccountType = requiredAccountType; 3566 } 3567 3568 if (sa.getBoolean( 3569 com.android.internal.R.styleable.AndroidManifestApplication_debuggable, 3570 false)) { 3571 ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE; 3572 } 3573 3574 if (sa.getBoolean( 3575 com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode, 3576 false)) { 3577 ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE; 3578 } 3579 3580 owner.baseHardwareAccelerated = sa.getBoolean( 3581 com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated, 3582 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH); 3583 if (owner.baseHardwareAccelerated) { 3584 ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED; 3585 } 3586 3587 if (sa.getBoolean( 3588 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, 3589 true)) { 3590 ai.flags |= ApplicationInfo.FLAG_HAS_CODE; 3591 } 3592 3593 if (sa.getBoolean( 3594 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting, 3595 false)) { 3596 ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; 3597 } 3598 3599 if (sa.getBoolean( 3600 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData, 3601 true)) { 3602 ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; 3603 } 3604 3605 // The parent package controls installation, hence specify test only installs. 3606 if (owner.parentPackage == null) { 3607 if (sa.getBoolean( 3608 com.android.internal.R.styleable.AndroidManifestApplication_testOnly, 3609 false)) { 3610 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY; 3611 } 3612 } 3613 3614 if (sa.getBoolean( 3615 com.android.internal.R.styleable.AndroidManifestApplication_largeHeap, 3616 false)) { 3617 ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP; 3618 } 3619 3620 if (sa.getBoolean( 3621 com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic, 3622 true)) { 3623 ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC; 3624 } 3625 3626 if (sa.getBoolean( 3627 com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl, 3628 false /* default is no RTL support*/)) { 3629 ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL; 3630 } 3631 3632 if (sa.getBoolean( 3633 com.android.internal.R.styleable.AndroidManifestApplication_multiArch, 3634 false)) { 3635 ai.flags |= ApplicationInfo.FLAG_MULTIARCH; 3636 } 3637 3638 if (sa.getBoolean( 3639 com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs, 3640 true)) { 3641 ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS; 3642 } 3643 3644 if (sa.getBoolean( 3645 R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, 3646 false)) { 3647 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE; 3648 } 3649 if (sa.getBoolean( 3650 R.styleable.AndroidManifestApplication_directBootAware, 3651 false)) { 3652 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; 3653 } 3654 3655 if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) { 3656 if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity, true)) { 3657 ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE; 3658 } else { 3659 ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE; 3660 } 3661 } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) { 3662 ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 3663 } 3664 3665 ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0); 3666 3667 ai.networkSecurityConfigRes = sa.getResourceId( 3668 com.android.internal.R.styleable.AndroidManifestApplication_networkSecurityConfig, 3669 0); 3670 ai.category = sa.getInt( 3671 com.android.internal.R.styleable.AndroidManifestApplication_appCategory, 3672 ApplicationInfo.CATEGORY_UNDEFINED); 3673 3674 String str; 3675 str = sa.getNonConfigurationString( 3676 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0); 3677 ai.permission = (str != null && str.length() > 0) ? str.intern() : null; 3678 3679 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 3680 str = sa.getNonConfigurationString( 3681 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, 3682 Configuration.NATIVE_CONFIG_VERSION); 3683 } else { 3684 // Some older apps have been seen to use a resource reference 3685 // here that on older builds was ignored (with a warning). We 3686 // need to continue to do this for them so they don't break. 3687 str = sa.getNonResourceString( 3688 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity); 3689 } 3690 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName, 3691 str, outError); 3692 3693 if (outError[0] == null) { 3694 CharSequence pname; 3695 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 3696 pname = sa.getNonConfigurationString( 3697 com.android.internal.R.styleable.AndroidManifestApplication_process, 3698 Configuration.NATIVE_CONFIG_VERSION); 3699 } else { 3700 // Some older apps have been seen to use a resource reference 3701 // here that on older builds was ignored (with a warning). We 3702 // need to continue to do this for them so they don't break. 3703 pname = sa.getNonResourceString( 3704 com.android.internal.R.styleable.AndroidManifestApplication_process); 3705 } 3706 ai.processName = buildProcessName(ai.packageName, null, pname, 3707 flags, mSeparateProcesses, outError); 3708 3709 ai.enabled = sa.getBoolean( 3710 com.android.internal.R.styleable.AndroidManifestApplication_enabled, true); 3711 3712 if (sa.getBoolean( 3713 com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) { 3714 ai.flags |= ApplicationInfo.FLAG_IS_GAME; 3715 } 3716 3717 if (false) { 3718 if (sa.getBoolean( 3719 com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState, 3720 false)) { 3721 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE; 3722 3723 // A heavy-weight application can not be in a custom process. 3724 // We can do direct compare because we intern all strings. 3725 if (ai.processName != null && ai.processName != ai.packageName) { 3726 outError[0] = "cantSaveState applications can not use custom processes"; 3727 } 3728 } 3729 } 3730 } 3731 3732 ai.uiOptions = sa.getInt( 3733 com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0); 3734 3735 ai.classLoaderName = sa.getString( 3736 com.android.internal.R.styleable.AndroidManifestApplication_classLoader); 3737 if (ai.classLoaderName != null 3738 && !ClassLoaderFactory.isValidClassLoaderName(ai.classLoaderName)) { 3739 outError[0] = "Invalid class loader name: " + ai.classLoaderName; 3740 } 3741 3742 sa.recycle(); 3743 3744 if (outError[0] != null) { 3745 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3746 return false; 3747 } 3748 3749 final int innerDepth = parser.getDepth(); 3750 // IMPORTANT: These must only be cached for a single <application> to avoid components 3751 // getting added to the wrong package. 3752 final CachedComponentArgs cachedArgs = new CachedComponentArgs(); 3753 int type; 3754 3755 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 3756 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 3757 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3758 continue; 3759 } 3760 3761 String tagName = parser.getName(); 3762 if (tagName.equals("activity")) { 3763 Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false, 3764 owner.baseHardwareAccelerated); 3765 if (a == null) { 3766 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3767 return false; 3768 } 3769 3770 owner.activities.add(a); 3771 3772 } else if (tagName.equals("receiver")) { 3773 Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, 3774 true, false); 3775 if (a == null) { 3776 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3777 return false; 3778 } 3779 3780 owner.receivers.add(a); 3781 3782 } else if (tagName.equals("service")) { 3783 Service s = parseService(owner, res, parser, flags, outError, cachedArgs); 3784 if (s == null) { 3785 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3786 return false; 3787 } 3788 3789 owner.services.add(s); 3790 3791 } else if (tagName.equals("provider")) { 3792 Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs); 3793 if (p == null) { 3794 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3795 return false; 3796 } 3797 3798 owner.providers.add(p); 3799 3800 } else if (tagName.equals("activity-alias")) { 3801 Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs); 3802 if (a == null) { 3803 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3804 return false; 3805 } 3806 3807 owner.activities.add(a); 3808 3809 } else if (parser.getName().equals("meta-data")) { 3810 // note: application meta-data is stored off to the side, so it can 3811 // remain null in the primary copy (we like to avoid extra copies because 3812 // it can be large) 3813 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData, 3814 outError)) == null) { 3815 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3816 return false; 3817 } 3818 } else if (tagName.equals("static-library")) { 3819 sa = res.obtainAttributes(parser, 3820 com.android.internal.R.styleable.AndroidManifestStaticLibrary); 3821 3822 // Note: don't allow this value to be a reference to a resource 3823 // that may change. 3824 final String lname = sa.getNonResourceString( 3825 com.android.internal.R.styleable.AndroidManifestStaticLibrary_name); 3826 final int version = sa.getInt( 3827 com.android.internal.R.styleable.AndroidManifestStaticLibrary_version, -1); 3828 3829 sa.recycle(); 3830 3831 // Since the app canot run without a static lib - fail if malformed 3832 if (lname == null || version < 0) { 3833 outError[0] = "Bad static-library declaration name: " + lname 3834 + " version: " + version; 3835 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3836 XmlUtils.skipCurrentTag(parser); 3837 return false; 3838 } 3839 3840 if (owner.mSharedUserId != null) { 3841 outError[0] = "sharedUserId not allowed in static shared library"; 3842 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; 3843 XmlUtils.skipCurrentTag(parser); 3844 return false; 3845 } 3846 3847 if (owner.staticSharedLibName != null) { 3848 outError[0] = "Multiple static-shared libs for package " + pkgName; 3849 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3850 XmlUtils.skipCurrentTag(parser); 3851 return false; 3852 } 3853 3854 owner.staticSharedLibName = lname.intern(); 3855 owner.staticSharedLibVersion = version; 3856 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY; 3857 3858 XmlUtils.skipCurrentTag(parser); 3859 3860 } else if (tagName.equals("library")) { 3861 sa = res.obtainAttributes(parser, 3862 com.android.internal.R.styleable.AndroidManifestLibrary); 3863 3864 // Note: don't allow this value to be a reference to a resource 3865 // that may change. 3866 String lname = sa.getNonResourceString( 3867 com.android.internal.R.styleable.AndroidManifestLibrary_name); 3868 3869 sa.recycle(); 3870 3871 if (lname != null) { 3872 lname = lname.intern(); 3873 if (!ArrayUtils.contains(owner.libraryNames, lname)) { 3874 owner.libraryNames = ArrayUtils.add( 3875 owner.libraryNames, lname); 3876 } 3877 } 3878 3879 XmlUtils.skipCurrentTag(parser); 3880 3881 } else if (tagName.equals("uses-static-library")) { 3882 if (!parseUsesStaticLibrary(owner, res, parser, outError)) { 3883 return false; 3884 } 3885 3886 } else if (tagName.equals("uses-library")) { 3887 sa = res.obtainAttributes(parser, 3888 com.android.internal.R.styleable.AndroidManifestUsesLibrary); 3889 3890 // Note: don't allow this value to be a reference to a resource 3891 // that may change. 3892 String lname = sa.getNonResourceString( 3893 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 3894 boolean req = sa.getBoolean( 3895 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, 3896 true); 3897 3898 sa.recycle(); 3899 3900 if (lname != null) { 3901 lname = lname.intern(); 3902 if (req) { 3903 owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname); 3904 } else { 3905 owner.usesOptionalLibraries = ArrayUtils.add( 3906 owner.usesOptionalLibraries, lname); 3907 } 3908 } 3909 3910 XmlUtils.skipCurrentTag(parser); 3911 3912 } else if (tagName.equals("uses-package")) { 3913 // Dependencies for app installers; we don't currently try to 3914 // enforce this. 3915 XmlUtils.skipCurrentTag(parser); 3916 3917 } else { 3918 if (!RIGID_PARSER) { 3919 Slog.w(TAG, "Unknown element under <application>: " + tagName 3920 + " at " + mArchiveSourcePath + " " 3921 + parser.getPositionDescription()); 3922 XmlUtils.skipCurrentTag(parser); 3923 continue; 3924 } else { 3925 outError[0] = "Bad element under <application>: " + tagName; 3926 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3927 return false; 3928 } 3929 } 3930 } 3931 3932 // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after 3933 // every activity info has had a chance to set it from its attributes. 3934 setMaxAspectRatio(owner); 3935 3936 PackageBackwardCompatibility.modifySharedLibraries(owner); 3937 3938 if (hasDomainURLs(owner)) { 3939 owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS; 3940 } else { 3941 owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS; 3942 } 3943 3944 return true; 3945 } 3946 3947 /** 3948 * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI 3949 */ 3950 private static boolean hasDomainURLs(Package pkg) { 3951 if (pkg == null || pkg.activities == null) return false; 3952 final ArrayList<Activity> activities = pkg.activities; 3953 final int countActivities = activities.size(); 3954 for (int n=0; n<countActivities; n++) { 3955 Activity activity = activities.get(n); 3956 ArrayList<ActivityIntentInfo> filters = activity.intents; 3957 if (filters == null) continue; 3958 final int countFilters = filters.size(); 3959 for (int m=0; m<countFilters; m++) { 3960 ActivityIntentInfo aii = filters.get(m); 3961 if (!aii.hasAction(Intent.ACTION_VIEW)) continue; 3962 if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue; 3963 if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) || 3964 aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) { 3965 return true; 3966 } 3967 } 3968 } 3969 return false; 3970 } 3971 3972 /** 3973 * Parse the {@code application} XML tree at the current parse location in a 3974 * <em>split APK</em> manifest. 3975 * <p> 3976 * Note that split APKs have many more restrictions on what they're capable 3977 * of doing, so many valid features of a base APK have been carefully 3978 * omitted here. 3979 */ 3980 private boolean parseSplitApplication(Package owner, Resources res, XmlResourceParser parser, 3981 int flags, int splitIndex, String[] outError) 3982 throws XmlPullParserException, IOException { 3983 TypedArray sa = res.obtainAttributes(parser, 3984 com.android.internal.R.styleable.AndroidManifestApplication); 3985 3986 if (sa.getBoolean( 3987 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, true)) { 3988 owner.splitFlags[splitIndex] |= ApplicationInfo.FLAG_HAS_CODE; 3989 } 3990 3991 final String classLoaderName = sa.getString( 3992 com.android.internal.R.styleable.AndroidManifestApplication_classLoader); 3993 if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { 3994 owner.applicationInfo.splitClassLoaderNames[splitIndex] = classLoaderName; 3995 } else { 3996 outError[0] = "Invalid class loader name: " + classLoaderName; 3997 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3998 return false; 3999 } 4000 4001 final int innerDepth = parser.getDepth(); 4002 int type; 4003 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 4004 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 4005 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4006 continue; 4007 } 4008 4009 ComponentInfo parsedComponent = null; 4010 4011 // IMPORTANT: These must only be cached for a single <application> to avoid components 4012 // getting added to the wrong package. 4013 final CachedComponentArgs cachedArgs = new CachedComponentArgs(); 4014 String tagName = parser.getName(); 4015 if (tagName.equals("activity")) { 4016 Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false, 4017 owner.baseHardwareAccelerated); 4018 if (a == null) { 4019 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 4020 return false; 4021 } 4022 4023 owner.activities.add(a); 4024 parsedComponent = a.info; 4025 4026 } else if (tagName.equals("receiver")) { 4027 Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, 4028 true, false); 4029 if (a == null) { 4030 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 4031 return false; 4032 } 4033 4034 owner.receivers.add(a); 4035 parsedComponent = a.info; 4036 4037 } else if (tagName.equals("service")) { 4038 Service s = parseService(owner, res, parser, flags, outError, cachedArgs); 4039 if (s == null) { 4040 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 4041 return false; 4042 } 4043 4044 owner.services.add(s); 4045 parsedComponent = s.info; 4046 4047 } else if (tagName.equals("provider")) { 4048 Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs); 4049 if (p == null) { 4050 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 4051 return false; 4052 } 4053 4054 owner.providers.add(p); 4055 parsedComponent = p.info; 4056 4057 } else if (tagName.equals("activity-alias")) { 4058 Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs); 4059 if (a == null) { 4060 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 4061 return false; 4062 } 4063 4064 owner.activities.add(a); 4065 parsedComponent = a.info; 4066 4067 } else if (parser.getName().equals("meta-data")) { 4068 // note: application meta-data is stored off to the side, so it can 4069 // remain null in the primary copy (we like to avoid extra copies because 4070 // it can be large) 4071 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData, 4072 outError)) == null) { 4073 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 4074 return false; 4075 } 4076 4077 } else if (tagName.equals("uses-static-library")) { 4078 if (!parseUsesStaticLibrary(owner, res, parser, outError)) { 4079 return false; 4080 } 4081 4082 } else if (tagName.equals("uses-library")) { 4083 sa = res.obtainAttributes(parser, 4084 com.android.internal.R.styleable.AndroidManifestUsesLibrary); 4085 4086 // Note: don't allow this value to be a reference to a resource 4087 // that may change. 4088 String lname = sa.getNonResourceString( 4089 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 4090 boolean req = sa.getBoolean( 4091 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, 4092 true); 4093 4094 sa.recycle(); 4095 4096 if (lname != null) { 4097 lname = lname.intern(); 4098 if (req) { 4099 // Upgrade to treat as stronger constraint 4100 owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname); 4101 owner.usesOptionalLibraries = ArrayUtils.remove( 4102 owner.usesOptionalLibraries, lname); 4103 } else { 4104 // Ignore if someone already defined as required 4105 if (!ArrayUtils.contains(owner.usesLibraries, lname)) { 4106 owner.usesOptionalLibraries = ArrayUtils.add( 4107 owner.usesOptionalLibraries, lname); 4108 } 4109 } 4110 } 4111 4112 XmlUtils.skipCurrentTag(parser); 4113 4114 } else if (tagName.equals("uses-package")) { 4115 // Dependencies for app installers; we don't currently try to 4116 // enforce this. 4117 XmlUtils.skipCurrentTag(parser); 4118 4119 } else { 4120 if (!RIGID_PARSER) { 4121 Slog.w(TAG, "Unknown element under <application>: " + tagName 4122 + " at " + mArchiveSourcePath + " " 4123 + parser.getPositionDescription()); 4124 XmlUtils.skipCurrentTag(parser); 4125 continue; 4126 } else { 4127 outError[0] = "Bad element under <application>: " + tagName; 4128 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 4129 return false; 4130 } 4131 } 4132 4133 if (parsedComponent != null && parsedComponent.splitName == null) { 4134 // If the loaded component did not specify a split, inherit the split name 4135 // based on the split it is defined in. 4136 // This is used to later load the correct split when starting this 4137 // component. 4138 parsedComponent.splitName = owner.splitNames[splitIndex]; 4139 } 4140 } 4141 4142 return true; 4143 } 4144 4145 private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo, 4146 String[] outError, String tag, TypedArray sa, boolean nameRequired, 4147 int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) { 4148 // This case can only happen in unit tests where we sometimes need to create fakes 4149 // of various package parser data structures. 4150 if (sa == null) { 4151 outError[0] = tag + " does not contain any attributes"; 4152 return false; 4153 } 4154 4155 String name = sa.getNonConfigurationString(nameRes, 0); 4156 if (name == null) { 4157 if (nameRequired) { 4158 outError[0] = tag + " does not specify android:name"; 4159 return false; 4160 } 4161 } else { 4162 outInfo.name 4163 = buildClassName(owner.applicationInfo.packageName, name, outError); 4164 if (outInfo.name == null) { 4165 return false; 4166 } 4167 } 4168 4169 final boolean useRoundIcon = 4170 Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon); 4171 int roundIconVal = useRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0; 4172 if (roundIconVal != 0) { 4173 outInfo.icon = roundIconVal; 4174 outInfo.nonLocalizedLabel = null; 4175 } else { 4176 int iconVal = sa.getResourceId(iconRes, 0); 4177 if (iconVal != 0) { 4178 outInfo.icon = iconVal; 4179 outInfo.nonLocalizedLabel = null; 4180 } 4181 } 4182 4183 int logoVal = sa.getResourceId(logoRes, 0); 4184 if (logoVal != 0) { 4185 outInfo.logo = logoVal; 4186 } 4187 4188 int bannerVal = sa.getResourceId(bannerRes, 0); 4189 if (bannerVal != 0) { 4190 outInfo.banner = bannerVal; 4191 } 4192 4193 TypedValue v = sa.peekValue(labelRes); 4194 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 4195 outInfo.nonLocalizedLabel = v.coerceToString(); 4196 } 4197 4198 outInfo.packageName = owner.packageName; 4199 4200 return true; 4201 } 4202 4203 private Activity parseActivity(Package owner, Resources res, 4204 XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs, 4205 boolean receiver, boolean hardwareAccelerated) 4206 throws XmlPullParserException, IOException { 4207 TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity); 4208 4209 if (cachedArgs.mActivityArgs == null) { 4210 cachedArgs.mActivityArgs = new ParseComponentArgs(owner, outError, 4211 R.styleable.AndroidManifestActivity_name, 4212 R.styleable.AndroidManifestActivity_label, 4213 R.styleable.AndroidManifestActivity_icon, 4214 R.styleable.AndroidManifestActivity_roundIcon, 4215 R.styleable.AndroidManifestActivity_logo, 4216 R.styleable.AndroidManifestActivity_banner, 4217 mSeparateProcesses, 4218 R.styleable.AndroidManifestActivity_process, 4219 R.styleable.AndroidManifestActivity_description, 4220 R.styleable.AndroidManifestActivity_enabled); 4221 } 4222 4223 cachedArgs.mActivityArgs.tag = receiver ? "<receiver>" : "<activity>"; 4224 cachedArgs.mActivityArgs.sa = sa; 4225 cachedArgs.mActivityArgs.flags = flags; 4226 4227 Activity a = new Activity(cachedArgs.mActivityArgs, new ActivityInfo()); 4228 if (outError[0] != null) { 4229 sa.recycle(); 4230 return null; 4231 } 4232 4233 boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported); 4234 if (setExported) { 4235 a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false); 4236 } 4237 4238 a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0); 4239 4240 a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, 4241 a.info.applicationInfo.uiOptions); 4242 4243 String parentName = sa.getNonConfigurationString( 4244 R.styleable.AndroidManifestActivity_parentActivityName, 4245 Configuration.NATIVE_CONFIG_VERSION); 4246 if (parentName != null) { 4247 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 4248 if (outError[0] == null) { 4249 a.info.parentActivityName = parentClassName; 4250 } else { 4251 Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " + 4252 parentName); 4253 outError[0] = null; 4254 } 4255 } 4256 4257 String str; 4258 str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0); 4259 if (str == null) { 4260 a.info.permission = owner.applicationInfo.permission; 4261 } else { 4262 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 4263 } 4264 4265 str = sa.getNonConfigurationString( 4266 R.styleable.AndroidManifestActivity_taskAffinity, 4267 Configuration.NATIVE_CONFIG_VERSION); 4268 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName, 4269 owner.applicationInfo.taskAffinity, str, outError); 4270 4271 a.info.splitName = 4272 sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0); 4273 4274 a.info.flags = 0; 4275 if (sa.getBoolean( 4276 R.styleable.AndroidManifestActivity_multiprocess, false)) { 4277 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS; 4278 } 4279 4280 if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) { 4281 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; 4282 } 4283 4284 if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) { 4285 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; 4286 } 4287 4288 if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) { 4289 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY; 4290 } 4291 4292 if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) { 4293 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; 4294 } 4295 4296 if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) { 4297 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; 4298 } 4299 4300 if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) { 4301 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; 4302 } 4303 4304 if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting, 4305 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) { 4306 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; 4307 } 4308 4309 if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) { 4310 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; 4311 } 4312 4313 if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false) 4314 || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) { 4315 a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; 4316 } 4317 4318 if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) { 4319 a.info.flags |= ActivityInfo.FLAG_IMMERSIVE; 4320 } 4321 4322 if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) { 4323 a.info.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY; 4324 } 4325 4326 if (!receiver) { 4327 if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated, 4328 hardwareAccelerated)) { 4329 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; 4330 } 4331 4332 a.info.launchMode = sa.getInt( 4333 R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE); 4334 a.info.documentLaunchMode = sa.getInt( 4335 R.styleable.AndroidManifestActivity_documentLaunchMode, 4336 ActivityInfo.DOCUMENT_LAUNCH_NONE); 4337 a.info.maxRecents = sa.getInt( 4338 R.styleable.AndroidManifestActivity_maxRecents, 4339 ActivityManager.getDefaultAppRecentsLimitStatic()); 4340 a.info.configChanges = getActivityConfigChanges( 4341 sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0), 4342 sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0)); 4343 a.info.softInputMode = sa.getInt( 4344 R.styleable.AndroidManifestActivity_windowSoftInputMode, 0); 4345 4346 a.info.persistableMode = sa.getInteger( 4347 R.styleable.AndroidManifestActivity_persistableMode, 4348 ActivityInfo.PERSIST_ROOT_ONLY); 4349 4350 if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) { 4351 a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED; 4352 } 4353 4354 if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) { 4355 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS; 4356 } 4357 4358 if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) { 4359 a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; 4360 } 4361 4362 if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) { 4363 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING; 4364 } 4365 4366 a.info.screenOrientation = sa.getInt( 4367 R.styleable.AndroidManifestActivity_screenOrientation, 4368 SCREEN_ORIENTATION_UNSPECIFIED); 4369 4370 setActivityResizeMode(a.info, sa, owner); 4371 4372 if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, 4373 false)) { 4374 a.info.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE; 4375 } 4376 4377 if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) { 4378 a.info.flags |= FLAG_ALWAYS_FOCUSABLE; 4379 } 4380 4381 if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio) 4382 && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio) 4383 == TypedValue.TYPE_FLOAT) { 4384 a.setMaxAspectRatio(sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio, 4385 0 /*default*/)); 4386 } 4387 4388 a.info.lockTaskLaunchMode = 4389 sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0); 4390 4391 a.info.encryptionAware = a.info.directBootAware = sa.getBoolean( 4392 R.styleable.AndroidManifestActivity_directBootAware, 4393 false); 4394 4395 a.info.requestedVrComponent = 4396 sa.getString(R.styleable.AndroidManifestActivity_enableVrMode); 4397 4398 a.info.rotationAnimation = 4399 sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, ROTATION_ANIMATION_UNSPECIFIED); 4400 4401 a.info.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, 4402 ActivityInfo.COLOR_MODE_DEFAULT); 4403 4404 if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) { 4405 a.info.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED; 4406 } 4407 4408 if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) { 4409 a.info.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON; 4410 } 4411 4412 } else { 4413 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; 4414 a.info.configChanges = 0; 4415 4416 if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) { 4417 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER; 4418 if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 4419 Slog.w(TAG, "Activity exported request ignored due to singleUser: " 4420 + a.className + " at " + mArchiveSourcePath + " " 4421 + parser.getPositionDescription()); 4422 a.info.exported = false; 4423 setExported = true; 4424 } 4425 } 4426 4427 a.info.encryptionAware = a.info.directBootAware = sa.getBoolean( 4428 R.styleable.AndroidManifestActivity_directBootAware, 4429 false); 4430 } 4431 4432 if (a.info.directBootAware) { 4433 owner.applicationInfo.privateFlags |= 4434 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; 4435 } 4436 4437 // can't make this final; we may set it later via meta-data 4438 boolean visibleToEphemeral = 4439 sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false); 4440 if (visibleToEphemeral) { 4441 a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; 4442 owner.visibleToInstantApps = true; 4443 } 4444 4445 sa.recycle(); 4446 4447 if (receiver && (owner.applicationInfo.privateFlags 4448 &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { 4449 // A heavy-weight application can not have receives in its main process 4450 // We can do direct compare because we intern all strings. 4451 if (a.info.processName == owner.packageName) { 4452 outError[0] = "Heavy-weight applications can not have receivers in main process"; 4453 } 4454 } 4455 4456 if (outError[0] != null) { 4457 return null; 4458 } 4459 4460 int outerDepth = parser.getDepth(); 4461 int type; 4462 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 4463 && (type != XmlPullParser.END_TAG 4464 || parser.getDepth() > outerDepth)) { 4465 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4466 continue; 4467 } 4468 4469 if (parser.getName().equals("intent-filter")) { 4470 ActivityIntentInfo intent = new ActivityIntentInfo(a); 4471 if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/, 4472 intent, outError)) { 4473 return null; 4474 } 4475 if (intent.countActions() == 0) { 4476 Slog.w(TAG, "No actions in intent filter at " 4477 + mArchiveSourcePath + " " 4478 + parser.getPositionDescription()); 4479 } else { 4480 a.intents.add(intent); 4481 } 4482 // adjust activity flags when we implicitly expose it via a browsable filter 4483 final int visibility = visibleToEphemeral 4484 ? IntentFilter.VISIBILITY_EXPLICIT 4485 : !receiver && isImplicitlyExposedIntent(intent) 4486 ? IntentFilter.VISIBILITY_IMPLICIT 4487 : IntentFilter.VISIBILITY_NONE; 4488 intent.setVisibilityToInstantApp(visibility); 4489 if (intent.isVisibleToInstantApp()) { 4490 a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; 4491 } 4492 if (intent.isImplicitlyVisibleToInstantApp()) { 4493 a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; 4494 } 4495 if (LOG_UNSAFE_BROADCASTS && receiver 4496 && (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O)) { 4497 for (int i = 0; i < intent.countActions(); i++) { 4498 final String action = intent.getAction(i); 4499 if (action == null || !action.startsWith("android.")) continue; 4500 if (!SAFE_BROADCASTS.contains(action)) { 4501 Slog.w(TAG, "Broadcast " + action + " may never be delivered to " 4502 + owner.packageName + " as requested at: " 4503 + parser.getPositionDescription()); 4504 } 4505 } 4506 } 4507 } else if (!receiver && parser.getName().equals("preferred")) { 4508 ActivityIntentInfo intent = new ActivityIntentInfo(a); 4509 if (!parseIntent(res, parser, false /*allowGlobs*/, false /*allowAutoVerify*/, 4510 intent, outError)) { 4511 return null; 4512 } 4513 if (intent.countActions() == 0) { 4514 Slog.w(TAG, "No actions in preferred at " 4515 + mArchiveSourcePath + " " 4516 + parser.getPositionDescription()); 4517 } else { 4518 if (owner.preferredActivityFilters == null) { 4519 owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>(); 4520 } 4521 owner.preferredActivityFilters.add(intent); 4522 } 4523 // adjust activity flags when we implicitly expose it via a browsable filter 4524 final int visibility = visibleToEphemeral 4525 ? IntentFilter.VISIBILITY_EXPLICIT 4526 : !receiver && isImplicitlyExposedIntent(intent) 4527 ? IntentFilter.VISIBILITY_IMPLICIT 4528 : IntentFilter.VISIBILITY_NONE; 4529 intent.setVisibilityToInstantApp(visibility); 4530 if (intent.isVisibleToInstantApp()) { 4531 a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; 4532 } 4533 if (intent.isImplicitlyVisibleToInstantApp()) { 4534 a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; 4535 } 4536 } else if (parser.getName().equals("meta-data")) { 4537 if ((a.metaData = parseMetaData(res, parser, a.metaData, 4538 outError)) == null) { 4539 return null; 4540 } 4541 // we don't have an attribute [or it's false], but, we have meta-data 4542 if (!visibleToEphemeral && a.metaData.getBoolean(META_DATA_INSTANT_APPS)) { 4543 visibleToEphemeral = true; // set in case there are more intent filters 4544 a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; 4545 a.info.flags &= ~ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; 4546 owner.visibleToInstantApps = true; 4547 // cycle through any filters already seen 4548 for (int i = a.intents.size() - 1; i >= 0; --i) { 4549 a.intents.get(i) 4550 .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); 4551 } 4552 if (owner.preferredActivityFilters != null) { 4553 for (int i = owner.preferredActivityFilters.size() - 1; i >= 0; --i) { 4554 owner.preferredActivityFilters.get(i) 4555 .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); 4556 } 4557 } 4558 } 4559 } else if (!receiver && parser.getName().equals("layout")) { 4560 parseLayout(res, parser, a); 4561 } else { 4562 if (!RIGID_PARSER) { 4563 Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 4564 if (receiver) { 4565 Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName() 4566 + " at " + mArchiveSourcePath + " " 4567 + parser.getPositionDescription()); 4568 } else { 4569 Slog.w(TAG, "Unknown element under <activity>: " + parser.getName() 4570 + " at " + mArchiveSourcePath + " " 4571 + parser.getPositionDescription()); 4572 } 4573 XmlUtils.skipCurrentTag(parser); 4574 continue; 4575 } else { 4576 if (receiver) { 4577 outError[0] = "Bad element under <receiver>: " + parser.getName(); 4578 } else { 4579 outError[0] = "Bad element under <activity>: " + parser.getName(); 4580 } 4581 return null; 4582 } 4583 } 4584 } 4585 4586 if (!setExported) { 4587 a.info.exported = a.intents.size() > 0; 4588 } 4589 4590 return a; 4591 } 4592 4593 private void setActivityResizeMode(ActivityInfo aInfo, TypedArray sa, Package owner) { 4594 final boolean appExplicitDefault = (owner.applicationInfo.privateFlags 4595 & (PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE 4596 | PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0; 4597 4598 if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity) 4599 || appExplicitDefault) { 4600 // Activity or app explicitly set if it is resizeable or not; 4601 final boolean appResizeable = (owner.applicationInfo.privateFlags 4602 & PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0; 4603 if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, 4604 appResizeable)) { 4605 aInfo.resizeMode = RESIZE_MODE_RESIZEABLE; 4606 } else { 4607 aInfo.resizeMode = RESIZE_MODE_UNRESIZEABLE; 4608 } 4609 return; 4610 } 4611 4612 if ((owner.applicationInfo.privateFlags 4613 & PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) != 0) { 4614 // The activity or app didn't explicitly set the resizing option, however we want to 4615 // make it resize due to the sdk version it is targeting. 4616 aInfo.resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 4617 return; 4618 } 4619 4620 // resize preference isn't set and target sdk version doesn't support resizing apps by 4621 // default. For the app to be resizeable if it isn't fixed orientation or immersive. 4622 if (aInfo.isFixedOrientationPortrait()) { 4623 aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; 4624 } else if (aInfo.isFixedOrientationLandscape()) { 4625 aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; 4626 } else if (aInfo.isFixedOrientation()) { 4627 aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 4628 } else { 4629 aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; 4630 } 4631 } 4632 4633 /** 4634 * Sets every the max aspect ratio of every child activity that doesn't already have an aspect 4635 * ratio set. 4636 */ 4637 private void setMaxAspectRatio(Package owner) { 4638 // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater. 4639 // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD. 4640 float maxAspectRatio = owner.applicationInfo.targetSdkVersion < O 4641 ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0; 4642 4643 if (owner.applicationInfo.maxAspectRatio != 0) { 4644 // Use the application max aspect ration as default if set. 4645 maxAspectRatio = owner.applicationInfo.maxAspectRatio; 4646 } else if (owner.mAppMetaData != null 4647 && owner.mAppMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) { 4648 maxAspectRatio = owner.mAppMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio); 4649 } 4650 4651 for (Activity activity : owner.activities) { 4652 // If the max aspect ratio for the activity has already been set, skip. 4653 if (activity.hasMaxAspectRatio()) { 4654 continue; 4655 } 4656 4657 // By default we prefer to use a values defined on the activity directly than values 4658 // defined on the application. We do not check the styled attributes on the activity 4659 // as it would have already been set when we processed the activity. We wait to process 4660 // the meta data here since this method is called at the end of processing the 4661 // application and all meta data is guaranteed. 4662 final float activityAspectRatio = activity.metaData != null 4663 ? activity.metaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio) 4664 : maxAspectRatio; 4665 4666 activity.setMaxAspectRatio(activityAspectRatio); 4667 } 4668 } 4669 4670 /** 4671 * @param configChanges The bit mask of configChanges fetched from AndroidManifest.xml. 4672 * @param recreateOnConfigChanges The bit mask recreateOnConfigChanges fetched from 4673 * AndroidManifest.xml. 4674 * @hide Exposed for unit testing only. 4675 */ 4676 @TestApi 4677 public static int getActivityConfigChanges(int configChanges, int recreateOnConfigChanges) { 4678 return configChanges | ((~recreateOnConfigChanges) & RECREATE_ON_CONFIG_CHANGES_MASK); 4679 } 4680 4681 private void parseLayout(Resources res, AttributeSet attrs, Activity a) { 4682 TypedArray sw = res.obtainAttributes(attrs, 4683 com.android.internal.R.styleable.AndroidManifestLayout); 4684 int width = -1; 4685 float widthFraction = -1f; 4686 int height = -1; 4687 float heightFraction = -1f; 4688 final int widthType = sw.getType( 4689 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth); 4690 if (widthType == TypedValue.TYPE_FRACTION) { 4691 widthFraction = sw.getFraction( 4692 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth, 4693 1, 1, -1); 4694 } else if (widthType == TypedValue.TYPE_DIMENSION) { 4695 width = sw.getDimensionPixelSize( 4696 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth, 4697 -1); 4698 } 4699 final int heightType = sw.getType( 4700 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight); 4701 if (heightType == TypedValue.TYPE_FRACTION) { 4702 heightFraction = sw.getFraction( 4703 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight, 4704 1, 1, -1); 4705 } else if (heightType == TypedValue.TYPE_DIMENSION) { 4706 height = sw.getDimensionPixelSize( 4707 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight, 4708 -1); 4709 } 4710 int gravity = sw.getInt( 4711 com.android.internal.R.styleable.AndroidManifestLayout_gravity, 4712 Gravity.CENTER); 4713 int minWidth = sw.getDimensionPixelSize( 4714 com.android.internal.R.styleable.AndroidManifestLayout_minWidth, 4715 -1); 4716 int minHeight = sw.getDimensionPixelSize( 4717 com.android.internal.R.styleable.AndroidManifestLayout_minHeight, 4718 -1); 4719 sw.recycle(); 4720 a.info.windowLayout = new ActivityInfo.WindowLayout(width, widthFraction, 4721 height, heightFraction, gravity, minWidth, minHeight); 4722 } 4723 4724 private Activity parseActivityAlias(Package owner, Resources res, 4725 XmlResourceParser parser, int flags, String[] outError, 4726 CachedComponentArgs cachedArgs) 4727 throws XmlPullParserException, IOException { 4728 TypedArray sa = res.obtainAttributes(parser, 4729 com.android.internal.R.styleable.AndroidManifestActivityAlias); 4730 4731 String targetActivity = sa.getNonConfigurationString( 4732 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity, 4733 Configuration.NATIVE_CONFIG_VERSION); 4734 if (targetActivity == null) { 4735 outError[0] = "<activity-alias> does not specify android:targetActivity"; 4736 sa.recycle(); 4737 return null; 4738 } 4739 4740 targetActivity = buildClassName(owner.applicationInfo.packageName, 4741 targetActivity, outError); 4742 if (targetActivity == null) { 4743 sa.recycle(); 4744 return null; 4745 } 4746 4747 if (cachedArgs.mActivityAliasArgs == null) { 4748 cachedArgs.mActivityAliasArgs = new ParseComponentArgs(owner, outError, 4749 com.android.internal.R.styleable.AndroidManifestActivityAlias_name, 4750 com.android.internal.R.styleable.AndroidManifestActivityAlias_label, 4751 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, 4752 com.android.internal.R.styleable.AndroidManifestActivityAlias_roundIcon, 4753 com.android.internal.R.styleable.AndroidManifestActivityAlias_logo, 4754 com.android.internal.R.styleable.AndroidManifestActivityAlias_banner, 4755 mSeparateProcesses, 4756 0, 4757 com.android.internal.R.styleable.AndroidManifestActivityAlias_description, 4758 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled); 4759 cachedArgs.mActivityAliasArgs.tag = "<activity-alias>"; 4760 } 4761 4762 cachedArgs.mActivityAliasArgs.sa = sa; 4763 cachedArgs.mActivityAliasArgs.flags = flags; 4764 4765 Activity target = null; 4766 4767 final int NA = owner.activities.size(); 4768 for (int i=0; i<NA; i++) { 4769 Activity t = owner.activities.get(i); 4770 if (targetActivity.equals(t.info.name)) { 4771 target = t; 4772 break; 4773 } 4774 } 4775 4776 if (target == null) { 4777 outError[0] = "<activity-alias> target activity " + targetActivity 4778 + " not found in manifest"; 4779 sa.recycle(); 4780 return null; 4781 } 4782 4783 ActivityInfo info = new ActivityInfo(); 4784 info.targetActivity = targetActivity; 4785 info.configChanges = target.info.configChanges; 4786 info.flags = target.info.flags; 4787 info.icon = target.info.icon; 4788 info.logo = target.info.logo; 4789 info.banner = target.info.banner; 4790 info.labelRes = target.info.labelRes; 4791 info.nonLocalizedLabel = target.info.nonLocalizedLabel; 4792 info.launchMode = target.info.launchMode; 4793 info.lockTaskLaunchMode = target.info.lockTaskLaunchMode; 4794 info.processName = target.info.processName; 4795 if (info.descriptionRes == 0) { 4796 info.descriptionRes = target.info.descriptionRes; 4797 } 4798 info.screenOrientation = target.info.screenOrientation; 4799 info.taskAffinity = target.info.taskAffinity; 4800 info.theme = target.info.theme; 4801 info.softInputMode = target.info.softInputMode; 4802 info.uiOptions = target.info.uiOptions; 4803 info.parentActivityName = target.info.parentActivityName; 4804 info.maxRecents = target.info.maxRecents; 4805 info.windowLayout = target.info.windowLayout; 4806 info.resizeMode = target.info.resizeMode; 4807 info.maxAspectRatio = target.info.maxAspectRatio; 4808 4809 info.encryptionAware = info.directBootAware = target.info.directBootAware; 4810 4811 Activity a = new Activity(cachedArgs.mActivityAliasArgs, info); 4812 if (outError[0] != null) { 4813 sa.recycle(); 4814 return null; 4815 } 4816 4817 final boolean setExported = sa.hasValue( 4818 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported); 4819 if (setExported) { 4820 a.info.exported = sa.getBoolean( 4821 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false); 4822 } 4823 4824 String str; 4825 str = sa.getNonConfigurationString( 4826 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0); 4827 if (str != null) { 4828 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 4829 } 4830 4831 String parentName = sa.getNonConfigurationString( 4832 com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName, 4833 Configuration.NATIVE_CONFIG_VERSION); 4834 if (parentName != null) { 4835 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 4836 if (outError[0] == null) { 4837 a.info.parentActivityName = parentClassName; 4838 } else { 4839 Log.e(TAG, "Activity alias " + a.info.name + 4840 " specified invalid parentActivityName " + parentName); 4841 outError[0] = null; 4842 } 4843 } 4844 4845 // TODO add visibleToInstantApps attribute to activity alias 4846 final boolean visibleToEphemeral = 4847 ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0); 4848 4849 sa.recycle(); 4850 4851 if (outError[0] != null) { 4852 return null; 4853 } 4854 4855 int outerDepth = parser.getDepth(); 4856 int type; 4857 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 4858 && (type != XmlPullParser.END_TAG 4859 || parser.getDepth() > outerDepth)) { 4860 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4861 continue; 4862 } 4863 4864 if (parser.getName().equals("intent-filter")) { 4865 ActivityIntentInfo intent = new ActivityIntentInfo(a); 4866 if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/, 4867 intent, outError)) { 4868 return null; 4869 } 4870 if (intent.countActions() == 0) { 4871 Slog.w(TAG, "No actions in intent filter at " 4872 + mArchiveSourcePath + " " 4873 + parser.getPositionDescription()); 4874 } else { 4875 a.intents.add(intent); 4876 } 4877 // adjust activity flags when we implicitly expose it via a browsable filter 4878 final int visibility = visibleToEphemeral 4879 ? IntentFilter.VISIBILITY_EXPLICIT 4880 : isImplicitlyExposedIntent(intent) 4881 ? IntentFilter.VISIBILITY_IMPLICIT 4882 : IntentFilter.VISIBILITY_NONE; 4883 intent.setVisibilityToInstantApp(visibility); 4884 if (intent.isVisibleToInstantApp()) { 4885 a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; 4886 } 4887 if (intent.isImplicitlyVisibleToInstantApp()) { 4888 a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; 4889 } 4890 } else if (parser.getName().equals("meta-data")) { 4891 if ((a.metaData=parseMetaData(res, parser, a.metaData, 4892 outError)) == null) { 4893 return null; 4894 } 4895 } else { 4896 if (!RIGID_PARSER) { 4897 Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName() 4898 + " at " + mArchiveSourcePath + " " 4899 + parser.getPositionDescription()); 4900 XmlUtils.skipCurrentTag(parser); 4901 continue; 4902 } else { 4903 outError[0] = "Bad element under <activity-alias>: " + parser.getName(); 4904 return null; 4905 } 4906 } 4907 } 4908 4909 if (!setExported) { 4910 a.info.exported = a.intents.size() > 0; 4911 } 4912 4913 return a; 4914 } 4915 4916 private Provider parseProvider(Package owner, Resources res, 4917 XmlResourceParser parser, int flags, String[] outError, 4918 CachedComponentArgs cachedArgs) 4919 throws XmlPullParserException, IOException { 4920 TypedArray sa = res.obtainAttributes(parser, 4921 com.android.internal.R.styleable.AndroidManifestProvider); 4922 4923 if (cachedArgs.mProviderArgs == null) { 4924 cachedArgs.mProviderArgs = new ParseComponentArgs(owner, outError, 4925 com.android.internal.R.styleable.AndroidManifestProvider_name, 4926 com.android.internal.R.styleable.AndroidManifestProvider_label, 4927 com.android.internal.R.styleable.AndroidManifestProvider_icon, 4928 com.android.internal.R.styleable.AndroidManifestProvider_roundIcon, 4929 com.android.internal.R.styleable.AndroidManifestProvider_logo, 4930 com.android.internal.R.styleable.AndroidManifestProvider_banner, 4931 mSeparateProcesses, 4932 com.android.internal.R.styleable.AndroidManifestProvider_process, 4933 com.android.internal.R.styleable.AndroidManifestProvider_description, 4934 com.android.internal.R.styleable.AndroidManifestProvider_enabled); 4935 cachedArgs.mProviderArgs.tag = "<provider>"; 4936 } 4937 4938 cachedArgs.mProviderArgs.sa = sa; 4939 cachedArgs.mProviderArgs.flags = flags; 4940 4941 Provider p = new Provider(cachedArgs.mProviderArgs, new ProviderInfo()); 4942 if (outError[0] != null) { 4943 sa.recycle(); 4944 return null; 4945 } 4946 4947 boolean providerExportedDefault = false; 4948 4949 if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 4950 // For compatibility, applications targeting API level 16 or lower 4951 // should have their content providers exported by default, unless they 4952 // specify otherwise. 4953 providerExportedDefault = true; 4954 } 4955 4956 p.info.exported = sa.getBoolean( 4957 com.android.internal.R.styleable.AndroidManifestProvider_exported, 4958 providerExportedDefault); 4959 4960 String cpname = sa.getNonConfigurationString( 4961 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0); 4962 4963 p.info.isSyncable = sa.getBoolean( 4964 com.android.internal.R.styleable.AndroidManifestProvider_syncable, 4965 false); 4966 4967 String permission = sa.getNonConfigurationString( 4968 com.android.internal.R.styleable.AndroidManifestProvider_permission, 0); 4969 String str = sa.getNonConfigurationString( 4970 com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0); 4971 if (str == null) { 4972 str = permission; 4973 } 4974 if (str == null) { 4975 p.info.readPermission = owner.applicationInfo.permission; 4976 } else { 4977 p.info.readPermission = 4978 str.length() > 0 ? str.toString().intern() : null; 4979 } 4980 str = sa.getNonConfigurationString( 4981 com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0); 4982 if (str == null) { 4983 str = permission; 4984 } 4985 if (str == null) { 4986 p.info.writePermission = owner.applicationInfo.permission; 4987 } else { 4988 p.info.writePermission = 4989 str.length() > 0 ? str.toString().intern() : null; 4990 } 4991 4992 p.info.grantUriPermissions = sa.getBoolean( 4993 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions, 4994 false); 4995 4996 p.info.multiprocess = sa.getBoolean( 4997 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess, 4998 false); 4999 5000 p.info.initOrder = sa.getInt( 5001 com.android.internal.R.styleable.AndroidManifestProvider_initOrder, 5002 0); 5003 5004 p.info.splitName = 5005 sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0); 5006 5007 p.info.flags = 0; 5008 5009 if (sa.getBoolean( 5010 com.android.internal.R.styleable.AndroidManifestProvider_singleUser, 5011 false)) { 5012 p.info.flags |= ProviderInfo.FLAG_SINGLE_USER; 5013 if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 5014 Slog.w(TAG, "Provider exported request ignored due to singleUser: " 5015 + p.className + " at " + mArchiveSourcePath + " " 5016 + parser.getPositionDescription()); 5017 p.info.exported = false; 5018 } 5019 } 5020 5021 p.info.encryptionAware = p.info.directBootAware = sa.getBoolean( 5022 R.styleable.AndroidManifestProvider_directBootAware, 5023 false); 5024 if (p.info.directBootAware) { 5025 owner.applicationInfo.privateFlags |= 5026 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; 5027 } 5028 5029 final boolean visibleToEphemeral = 5030 sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false); 5031 if (visibleToEphemeral) { 5032 p.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP; 5033 owner.visibleToInstantApps = true; 5034 } 5035 5036 sa.recycle(); 5037 5038 if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) 5039 != 0) { 5040 // A heavy-weight application can not have providers in its main process 5041 // We can do direct compare because we intern all strings. 5042 if (p.info.processName == owner.packageName) { 5043 outError[0] = "Heavy-weight applications can not have providers in main process"; 5044 return null; 5045 } 5046 } 5047 5048 if (cpname == null) { 5049 outError[0] = "<provider> does not include authorities attribute"; 5050 return null; 5051 } 5052 if (cpname.length() <= 0) { 5053 outError[0] = "<provider> has empty authorities attribute"; 5054 return null; 5055 } 5056 p.info.authority = cpname.intern(); 5057 5058 if (!parseProviderTags( 5059 res, parser, visibleToEphemeral, owner, p, outError)) { 5060 return null; 5061 } 5062 5063 return p; 5064 } 5065 5066 private boolean parseProviderTags(Resources res, XmlResourceParser parser, 5067 boolean visibleToEphemeral, Package owner, Provider outInfo, String[] outError) 5068 throws XmlPullParserException, IOException { 5069 int outerDepth = parser.getDepth(); 5070 int type; 5071 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 5072 && (type != XmlPullParser.END_TAG 5073 || parser.getDepth() > outerDepth)) { 5074 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 5075 continue; 5076 } 5077 5078 if (parser.getName().equals("intent-filter")) { 5079 ProviderIntentInfo intent = new ProviderIntentInfo(outInfo); 5080 if (!parseIntent(res, parser, true /*allowGlobs*/, false /*allowAutoVerify*/, 5081 intent, outError)) { 5082 return false; 5083 } 5084 if (visibleToEphemeral) { 5085 intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); 5086 outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP; 5087 } 5088 outInfo.intents.add(intent); 5089 5090 } else if (parser.getName().equals("meta-data")) { 5091 if ((outInfo.metaData=parseMetaData(res, parser, 5092 outInfo.metaData, outError)) == null) { 5093 return false; 5094 } 5095 // we don't have an attribute [or it's false], but, we have meta-data 5096 if (!visibleToEphemeral && outInfo.metaData.getBoolean(META_DATA_INSTANT_APPS)) { 5097 visibleToEphemeral = true; // set in case there are more intent filters 5098 outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP; 5099 owner.visibleToInstantApps = true; 5100 // cycle through any filters already seen 5101 for (int i = outInfo.intents.size() - 1; i >= 0; --i) { 5102 outInfo.intents.get(i) 5103 .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); 5104 } 5105 } 5106 5107 } else if (parser.getName().equals("grant-uri-permission")) { 5108 TypedArray sa = res.obtainAttributes(parser, 5109 com.android.internal.R.styleable.AndroidManifestGrantUriPermission); 5110 5111 PatternMatcher pa = null; 5112 5113 String str = sa.getNonConfigurationString( 5114 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0); 5115 if (str != null) { 5116 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); 5117 } 5118 5119 str = sa.getNonConfigurationString( 5120 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); 5121 if (str != null) { 5122 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); 5123 } 5124 5125 str = sa.getNonConfigurationString( 5126 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); 5127 if (str != null) { 5128 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 5129 } 5130 5131 sa.recycle(); 5132 5133 if (pa != null) { 5134 if (outInfo.info.uriPermissionPatterns == null) { 5135 outInfo.info.uriPermissionPatterns = new PatternMatcher[1]; 5136 outInfo.info.uriPermissionPatterns[0] = pa; 5137 } else { 5138 final int N = outInfo.info.uriPermissionPatterns.length; 5139 PatternMatcher[] newp = new PatternMatcher[N+1]; 5140 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N); 5141 newp[N] = pa; 5142 outInfo.info.uriPermissionPatterns = newp; 5143 } 5144 outInfo.info.grantUriPermissions = true; 5145 } else { 5146 if (!RIGID_PARSER) { 5147 Slog.w(TAG, "Unknown element under <path-permission>: " 5148 + parser.getName() + " at " + mArchiveSourcePath + " " 5149 + parser.getPositionDescription()); 5150 XmlUtils.skipCurrentTag(parser); 5151 continue; 5152 } else { 5153 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 5154 return false; 5155 } 5156 } 5157 XmlUtils.skipCurrentTag(parser); 5158 5159 } else if (parser.getName().equals("path-permission")) { 5160 TypedArray sa = res.obtainAttributes(parser, 5161 com.android.internal.R.styleable.AndroidManifestPathPermission); 5162 5163 PathPermission pa = null; 5164 5165 String permission = sa.getNonConfigurationString( 5166 com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0); 5167 String readPermission = sa.getNonConfigurationString( 5168 com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0); 5169 if (readPermission == null) { 5170 readPermission = permission; 5171 } 5172 String writePermission = sa.getNonConfigurationString( 5173 com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0); 5174 if (writePermission == null) { 5175 writePermission = permission; 5176 } 5177 5178 boolean havePerm = false; 5179 if (readPermission != null) { 5180 readPermission = readPermission.intern(); 5181 havePerm = true; 5182 } 5183 if (writePermission != null) { 5184 writePermission = writePermission.intern(); 5185 havePerm = true; 5186 } 5187 5188 if (!havePerm) { 5189 if (!RIGID_PARSER) { 5190 Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: " 5191 + parser.getName() + " at " + mArchiveSourcePath + " " 5192 + parser.getPositionDescription()); 5193 XmlUtils.skipCurrentTag(parser); 5194 continue; 5195 } else { 5196 outError[0] = "No readPermission or writePermssion for <path-permission>"; 5197 return false; 5198 } 5199 } 5200 5201 String path = sa.getNonConfigurationString( 5202 com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0); 5203 if (path != null) { 5204 pa = new PathPermission(path, 5205 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission); 5206 } 5207 5208 path = sa.getNonConfigurationString( 5209 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0); 5210 if (path != null) { 5211 pa = new PathPermission(path, 5212 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission); 5213 } 5214 5215 path = sa.getNonConfigurationString( 5216 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0); 5217 if (path != null) { 5218 pa = new PathPermission(path, 5219 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission); 5220 } 5221 5222 path = sa.getNonConfigurationString( 5223 com.android.internal.R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0); 5224 if (path != null) { 5225 pa = new PathPermission(path, 5226 PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission); 5227 } 5228 5229 sa.recycle(); 5230 5231 if (pa != null) { 5232 if (outInfo.info.pathPermissions == null) { 5233 outInfo.info.pathPermissions = new PathPermission[1]; 5234 outInfo.info.pathPermissions[0] = pa; 5235 } else { 5236 final int N = outInfo.info.pathPermissions.length; 5237 PathPermission[] newp = new PathPermission[N+1]; 5238 System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N); 5239 newp[N] = pa; 5240 outInfo.info.pathPermissions = newp; 5241 } 5242 } else { 5243 if (!RIGID_PARSER) { 5244 Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: " 5245 + parser.getName() + " at " + mArchiveSourcePath + " " 5246 + parser.getPositionDescription()); 5247 XmlUtils.skipCurrentTag(parser); 5248 continue; 5249 } 5250 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 5251 return false; 5252 } 5253 XmlUtils.skipCurrentTag(parser); 5254 5255 } else { 5256 if (!RIGID_PARSER) { 5257 Slog.w(TAG, "Unknown element under <provider>: " 5258 + parser.getName() + " at " + mArchiveSourcePath + " " 5259 + parser.getPositionDescription()); 5260 XmlUtils.skipCurrentTag(parser); 5261 continue; 5262 } else { 5263 outError[0] = "Bad element under <provider>: " + parser.getName(); 5264 return false; 5265 } 5266 } 5267 } 5268 return true; 5269 } 5270 5271 private Service parseService(Package owner, Resources res, 5272 XmlResourceParser parser, int flags, String[] outError, 5273 CachedComponentArgs cachedArgs) 5274 throws XmlPullParserException, IOException { 5275 TypedArray sa = res.obtainAttributes(parser, 5276 com.android.internal.R.styleable.AndroidManifestService); 5277 5278 if (cachedArgs.mServiceArgs == null) { 5279 cachedArgs.mServiceArgs = new ParseComponentArgs(owner, outError, 5280 com.android.internal.R.styleable.AndroidManifestService_name, 5281 com.android.internal.R.styleable.AndroidManifestService_label, 5282 com.android.internal.R.styleable.AndroidManifestService_icon, 5283 com.android.internal.R.styleable.AndroidManifestService_roundIcon, 5284 com.android.internal.R.styleable.AndroidManifestService_logo, 5285 com.android.internal.R.styleable.AndroidManifestService_banner, 5286 mSeparateProcesses, 5287 com.android.internal.R.styleable.AndroidManifestService_process, 5288 com.android.internal.R.styleable.AndroidManifestService_description, 5289 com.android.internal.R.styleable.AndroidManifestService_enabled); 5290 cachedArgs.mServiceArgs.tag = "<service>"; 5291 } 5292 5293 cachedArgs.mServiceArgs.sa = sa; 5294 cachedArgs.mServiceArgs.flags = flags; 5295 5296 Service s = new Service(cachedArgs.mServiceArgs, new ServiceInfo()); 5297 if (outError[0] != null) { 5298 sa.recycle(); 5299 return null; 5300 } 5301 5302 boolean setExported = sa.hasValue( 5303 com.android.internal.R.styleable.AndroidManifestService_exported); 5304 if (setExported) { 5305 s.info.exported = sa.getBoolean( 5306 com.android.internal.R.styleable.AndroidManifestService_exported, false); 5307 } 5308 5309 String str = sa.getNonConfigurationString( 5310 com.android.internal.R.styleable.AndroidManifestService_permission, 0); 5311 if (str == null) { 5312 s.info.permission = owner.applicationInfo.permission; 5313 } else { 5314 s.info.permission = str.length() > 0 ? str.toString().intern() : null; 5315 } 5316 5317 s.info.splitName = 5318 sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0); 5319 5320 s.info.flags = 0; 5321 if (sa.getBoolean( 5322 com.android.internal.R.styleable.AndroidManifestService_stopWithTask, 5323 false)) { 5324 s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK; 5325 } 5326 if (sa.getBoolean( 5327 com.android.internal.R.styleable.AndroidManifestService_isolatedProcess, 5328 false)) { 5329 s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS; 5330 } 5331 if (sa.getBoolean( 5332 com.android.internal.R.styleable.AndroidManifestService_externalService, 5333 false)) { 5334 s.info.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE; 5335 } 5336 if (sa.getBoolean( 5337 com.android.internal.R.styleable.AndroidManifestService_singleUser, 5338 false)) { 5339 s.info.flags |= ServiceInfo.FLAG_SINGLE_USER; 5340 if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 5341 Slog.w(TAG, "Service exported request ignored due to singleUser: " 5342 + s.className + " at " + mArchiveSourcePath + " " 5343 + parser.getPositionDescription()); 5344 s.info.exported = false; 5345 setExported = true; 5346 } 5347 } 5348 5349 s.info.encryptionAware = s.info.directBootAware = sa.getBoolean( 5350 R.styleable.AndroidManifestService_directBootAware, 5351 false); 5352 if (s.info.directBootAware) { 5353 owner.applicationInfo.privateFlags |= 5354 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; 5355 } 5356 5357 boolean visibleToEphemeral = 5358 sa.getBoolean(R.styleable.AndroidManifestService_visibleToInstantApps, false); 5359 if (visibleToEphemeral) { 5360 s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP; 5361 owner.visibleToInstantApps = true; 5362 } 5363 5364 sa.recycle(); 5365 5366 if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) 5367 != 0) { 5368 // A heavy-weight application can not have services in its main process 5369 // We can do direct compare because we intern all strings. 5370 if (s.info.processName == owner.packageName) { 5371 outError[0] = "Heavy-weight applications can not have services in main process"; 5372 return null; 5373 } 5374 } 5375 5376 int outerDepth = parser.getDepth(); 5377 int type; 5378 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 5379 && (type != XmlPullParser.END_TAG 5380 || parser.getDepth() > outerDepth)) { 5381 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 5382 continue; 5383 } 5384 5385 if (parser.getName().equals("intent-filter")) { 5386 ServiceIntentInfo intent = new ServiceIntentInfo(s); 5387 if (!parseIntent(res, parser, true /*allowGlobs*/, false /*allowAutoVerify*/, 5388 intent, outError)) { 5389 return null; 5390 } 5391 if (visibleToEphemeral) { 5392 intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); 5393 s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP; 5394 } 5395 s.intents.add(intent); 5396 } else if (parser.getName().equals("meta-data")) { 5397 if ((s.metaData=parseMetaData(res, parser, s.metaData, 5398 outError)) == null) { 5399 return null; 5400 } 5401 // we don't have an attribute [or it's false], but, we have meta-data 5402 if (!visibleToEphemeral && s.metaData.getBoolean(META_DATA_INSTANT_APPS)) { 5403 visibleToEphemeral = true; // set in case there are more intent filters 5404 s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP; 5405 owner.visibleToInstantApps = true; 5406 // cycle through any filters already seen 5407 for (int i = s.intents.size() - 1; i >= 0; --i) { 5408 s.intents.get(i) 5409 .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); 5410 } 5411 } 5412 } else { 5413 if (!RIGID_PARSER) { 5414 Slog.w(TAG, "Unknown element under <service>: " 5415 + parser.getName() + " at " + mArchiveSourcePath + " " 5416 + parser.getPositionDescription()); 5417 XmlUtils.skipCurrentTag(parser); 5418 continue; 5419 } else { 5420 outError[0] = "Bad element under <service>: " + parser.getName(); 5421 return null; 5422 } 5423 } 5424 } 5425 5426 if (!setExported) { 5427 s.info.exported = s.intents.size() > 0; 5428 } 5429 5430 return s; 5431 } 5432 5433 private boolean isImplicitlyExposedIntent(IntentInfo intent) { 5434 return intent.hasCategory(Intent.CATEGORY_BROWSABLE) 5435 || intent.hasAction(Intent.ACTION_SEND) 5436 || intent.hasAction(Intent.ACTION_SENDTO) 5437 || intent.hasAction(Intent.ACTION_SEND_MULTIPLE); 5438 } 5439 5440 private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag, 5441 Component<?> outInfo, String[] outError) throws XmlPullParserException, IOException { 5442 int outerDepth = parser.getDepth(); 5443 int type; 5444 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 5445 && (type != XmlPullParser.END_TAG 5446 || parser.getDepth() > outerDepth)) { 5447 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 5448 continue; 5449 } 5450 5451 if (parser.getName().equals("meta-data")) { 5452 if ((outInfo.metaData=parseMetaData(res, parser, 5453 outInfo.metaData, outError)) == null) { 5454 return false; 5455 } 5456 } else { 5457 if (!RIGID_PARSER) { 5458 Slog.w(TAG, "Unknown element under " + tag + ": " 5459 + parser.getName() + " at " + mArchiveSourcePath + " " 5460 + parser.getPositionDescription()); 5461 XmlUtils.skipCurrentTag(parser); 5462 continue; 5463 } else { 5464 outError[0] = "Bad element under " + tag + ": " + parser.getName(); 5465 return false; 5466 } 5467 } 5468 } 5469 return true; 5470 } 5471 5472 private Bundle parseMetaData(Resources res, 5473 XmlResourceParser parser, Bundle data, String[] outError) 5474 throws XmlPullParserException, IOException { 5475 5476 TypedArray sa = res.obtainAttributes(parser, 5477 com.android.internal.R.styleable.AndroidManifestMetaData); 5478 5479 if (data == null) { 5480 data = new Bundle(); 5481 } 5482 5483 String name = sa.getNonConfigurationString( 5484 com.android.internal.R.styleable.AndroidManifestMetaData_name, 0); 5485 if (name == null) { 5486 outError[0] = "<meta-data> requires an android:name attribute"; 5487 sa.recycle(); 5488 return null; 5489 } 5490 5491 name = name.intern(); 5492 5493 TypedValue v = sa.peekValue( 5494 com.android.internal.R.styleable.AndroidManifestMetaData_resource); 5495 if (v != null && v.resourceId != 0) { 5496 //Slog.i(TAG, "Meta data ref " + name + ": " + v); 5497 data.putInt(name, v.resourceId); 5498 } else { 5499 v = sa.peekValue( 5500 com.android.internal.R.styleable.AndroidManifestMetaData_value); 5501 //Slog.i(TAG, "Meta data " + name + ": " + v); 5502 if (v != null) { 5503 if (v.type == TypedValue.TYPE_STRING) { 5504 CharSequence cs = v.coerceToString(); 5505 data.putString(name, cs != null ? cs.toString() : null); 5506 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { 5507 data.putBoolean(name, v.data != 0); 5508 } else if (v.type >= TypedValue.TYPE_FIRST_INT 5509 && v.type <= TypedValue.TYPE_LAST_INT) { 5510 data.putInt(name, v.data); 5511 } else if (v.type == TypedValue.TYPE_FLOAT) { 5512 data.putFloat(name, v.getFloat()); 5513 } else { 5514 if (!RIGID_PARSER) { 5515 Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: " 5516 + parser.getName() + " at " + mArchiveSourcePath + " " 5517 + parser.getPositionDescription()); 5518 } else { 5519 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types"; 5520 data = null; 5521 } 5522 } 5523 } else { 5524 outError[0] = "<meta-data> requires an android:value or android:resource attribute"; 5525 data = null; 5526 } 5527 } 5528 5529 sa.recycle(); 5530 5531 XmlUtils.skipCurrentTag(parser); 5532 5533 return data; 5534 } 5535 5536 private static VerifierInfo parseVerifier(AttributeSet attrs) { 5537 String packageName = null; 5538 String encodedPublicKey = null; 5539 5540 final int attrCount = attrs.getAttributeCount(); 5541 for (int i = 0; i < attrCount; i++) { 5542 final int attrResId = attrs.getAttributeNameResource(i); 5543 switch (attrResId) { 5544 case com.android.internal.R.attr.name: 5545 packageName = attrs.getAttributeValue(i); 5546 break; 5547 5548 case com.android.internal.R.attr.publicKey: 5549 encodedPublicKey = attrs.getAttributeValue(i); 5550 break; 5551 } 5552 } 5553 5554 if (packageName == null || packageName.length() == 0) { 5555 Slog.i(TAG, "verifier package name was null; skipping"); 5556 return null; 5557 } 5558 5559 final PublicKey publicKey = parsePublicKey(encodedPublicKey); 5560 if (publicKey == null) { 5561 Slog.i(TAG, "Unable to parse verifier public key for " + packageName); 5562 return null; 5563 } 5564 5565 return new VerifierInfo(packageName, publicKey); 5566 } 5567 5568 public static final PublicKey parsePublicKey(final String encodedPublicKey) { 5569 if (encodedPublicKey == null) { 5570 Slog.w(TAG, "Could not parse null public key"); 5571 return null; 5572 } 5573 5574 EncodedKeySpec keySpec; 5575 try { 5576 final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT); 5577 keySpec = new X509EncodedKeySpec(encoded); 5578 } catch (IllegalArgumentException e) { 5579 Slog.w(TAG, "Could not parse verifier public key; invalid Base64"); 5580 return null; 5581 } 5582 5583 /* First try the key as an RSA key. */ 5584 try { 5585 final KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 5586 return keyFactory.generatePublic(keySpec); 5587 } catch (NoSuchAlgorithmException e) { 5588 Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build"); 5589 } catch (InvalidKeySpecException e) { 5590 // Not a RSA public key. 5591 } 5592 5593 /* Now try it as a ECDSA key. */ 5594 try { 5595 final KeyFactory keyFactory = KeyFactory.getInstance("EC"); 5596 return keyFactory.generatePublic(keySpec); 5597 } catch (NoSuchAlgorithmException e) { 5598 Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build"); 5599 } catch (InvalidKeySpecException e) { 5600 // Not a ECDSA public key. 5601 } 5602 5603 /* Now try it as a DSA key. */ 5604 try { 5605 final KeyFactory keyFactory = KeyFactory.getInstance("DSA"); 5606 return keyFactory.generatePublic(keySpec); 5607 } catch (NoSuchAlgorithmException e) { 5608 Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build"); 5609 } catch (InvalidKeySpecException e) { 5610 // Not a DSA public key. 5611 } 5612 5613 /* Not a supported key type */ 5614 return null; 5615 } 5616 5617 private static final String ANDROID_RESOURCES 5618 = "http://schemas.android.com/apk/res/android"; 5619 5620 private boolean parseIntent(Resources res, XmlResourceParser parser, boolean allowGlobs, 5621 boolean allowAutoVerify, IntentInfo outInfo, String[] outError) 5622 throws XmlPullParserException, IOException { 5623 5624 TypedArray sa = res.obtainAttributes(parser, 5625 com.android.internal.R.styleable.AndroidManifestIntentFilter); 5626 5627 int priority = sa.getInt( 5628 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0); 5629 outInfo.setPriority(priority); 5630 5631 TypedValue v = sa.peekValue( 5632 com.android.internal.R.styleable.AndroidManifestIntentFilter_label); 5633 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 5634 outInfo.nonLocalizedLabel = v.coerceToString(); 5635 } 5636 5637 final boolean useRoundIcon = 5638 Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon); 5639 int roundIconVal = useRoundIcon ? sa.getResourceId( 5640 com.android.internal.R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0; 5641 if (roundIconVal != 0) { 5642 outInfo.icon = roundIconVal; 5643 } else { 5644 outInfo.icon = sa.getResourceId( 5645 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0); 5646 } 5647 5648 outInfo.logo = sa.getResourceId( 5649 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0); 5650 5651 outInfo.banner = sa.getResourceId( 5652 com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0); 5653 5654 if (allowAutoVerify) { 5655 outInfo.setAutoVerify(sa.getBoolean( 5656 com.android.internal.R.styleable.AndroidManifestIntentFilter_autoVerify, 5657 false)); 5658 } 5659 5660 sa.recycle(); 5661 5662 int outerDepth = parser.getDepth(); 5663 int type; 5664 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 5665 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 5666 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 5667 continue; 5668 } 5669 5670 String nodeName = parser.getName(); 5671 if (nodeName.equals("action")) { 5672 String value = parser.getAttributeValue( 5673 ANDROID_RESOURCES, "name"); 5674 if (value == null || value == "") { 5675 outError[0] = "No value supplied for <android:name>"; 5676 return false; 5677 } 5678 XmlUtils.skipCurrentTag(parser); 5679 5680 outInfo.addAction(value); 5681 } else if (nodeName.equals("category")) { 5682 String value = parser.getAttributeValue( 5683 ANDROID_RESOURCES, "name"); 5684 if (value == null || value == "") { 5685 outError[0] = "No value supplied for <android:name>"; 5686 return false; 5687 } 5688 XmlUtils.skipCurrentTag(parser); 5689 5690 outInfo.addCategory(value); 5691 5692 } else if (nodeName.equals("data")) { 5693 sa = res.obtainAttributes(parser, 5694 com.android.internal.R.styleable.AndroidManifestData); 5695 5696 String str = sa.getNonConfigurationString( 5697 com.android.internal.R.styleable.AndroidManifestData_mimeType, 0); 5698 if (str != null) { 5699 try { 5700 outInfo.addDataType(str); 5701 } catch (IntentFilter.MalformedMimeTypeException e) { 5702 outError[0] = e.toString(); 5703 sa.recycle(); 5704 return false; 5705 } 5706 } 5707 5708 str = sa.getNonConfigurationString( 5709 com.android.internal.R.styleable.AndroidManifestData_scheme, 0); 5710 if (str != null) { 5711 outInfo.addDataScheme(str); 5712 } 5713 5714 str = sa.getNonConfigurationString( 5715 com.android.internal.R.styleable.AndroidManifestData_ssp, 0); 5716 if (str != null) { 5717 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL); 5718 } 5719 5720 str = sa.getNonConfigurationString( 5721 com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0); 5722 if (str != null) { 5723 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX); 5724 } 5725 5726 str = sa.getNonConfigurationString( 5727 com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0); 5728 if (str != null) { 5729 if (!allowGlobs) { 5730 outError[0] = "sspPattern not allowed here; ssp must be literal"; 5731 return false; 5732 } 5733 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 5734 } 5735 5736 String host = sa.getNonConfigurationString( 5737 com.android.internal.R.styleable.AndroidManifestData_host, 0); 5738 String port = sa.getNonConfigurationString( 5739 com.android.internal.R.styleable.AndroidManifestData_port, 0); 5740 if (host != null) { 5741 outInfo.addDataAuthority(host, port); 5742 } 5743 5744 str = sa.getNonConfigurationString( 5745 com.android.internal.R.styleable.AndroidManifestData_path, 0); 5746 if (str != null) { 5747 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); 5748 } 5749 5750 str = sa.getNonConfigurationString( 5751 com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0); 5752 if (str != null) { 5753 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); 5754 } 5755 5756 str = sa.getNonConfigurationString( 5757 com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0); 5758 if (str != null) { 5759 if (!allowGlobs) { 5760 outError[0] = "pathPattern not allowed here; path must be literal"; 5761 return false; 5762 } 5763 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 5764 } 5765 5766 str = sa.getNonConfigurationString( 5767 com.android.internal.R.styleable.AndroidManifestData_pathAdvancedPattern, 0); 5768 if (str != null) { 5769 if (!allowGlobs) { 5770 outError[0] = "pathAdvancedPattern not allowed here; path must be literal"; 5771 return false; 5772 } 5773 outInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB); 5774 } 5775 5776 sa.recycle(); 5777 XmlUtils.skipCurrentTag(parser); 5778 } else if (!RIGID_PARSER) { 5779 Slog.w(TAG, "Unknown element under <intent-filter>: " 5780 + parser.getName() + " at " + mArchiveSourcePath + " " 5781 + parser.getPositionDescription()); 5782 XmlUtils.skipCurrentTag(parser); 5783 } else { 5784 outError[0] = "Bad element under <intent-filter>: " + parser.getName(); 5785 return false; 5786 } 5787 } 5788 5789 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT); 5790 5791 if (DEBUG_PARSER) { 5792 final StringBuilder cats = new StringBuilder("Intent d="); 5793 cats.append(outInfo.hasDefault); 5794 cats.append(", cat="); 5795 5796 final Iterator<String> it = outInfo.categoriesIterator(); 5797 if (it != null) { 5798 while (it.hasNext()) { 5799 cats.append(' '); 5800 cats.append(it.next()); 5801 } 5802 } 5803 Slog.d(TAG, cats.toString()); 5804 } 5805 5806 return true; 5807 } 5808 5809 /** 5810 * Representation of a full package parsed from APK files on disk. A package 5811 * consists of a single base APK, and zero or more split APKs. 5812 */ 5813 public final static class Package implements Parcelable { 5814 5815 public String packageName; 5816 5817 // The package name declared in the manifest as the package can be 5818 // renamed, for example static shared libs use synthetic package names. 5819 public String manifestPackageName; 5820 5821 /** Names of any split APKs, ordered by parsed splitName */ 5822 public String[] splitNames; 5823 5824 // TODO: work towards making these paths invariant 5825 5826 public String volumeUuid; 5827 5828 /** 5829 * Path where this package was found on disk. For monolithic packages 5830 * this is path to single base APK file; for cluster packages this is 5831 * path to the cluster directory. 5832 */ 5833 public String codePath; 5834 5835 /** Path of base APK */ 5836 public String baseCodePath; 5837 /** Paths of any split APKs, ordered by parsed splitName */ 5838 public String[] splitCodePaths; 5839 5840 /** Revision code of base APK */ 5841 public int baseRevisionCode; 5842 /** Revision codes of any split APKs, ordered by parsed splitName */ 5843 public int[] splitRevisionCodes; 5844 5845 /** Flags of any split APKs; ordered by parsed splitName */ 5846 public int[] splitFlags; 5847 5848 /** 5849 * Private flags of any split APKs; ordered by parsed splitName. 5850 * 5851 * {@hide} 5852 */ 5853 public int[] splitPrivateFlags; 5854 5855 public boolean baseHardwareAccelerated; 5856 5857 // For now we only support one application per package. 5858 public ApplicationInfo applicationInfo = new ApplicationInfo(); 5859 5860 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0); 5861 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0); 5862 public final ArrayList<Activity> activities = new ArrayList<Activity>(0); 5863 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0); 5864 public final ArrayList<Provider> providers = new ArrayList<Provider>(0); 5865 public final ArrayList<Service> services = new ArrayList<Service>(0); 5866 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0); 5867 5868 public final ArrayList<String> requestedPermissions = new ArrayList<String>(); 5869 5870 public ArrayList<String> protectedBroadcasts; 5871 5872 public Package parentPackage; 5873 public ArrayList<Package> childPackages; 5874 5875 public String staticSharedLibName = null; 5876 public int staticSharedLibVersion = 0; 5877 public ArrayList<String> libraryNames = null; 5878 public ArrayList<String> usesLibraries = null; 5879 public ArrayList<String> usesStaticLibraries = null; 5880 public int[] usesStaticLibrariesVersions = null; 5881 public String[][] usesStaticLibrariesCertDigests = null; 5882 public ArrayList<String> usesOptionalLibraries = null; 5883 public String[] usesLibraryFiles = null; 5884 5885 public ArrayList<ActivityIntentInfo> preferredActivityFilters = null; 5886 5887 public ArrayList<String> mOriginalPackages = null; 5888 public String mRealPackage = null; 5889 public ArrayList<String> mAdoptPermissions = null; 5890 5891 // We store the application meta-data independently to avoid multiple unwanted references 5892 public Bundle mAppMetaData = null; 5893 5894 // The version code declared for this package. 5895 public int mVersionCode; 5896 5897 // The version name declared for this package. 5898 public String mVersionName; 5899 5900 // The shared user id that this package wants to use. 5901 public String mSharedUserId; 5902 5903 // The shared user label that this package wants to use. 5904 public int mSharedUserLabel; 5905 5906 // Signatures that were read from the package. 5907 public Signature[] mSignatures; 5908 public Certificate[][] mCertificates; 5909 5910 // For use by package manager service for quick lookup of 5911 // preferred up order. 5912 public int mPreferredOrder = 0; 5913 5914 // For use by package manager to keep track of when a package was last used. 5915 public long[] mLastPackageUsageTimeInMills = 5916 new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT]; 5917 5918 // // User set enabled state. 5919 // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; 5920 // 5921 // // Whether the package has been stopped. 5922 // public boolean mSetStopped = false; 5923 5924 // Additional data supplied by callers. 5925 public Object mExtras; 5926 5927 // Applications hardware preferences 5928 public ArrayList<ConfigurationInfo> configPreferences = null; 5929 5930 // Applications requested features 5931 public ArrayList<FeatureInfo> reqFeatures = null; 5932 5933 // Applications requested feature groups 5934 public ArrayList<FeatureGroupInfo> featureGroups = null; 5935 5936 public int installLocation; 5937 5938 public boolean coreApp; 5939 5940 /* An app that's required for all users and cannot be uninstalled for a user */ 5941 public boolean mRequiredForAllUsers; 5942 5943 /* The restricted account authenticator type that is used by this application */ 5944 public String mRestrictedAccountType; 5945 5946 /* The required account type without which this application will not function */ 5947 public String mRequiredAccountType; 5948 5949 public String mOverlayTarget; 5950 public int mOverlayPriority; 5951 public boolean mIsStaticOverlay; 5952 public boolean mTrustedOverlay; 5953 5954 /** 5955 * Data used to feed the KeySetManagerService 5956 */ 5957 public ArraySet<PublicKey> mSigningKeys; 5958 public ArraySet<String> mUpgradeKeySets; 5959 public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping; 5960 5961 /** 5962 * The install time abi override for this package, if any. 5963 * 5964 * TODO: This seems like a horrible place to put the abiOverride because 5965 * this isn't something the packageParser parsers. However, this fits in with 5966 * the rest of the PackageManager where package scanning randomly pushes 5967 * and prods fields out of {@code this.applicationInfo}. 5968 */ 5969 public String cpuAbiOverride; 5970 /** 5971 * The install time abi override to choose 32bit abi's when multiple abi's 5972 * are present. This is only meaningfull for multiarch applications. 5973 * The use32bitAbi attribute is ignored if cpuAbiOverride is also set. 5974 */ 5975 public boolean use32bitAbi; 5976 5977 public byte[] restrictUpdateHash; 5978 5979 /** Set if the app or any of its components are visible to instant applications. */ 5980 public boolean visibleToInstantApps; 5981 /** Whether or not the package is a stub and must be replaced by the full version. */ 5982 public boolean isStub; 5983 5984 public Package(String packageName) { 5985 this.packageName = packageName; 5986 this.manifestPackageName = packageName; 5987 applicationInfo.packageName = packageName; 5988 applicationInfo.uid = -1; 5989 } 5990 5991 public void setApplicationVolumeUuid(String volumeUuid) { 5992 final UUID storageUuid = StorageManager.convert(volumeUuid); 5993 this.applicationInfo.volumeUuid = volumeUuid; 5994 this.applicationInfo.storageUuid = storageUuid; 5995 if (childPackages != null) { 5996 final int packageCount = childPackages.size(); 5997 for (int i = 0; i < packageCount; i++) { 5998 childPackages.get(i).applicationInfo.volumeUuid = volumeUuid; 5999 childPackages.get(i).applicationInfo.storageUuid = storageUuid; 6000 } 6001 } 6002 } 6003 6004 public void setApplicationInfoCodePath(String codePath) { 6005 this.applicationInfo.setCodePath(codePath); 6006 if (childPackages != null) { 6007 final int packageCount = childPackages.size(); 6008 for (int i = 0; i < packageCount; i++) { 6009 childPackages.get(i).applicationInfo.setCodePath(codePath); 6010 } 6011 } 6012 } 6013 6014 public void setApplicationInfoResourcePath(String resourcePath) { 6015 this.applicationInfo.setResourcePath(resourcePath); 6016 if (childPackages != null) { 6017 final int packageCount = childPackages.size(); 6018 for (int i = 0; i < packageCount; i++) { 6019 childPackages.get(i).applicationInfo.setResourcePath(resourcePath); 6020 } 6021 } 6022 } 6023 6024 public void setApplicationInfoBaseResourcePath(String resourcePath) { 6025 this.applicationInfo.setBaseResourcePath(resourcePath); 6026 if (childPackages != null) { 6027 final int packageCount = childPackages.size(); 6028 for (int i = 0; i < packageCount; i++) { 6029 childPackages.get(i).applicationInfo.setBaseResourcePath(resourcePath); 6030 } 6031 } 6032 } 6033 6034 public void setApplicationInfoBaseCodePath(String baseCodePath) { 6035 this.applicationInfo.setBaseCodePath(baseCodePath); 6036 if (childPackages != null) { 6037 final int packageCount = childPackages.size(); 6038 for (int i = 0; i < packageCount; i++) { 6039 childPackages.get(i).applicationInfo.setBaseCodePath(baseCodePath); 6040 } 6041 } 6042 } 6043 6044 public List<String> getChildPackageNames() { 6045 if (childPackages == null) { 6046 return null; 6047 } 6048 final int childCount = childPackages.size(); 6049 final List<String> childPackageNames = new ArrayList<>(childCount); 6050 for (int i = 0; i < childCount; i++) { 6051 String childPackageName = childPackages.get(i).packageName; 6052 childPackageNames.add(childPackageName); 6053 } 6054 return childPackageNames; 6055 } 6056 6057 public boolean hasChildPackage(String packageName) { 6058 final int childCount = (childPackages != null) ? childPackages.size() : 0; 6059 for (int i = 0; i < childCount; i++) { 6060 if (childPackages.get(i).packageName.equals(packageName)) { 6061 return true; 6062 } 6063 } 6064 return false; 6065 } 6066 6067 public void setApplicationInfoSplitCodePaths(String[] splitCodePaths) { 6068 this.applicationInfo.setSplitCodePaths(splitCodePaths); 6069 // Children have no splits 6070 } 6071 6072 public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) { 6073 this.applicationInfo.setSplitResourcePaths(resroucePaths); 6074 // Children have no splits 6075 } 6076 6077 public void setSplitCodePaths(String[] codePaths) { 6078 this.splitCodePaths = codePaths; 6079 } 6080 6081 public void setCodePath(String codePath) { 6082 this.codePath = codePath; 6083 if (childPackages != null) { 6084 final int packageCount = childPackages.size(); 6085 for (int i = 0; i < packageCount; i++) { 6086 childPackages.get(i).codePath = codePath; 6087 } 6088 } 6089 } 6090 6091 public void setBaseCodePath(String baseCodePath) { 6092 this.baseCodePath = baseCodePath; 6093 if (childPackages != null) { 6094 final int packageCount = childPackages.size(); 6095 for (int i = 0; i < packageCount; i++) { 6096 childPackages.get(i).baseCodePath = baseCodePath; 6097 } 6098 } 6099 } 6100 6101 public void setSignatures(Signature[] signatures) { 6102 this.mSignatures = signatures; 6103 if (childPackages != null) { 6104 final int packageCount = childPackages.size(); 6105 for (int i = 0; i < packageCount; i++) { 6106 childPackages.get(i).mSignatures = signatures; 6107 } 6108 } 6109 } 6110 6111 public void setVolumeUuid(String volumeUuid) { 6112 this.volumeUuid = volumeUuid; 6113 if (childPackages != null) { 6114 final int packageCount = childPackages.size(); 6115 for (int i = 0; i < packageCount; i++) { 6116 childPackages.get(i).volumeUuid = volumeUuid; 6117 } 6118 } 6119 } 6120 6121 public void setApplicationInfoFlags(int mask, int flags) { 6122 applicationInfo.flags = (applicationInfo.flags & ~mask) | (mask & flags); 6123 if (childPackages != null) { 6124 final int packageCount = childPackages.size(); 6125 for (int i = 0; i < packageCount; i++) { 6126 childPackages.get(i).applicationInfo.flags = 6127 (applicationInfo.flags & ~mask) | (mask & flags); 6128 } 6129 } 6130 } 6131 6132 public void setUse32bitAbi(boolean use32bitAbi) { 6133 this.use32bitAbi = use32bitAbi; 6134 if (childPackages != null) { 6135 final int packageCount = childPackages.size(); 6136 for (int i = 0; i < packageCount; i++) { 6137 childPackages.get(i).use32bitAbi = use32bitAbi; 6138 } 6139 } 6140 } 6141 6142 public boolean isLibrary() { 6143 return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames); 6144 } 6145 6146 public List<String> getAllCodePaths() { 6147 ArrayList<String> paths = new ArrayList<>(); 6148 paths.add(baseCodePath); 6149 if (!ArrayUtils.isEmpty(splitCodePaths)) { 6150 Collections.addAll(paths, splitCodePaths); 6151 } 6152 return paths; 6153 } 6154 6155 /** 6156 * Filtered set of {@link #getAllCodePaths()} that excludes 6157 * resource-only APKs. 6158 */ 6159 public List<String> getAllCodePathsExcludingResourceOnly() { 6160 ArrayList<String> paths = new ArrayList<>(); 6161 if ((applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { 6162 paths.add(baseCodePath); 6163 } 6164 if (!ArrayUtils.isEmpty(splitCodePaths)) { 6165 for (int i = 0; i < splitCodePaths.length; i++) { 6166 if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { 6167 paths.add(splitCodePaths[i]); 6168 } 6169 } 6170 } 6171 return paths; 6172 } 6173 6174 public void setPackageName(String newName) { 6175 packageName = newName; 6176 applicationInfo.packageName = newName; 6177 for (int i=permissions.size()-1; i>=0; i--) { 6178 permissions.get(i).setPackageName(newName); 6179 } 6180 for (int i=permissionGroups.size()-1; i>=0; i--) { 6181 permissionGroups.get(i).setPackageName(newName); 6182 } 6183 for (int i=activities.size()-1; i>=0; i--) { 6184 activities.get(i).setPackageName(newName); 6185 } 6186 for (int i=receivers.size()-1; i>=0; i--) { 6187 receivers.get(i).setPackageName(newName); 6188 } 6189 for (int i=providers.size()-1; i>=0; i--) { 6190 providers.get(i).setPackageName(newName); 6191 } 6192 for (int i=services.size()-1; i>=0; i--) { 6193 services.get(i).setPackageName(newName); 6194 } 6195 for (int i=instrumentation.size()-1; i>=0; i--) { 6196 instrumentation.get(i).setPackageName(newName); 6197 } 6198 } 6199 6200 public boolean hasComponentClassName(String name) { 6201 for (int i=activities.size()-1; i>=0; i--) { 6202 if (name.equals(activities.get(i).className)) { 6203 return true; 6204 } 6205 } 6206 for (int i=receivers.size()-1; i>=0; i--) { 6207 if (name.equals(receivers.get(i).className)) { 6208 return true; 6209 } 6210 } 6211 for (int i=providers.size()-1; i>=0; i--) { 6212 if (name.equals(providers.get(i).className)) { 6213 return true; 6214 } 6215 } 6216 for (int i=services.size()-1; i>=0; i--) { 6217 if (name.equals(services.get(i).className)) { 6218 return true; 6219 } 6220 } 6221 for (int i=instrumentation.size()-1; i>=0; i--) { 6222 if (name.equals(instrumentation.get(i).className)) { 6223 return true; 6224 } 6225 } 6226 return false; 6227 } 6228 6229 /** 6230 * @hide 6231 */ 6232 public boolean isForwardLocked() { 6233 return applicationInfo.isForwardLocked(); 6234 } 6235 6236 /** 6237 * @hide 6238 */ 6239 public boolean isSystemApp() { 6240 return applicationInfo.isSystemApp(); 6241 } 6242 6243 /** 6244 * @hide 6245 */ 6246 public boolean isPrivilegedApp() { 6247 return applicationInfo.isPrivilegedApp(); 6248 } 6249 6250 /** 6251 * @hide 6252 */ 6253 public boolean isUpdatedSystemApp() { 6254 return applicationInfo.isUpdatedSystemApp(); 6255 } 6256 6257 /** 6258 * @hide 6259 */ 6260 public boolean canHaveOatDir() { 6261 // The following app types CANNOT have oat directory 6262 // - non-updated system apps 6263 // - forward-locked apps or apps installed in ASEC containers 6264 return (!isSystemApp() || isUpdatedSystemApp()) 6265 && !isForwardLocked() && !applicationInfo.isExternalAsec(); 6266 } 6267 6268 public boolean isMatch(int flags) { 6269 if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { 6270 return isSystemApp(); 6271 } 6272 return true; 6273 } 6274 6275 public long getLatestPackageUseTimeInMills() { 6276 long latestUse = 0L; 6277 for (long use : mLastPackageUsageTimeInMills) { 6278 latestUse = Math.max(latestUse, use); 6279 } 6280 return latestUse; 6281 } 6282 6283 public long getLatestForegroundPackageUseTimeInMills() { 6284 int[] foregroundReasons = { 6285 PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY, 6286 PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE 6287 }; 6288 6289 long latestUse = 0L; 6290 for (int reason : foregroundReasons) { 6291 latestUse = Math.max(latestUse, mLastPackageUsageTimeInMills[reason]); 6292 } 6293 return latestUse; 6294 } 6295 6296 public String toString() { 6297 return "Package{" 6298 + Integer.toHexString(System.identityHashCode(this)) 6299 + " " + packageName + "}"; 6300 } 6301 6302 @Override 6303 public int describeContents() { 6304 return 0; 6305 } 6306 6307 public Package(Parcel dest) { 6308 // We use the boot classloader for all classes that we load. 6309 final ClassLoader boot = Object.class.getClassLoader(); 6310 6311 packageName = dest.readString().intern(); 6312 manifestPackageName = dest.readString(); 6313 splitNames = dest.readStringArray(); 6314 volumeUuid = dest.readString(); 6315 codePath = dest.readString(); 6316 baseCodePath = dest.readString(); 6317 splitCodePaths = dest.readStringArray(); 6318 baseRevisionCode = dest.readInt(); 6319 splitRevisionCodes = dest.createIntArray(); 6320 splitFlags = dest.createIntArray(); 6321 splitPrivateFlags = dest.createIntArray(); 6322 baseHardwareAccelerated = (dest.readInt() == 1); 6323 applicationInfo = dest.readParcelable(boot); 6324 if (applicationInfo.permission != null) { 6325 applicationInfo.permission = applicationInfo.permission.intern(); 6326 } 6327 6328 // We don't serialize the "owner" package and the application info object for each of 6329 // these components, in order to save space and to avoid circular dependencies while 6330 // serialization. We need to fix them all up here. 6331 dest.readParcelableList(permissions, boot); 6332 fixupOwner(permissions); 6333 dest.readParcelableList(permissionGroups, boot); 6334 fixupOwner(permissionGroups); 6335 dest.readParcelableList(activities, boot); 6336 fixupOwner(activities); 6337 dest.readParcelableList(receivers, boot); 6338 fixupOwner(receivers); 6339 dest.readParcelableList(providers, boot); 6340 fixupOwner(providers); 6341 dest.readParcelableList(services, boot); 6342 fixupOwner(services); 6343 dest.readParcelableList(instrumentation, boot); 6344 fixupOwner(instrumentation); 6345 6346 dest.readStringList(requestedPermissions); 6347 internStringArrayList(requestedPermissions); 6348 protectedBroadcasts = dest.createStringArrayList(); 6349 internStringArrayList(protectedBroadcasts); 6350 6351 parentPackage = dest.readParcelable(boot); 6352 6353 childPackages = new ArrayList<>(); 6354 dest.readParcelableList(childPackages, boot); 6355 if (childPackages.size() == 0) { 6356 childPackages = null; 6357 } 6358 6359 staticSharedLibName = dest.readString(); 6360 if (staticSharedLibName != null) { 6361 staticSharedLibName = staticSharedLibName.intern(); 6362 } 6363 staticSharedLibVersion = dest.readInt(); 6364 libraryNames = dest.createStringArrayList(); 6365 internStringArrayList(libraryNames); 6366 usesLibraries = dest.createStringArrayList(); 6367 internStringArrayList(usesLibraries); 6368 usesOptionalLibraries = dest.createStringArrayList(); 6369 internStringArrayList(usesOptionalLibraries); 6370 usesLibraryFiles = dest.readStringArray(); 6371 6372 final int libCount = dest.readInt(); 6373 if (libCount > 0) { 6374 usesStaticLibraries = new ArrayList<>(libCount); 6375 dest.readStringList(usesStaticLibraries); 6376 internStringArrayList(usesStaticLibraries); 6377 usesStaticLibrariesVersions = new int[libCount]; 6378 dest.readIntArray(usesStaticLibrariesVersions); 6379 usesStaticLibrariesCertDigests = new String[libCount][]; 6380 for (int i = 0; i < libCount; i++) { 6381 usesStaticLibrariesCertDigests[i] = dest.createStringArray(); 6382 } 6383 } 6384 6385 preferredActivityFilters = new ArrayList<>(); 6386 dest.readParcelableList(preferredActivityFilters, boot); 6387 if (preferredActivityFilters.size() == 0) { 6388 preferredActivityFilters = null; 6389 } 6390 6391 mOriginalPackages = dest.createStringArrayList(); 6392 mRealPackage = dest.readString(); 6393 mAdoptPermissions = dest.createStringArrayList(); 6394 mAppMetaData = dest.readBundle(); 6395 mVersionCode = dest.readInt(); 6396 mVersionName = dest.readString(); 6397 if (mVersionName != null) { 6398 mVersionName = mVersionName.intern(); 6399 } 6400 mSharedUserId = dest.readString(); 6401 if (mSharedUserId != null) { 6402 mSharedUserId = mSharedUserId.intern(); 6403 } 6404 mSharedUserLabel = dest.readInt(); 6405 6406 mSignatures = (Signature[]) dest.readParcelableArray(boot, Signature.class); 6407 mCertificates = (Certificate[][]) dest.readSerializable(); 6408 6409 mPreferredOrder = dest.readInt(); 6410 6411 // long[] packageUsageTimeMillis is not persisted because it isn't information that 6412 // is parsed from the APK. 6413 6414 // Object mExtras is not persisted because it is not information that is read from 6415 // the APK, rather, it is supplied by callers. 6416 6417 6418 configPreferences = new ArrayList<>(); 6419 dest.readParcelableList(configPreferences, boot); 6420 if (configPreferences.size() == 0) { 6421 configPreferences = null; 6422 } 6423 6424 reqFeatures = new ArrayList<>(); 6425 dest.readParcelableList(reqFeatures, boot); 6426 if (reqFeatures.size() == 0) { 6427 reqFeatures = null; 6428 } 6429 6430 featureGroups = new ArrayList<>(); 6431 dest.readParcelableList(featureGroups, boot); 6432 if (featureGroups.size() == 0) { 6433 featureGroups = null; 6434 } 6435 6436 installLocation = dest.readInt(); 6437 coreApp = (dest.readInt() == 1); 6438 mRequiredForAllUsers = (dest.readInt() == 1); 6439 mRestrictedAccountType = dest.readString(); 6440 mRequiredAccountType = dest.readString(); 6441 mOverlayTarget = dest.readString(); 6442 mOverlayPriority = dest.readInt(); 6443 mIsStaticOverlay = (dest.readInt() == 1); 6444 mTrustedOverlay = (dest.readInt() == 1); 6445 mSigningKeys = (ArraySet<PublicKey>) dest.readArraySet(boot); 6446 mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot); 6447 6448 mKeySetMapping = readKeySetMapping(dest); 6449 6450 cpuAbiOverride = dest.readString(); 6451 use32bitAbi = (dest.readInt() == 1); 6452 restrictUpdateHash = dest.createByteArray(); 6453 visibleToInstantApps = dest.readInt() == 1; 6454 } 6455 6456 private static void internStringArrayList(List<String> list) { 6457 if (list != null) { 6458 final int N = list.size(); 6459 for (int i = 0; i < N; ++i) { 6460 list.set(i, list.get(i).intern()); 6461 } 6462 } 6463 } 6464 6465 /** 6466 * Sets the package owner and the the {@code applicationInfo} for every component 6467 * owner by this package. 6468 */ 6469 private void fixupOwner(List<? extends Component<?>> list) { 6470 if (list != null) { 6471 for (Component<?> c : list) { 6472 c.owner = this; 6473 if (c instanceof Activity) { 6474 ((Activity) c).info.applicationInfo = this.applicationInfo; 6475 } else if (c instanceof Service) { 6476 ((Service) c).info.applicationInfo = this.applicationInfo; 6477 } else if (c instanceof Provider) { 6478 ((Provider) c).info.applicationInfo = this.applicationInfo; 6479 } 6480 } 6481 } 6482 } 6483 6484 @Override 6485 public void writeToParcel(Parcel dest, int flags) { 6486 dest.writeString(packageName); 6487 dest.writeString(manifestPackageName); 6488 dest.writeStringArray(splitNames); 6489 dest.writeString(volumeUuid); 6490 dest.writeString(codePath); 6491 dest.writeString(baseCodePath); 6492 dest.writeStringArray(splitCodePaths); 6493 dest.writeInt(baseRevisionCode); 6494 dest.writeIntArray(splitRevisionCodes); 6495 dest.writeIntArray(splitFlags); 6496 dest.writeIntArray(splitPrivateFlags); 6497 dest.writeInt(baseHardwareAccelerated ? 1 : 0); 6498 dest.writeParcelable(applicationInfo, flags); 6499 6500 dest.writeParcelableList(permissions, flags); 6501 dest.writeParcelableList(permissionGroups, flags); 6502 dest.writeParcelableList(activities, flags); 6503 dest.writeParcelableList(receivers, flags); 6504 dest.writeParcelableList(providers, flags); 6505 dest.writeParcelableList(services, flags); 6506 dest.writeParcelableList(instrumentation, flags); 6507 6508 dest.writeStringList(requestedPermissions); 6509 dest.writeStringList(protectedBroadcasts); 6510 6511 // TODO: This doesn't work: b/64295061 6512 dest.writeParcelable(parentPackage, flags); 6513 dest.writeParcelableList(childPackages, flags); 6514 6515 dest.writeString(staticSharedLibName); 6516 dest.writeInt(staticSharedLibVersion); 6517 dest.writeStringList(libraryNames); 6518 dest.writeStringList(usesLibraries); 6519 dest.writeStringList(usesOptionalLibraries); 6520 dest.writeStringArray(usesLibraryFiles); 6521 6522 if (ArrayUtils.isEmpty(usesStaticLibraries)) { 6523 dest.writeInt(-1); 6524 } else { 6525 dest.writeInt(usesStaticLibraries.size()); 6526 dest.writeStringList(usesStaticLibraries); 6527 dest.writeIntArray(usesStaticLibrariesVersions); 6528 for (String[] usesStaticLibrariesCertDigest : usesStaticLibrariesCertDigests) { 6529 dest.writeStringArray(usesStaticLibrariesCertDigest); 6530 } 6531 } 6532 6533 dest.writeParcelableList(preferredActivityFilters, flags); 6534 6535 dest.writeStringList(mOriginalPackages); 6536 dest.writeString(mRealPackage); 6537 dest.writeStringList(mAdoptPermissions); 6538 dest.writeBundle(mAppMetaData); 6539 dest.writeInt(mVersionCode); 6540 dest.writeString(mVersionName); 6541 dest.writeString(mSharedUserId); 6542 dest.writeInt(mSharedUserLabel); 6543 6544 dest.writeParcelableArray(mSignatures, flags); 6545 dest.writeSerializable(mCertificates); 6546 6547 dest.writeInt(mPreferredOrder); 6548 6549 // long[] packageUsageTimeMillis is not persisted because it isn't information that 6550 // is parsed from the APK. 6551 6552 // Object mExtras is not persisted because it is not information that is read from 6553 // the APK, rather, it is supplied by callers. 6554 6555 dest.writeParcelableList(configPreferences, flags); 6556 dest.writeParcelableList(reqFeatures, flags); 6557 dest.writeParcelableList(featureGroups, flags); 6558 6559 dest.writeInt(installLocation); 6560 dest.writeInt(coreApp ? 1 : 0); 6561 dest.writeInt(mRequiredForAllUsers ? 1 : 0); 6562 dest.writeString(mRestrictedAccountType); 6563 dest.writeString(mRequiredAccountType); 6564 dest.writeString(mOverlayTarget); 6565 dest.writeInt(mOverlayPriority); 6566 dest.writeInt(mIsStaticOverlay ? 1 : 0); 6567 dest.writeInt(mTrustedOverlay ? 1 : 0); 6568 dest.writeArraySet(mSigningKeys); 6569 dest.writeArraySet(mUpgradeKeySets); 6570 writeKeySetMapping(dest, mKeySetMapping); 6571 dest.writeString(cpuAbiOverride); 6572 dest.writeInt(use32bitAbi ? 1 : 0); 6573 dest.writeByteArray(restrictUpdateHash); 6574 dest.writeInt(visibleToInstantApps ? 1 : 0); 6575 } 6576 6577 6578 /** 6579 * Writes the keyset mapping to the provided package. {@code null} mappings are permitted. 6580 */ 6581 private static void writeKeySetMapping( 6582 Parcel dest, ArrayMap<String, ArraySet<PublicKey>> keySetMapping) { 6583 if (keySetMapping == null) { 6584 dest.writeInt(-1); 6585 return; 6586 } 6587 6588 final int N = keySetMapping.size(); 6589 dest.writeInt(N); 6590 6591 for (int i = 0; i < N; i++) { 6592 dest.writeString(keySetMapping.keyAt(i)); 6593 ArraySet<PublicKey> keys = keySetMapping.valueAt(i); 6594 if (keys == null) { 6595 dest.writeInt(-1); 6596 continue; 6597 } 6598 6599 final int M = keys.size(); 6600 dest.writeInt(M); 6601 for (int j = 0; j < M; j++) { 6602 dest.writeSerializable(keys.valueAt(j)); 6603 } 6604 } 6605 } 6606 6607 /** 6608 * Reads a keyset mapping from the given parcel at the given data position. May return 6609 * {@code null} if the serialized mapping was {@code null}. 6610 */ 6611 private static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(Parcel in) { 6612 final int N = in.readInt(); 6613 if (N == -1) { 6614 return null; 6615 } 6616 6617 ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>(); 6618 for (int i = 0; i < N; ++i) { 6619 String key = in.readString(); 6620 final int M = in.readInt(); 6621 if (M == -1) { 6622 keySetMapping.put(key, null); 6623 continue; 6624 } 6625 6626 ArraySet<PublicKey> keys = new ArraySet<>(M); 6627 for (int j = 0; j < M; ++j) { 6628 PublicKey pk = (PublicKey) in.readSerializable(); 6629 keys.add(pk); 6630 } 6631 6632 keySetMapping.put(key, keys); 6633 } 6634 6635 return keySetMapping; 6636 } 6637 6638 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Package>() { 6639 public Package createFromParcel(Parcel in) { 6640 return new Package(in); 6641 } 6642 6643 public Package[] newArray(int size) { 6644 return new Package[size]; 6645 } 6646 }; 6647 } 6648 6649 public static abstract class Component<II extends IntentInfo> { 6650 public final ArrayList<II> intents; 6651 public final String className; 6652 6653 public Bundle metaData; 6654 public Package owner; 6655 6656 ComponentName componentName; 6657 String componentShortName; 6658 6659 public Component(Package _owner) { 6660 owner = _owner; 6661 intents = null; 6662 className = null; 6663 } 6664 6665 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) { 6666 owner = args.owner; 6667 intents = new ArrayList<II>(0); 6668 if (parsePackageItemInfo(args.owner, outInfo, args.outError, args.tag, args.sa, 6669 true /*nameRequired*/, args.nameRes, args.labelRes, args.iconRes, 6670 args.roundIconRes, args.logoRes, args.bannerRes)) { 6671 className = outInfo.name; 6672 } else { 6673 className = null; 6674 } 6675 } 6676 6677 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) { 6678 this(args, (PackageItemInfo)outInfo); 6679 if (args.outError[0] != null) { 6680 return; 6681 } 6682 6683 if (args.processRes != 0) { 6684 CharSequence pname; 6685 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 6686 pname = args.sa.getNonConfigurationString(args.processRes, 6687 Configuration.NATIVE_CONFIG_VERSION); 6688 } else { 6689 // Some older apps have been seen to use a resource reference 6690 // here that on older builds was ignored (with a warning). We 6691 // need to continue to do this for them so they don't break. 6692 pname = args.sa.getNonResourceString(args.processRes); 6693 } 6694 outInfo.processName = buildProcessName(owner.applicationInfo.packageName, 6695 owner.applicationInfo.processName, pname, 6696 args.flags, args.sepProcesses, args.outError); 6697 } 6698 6699 if (args.descriptionRes != 0) { 6700 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0); 6701 } 6702 6703 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true); 6704 } 6705 6706 public Component(Component<II> clone) { 6707 owner = clone.owner; 6708 intents = clone.intents; 6709 className = clone.className; 6710 componentName = clone.componentName; 6711 componentShortName = clone.componentShortName; 6712 } 6713 6714 public ComponentName getComponentName() { 6715 if (componentName != null) { 6716 return componentName; 6717 } 6718 if (className != null) { 6719 componentName = new ComponentName(owner.applicationInfo.packageName, 6720 className); 6721 } 6722 return componentName; 6723 } 6724 6725 protected Component(Parcel in) { 6726 className = in.readString(); 6727 metaData = in.readBundle(); 6728 intents = createIntentsList(in); 6729 6730 owner = null; 6731 } 6732 6733 protected void writeToParcel(Parcel dest, int flags) { 6734 dest.writeString(className); 6735 dest.writeBundle(metaData); 6736 6737 writeIntentsList(intents, dest, flags); 6738 } 6739 6740 /** 6741 * <p> 6742 * Implementation note: The serialized form for the intent list also contains the name 6743 * of the concrete class that's stored in the list, and assumes that every element of the 6744 * list is of the same type. This is very similar to the original parcelable mechanism. 6745 * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable 6746 * and is public API. It also declares Parcelable related methods as final which means 6747 * we can't extend them. The approach of using composition instead of inheritance leads to 6748 * a large set of cascading changes in the PackageManagerService, which seem undesirable. 6749 * 6750 * <p> 6751 * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up 6752 * to make sure their owner fields are consistent. See {@code fixupOwner}. 6753 */ 6754 private static void writeIntentsList(ArrayList<? extends IntentInfo> list, Parcel out, 6755 int flags) { 6756 if (list == null) { 6757 out.writeInt(-1); 6758 return; 6759 } 6760 6761 final int N = list.size(); 6762 out.writeInt(N); 6763 6764 // Don't bother writing the component name if the list is empty. 6765 if (N > 0) { 6766 IntentInfo info = list.get(0); 6767 out.writeString(info.getClass().getName()); 6768 6769 for (int i = 0; i < N;i++) { 6770 list.get(i).writeIntentInfoToParcel(out, flags); 6771 } 6772 } 6773 } 6774 6775 private static <T extends IntentInfo> ArrayList<T> createIntentsList(Parcel in) { 6776 int N = in.readInt(); 6777 if (N == -1) { 6778 return null; 6779 } 6780 6781 if (N == 0) { 6782 return new ArrayList<>(0); 6783 } 6784 6785 String componentName = in.readString(); 6786 final ArrayList<T> intentsList; 6787 try { 6788 final Class<T> cls = (Class<T>) Class.forName(componentName); 6789 final Constructor<T> cons = cls.getConstructor(Parcel.class); 6790 6791 intentsList = new ArrayList<>(N); 6792 for (int i = 0; i < N; ++i) { 6793 intentsList.add(cons.newInstance(in)); 6794 } 6795 } catch (ReflectiveOperationException ree) { 6796 throw new AssertionError("Unable to construct intent list for: " + componentName); 6797 } 6798 6799 return intentsList; 6800 } 6801 6802 public void appendComponentShortName(StringBuilder sb) { 6803 ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className); 6804 } 6805 6806 public void printComponentShortName(PrintWriter pw) { 6807 ComponentName.printShortString(pw, owner.applicationInfo.packageName, className); 6808 } 6809 6810 public void setPackageName(String packageName) { 6811 componentName = null; 6812 componentShortName = null; 6813 } 6814 } 6815 6816 public final static class Permission extends Component<IntentInfo> implements Parcelable { 6817 public final PermissionInfo info; 6818 public boolean tree; 6819 public PermissionGroup group; 6820 6821 public Permission(Package _owner) { 6822 super(_owner); 6823 info = new PermissionInfo(); 6824 } 6825 6826 public Permission(Package _owner, PermissionInfo _info) { 6827 super(_owner); 6828 info = _info; 6829 } 6830 6831 public void setPackageName(String packageName) { 6832 super.setPackageName(packageName); 6833 info.packageName = packageName; 6834 } 6835 6836 public String toString() { 6837 return "Permission{" 6838 + Integer.toHexString(System.identityHashCode(this)) 6839 + " " + info.name + "}"; 6840 } 6841 6842 @Override 6843 public int describeContents() { 6844 return 0; 6845 } 6846 6847 @Override 6848 public void writeToParcel(Parcel dest, int flags) { 6849 super.writeToParcel(dest, flags); 6850 dest.writeParcelable(info, flags); 6851 dest.writeInt(tree ? 1 : 0); 6852 dest.writeParcelable(group, flags); 6853 } 6854 6855 private Permission(Parcel in) { 6856 super(in); 6857 final ClassLoader boot = Object.class.getClassLoader(); 6858 info = in.readParcelable(boot); 6859 if (info.group != null) { 6860 info.group = info.group.intern(); 6861 } 6862 6863 tree = (in.readInt() == 1); 6864 group = in.readParcelable(boot); 6865 } 6866 6867 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Permission>() { 6868 public Permission createFromParcel(Parcel in) { 6869 return new Permission(in); 6870 } 6871 6872 public Permission[] newArray(int size) { 6873 return new Permission[size]; 6874 } 6875 }; 6876 } 6877 6878 public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable { 6879 public final PermissionGroupInfo info; 6880 6881 public PermissionGroup(Package _owner) { 6882 super(_owner); 6883 info = new PermissionGroupInfo(); 6884 } 6885 6886 public PermissionGroup(Package _owner, PermissionGroupInfo _info) { 6887 super(_owner); 6888 info = _info; 6889 } 6890 6891 public void setPackageName(String packageName) { 6892 super.setPackageName(packageName); 6893 info.packageName = packageName; 6894 } 6895 6896 public String toString() { 6897 return "PermissionGroup{" 6898 + Integer.toHexString(System.identityHashCode(this)) 6899 + " " + info.name + "}"; 6900 } 6901 6902 @Override 6903 public int describeContents() { 6904 return 0; 6905 } 6906 6907 @Override 6908 public void writeToParcel(Parcel dest, int flags) { 6909 super.writeToParcel(dest, flags); 6910 dest.writeParcelable(info, flags); 6911 } 6912 6913 private PermissionGroup(Parcel in) { 6914 super(in); 6915 info = in.readParcelable(Object.class.getClassLoader()); 6916 } 6917 6918 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<PermissionGroup>() { 6919 public PermissionGroup createFromParcel(Parcel in) { 6920 return new PermissionGroup(in); 6921 } 6922 6923 public PermissionGroup[] newArray(int size) { 6924 return new PermissionGroup[size]; 6925 } 6926 }; 6927 } 6928 6929 private static boolean copyNeeded(int flags, Package p, 6930 PackageUserState state, Bundle metaData, int userId) { 6931 if (userId != UserHandle.USER_SYSTEM) { 6932 // We always need to copy for other users, since we need 6933 // to fix up the uid. 6934 return true; 6935 } 6936 if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 6937 boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 6938 if (p.applicationInfo.enabled != enabled) { 6939 return true; 6940 } 6941 } 6942 boolean suspended = (p.applicationInfo.flags & FLAG_SUSPENDED) != 0; 6943 if (state.suspended != suspended) { 6944 return true; 6945 } 6946 if (!state.installed || state.hidden) { 6947 return true; 6948 } 6949 if (state.stopped) { 6950 return true; 6951 } 6952 if (state.instantApp != p.applicationInfo.isInstantApp()) { 6953 return true; 6954 } 6955 if ((flags & PackageManager.GET_META_DATA) != 0 6956 && (metaData != null || p.mAppMetaData != null)) { 6957 return true; 6958 } 6959 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 6960 && p.usesLibraryFiles != null) { 6961 return true; 6962 } 6963 if (p.staticSharedLibName != null) { 6964 return true; 6965 } 6966 return false; 6967 } 6968 6969 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 6970 PackageUserState state) { 6971 return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId()); 6972 } 6973 6974 private static void updateApplicationInfo(ApplicationInfo ai, int flags, 6975 PackageUserState state) { 6976 // CompatibilityMode is global state. 6977 if (!sCompatibilityModeEnabled) { 6978 ai.disableCompatibilityMode(); 6979 } 6980 if (state.installed) { 6981 ai.flags |= ApplicationInfo.FLAG_INSTALLED; 6982 } else { 6983 ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; 6984 } 6985 if (state.suspended) { 6986 ai.flags |= ApplicationInfo.FLAG_SUSPENDED; 6987 } else { 6988 ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED; 6989 } 6990 if (state.instantApp) { 6991 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT; 6992 } else { 6993 ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT; 6994 } 6995 if (state.virtualPreload) { 6996 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD; 6997 } else { 6998 ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD; 6999 } 7000 if (state.hidden) { 7001 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN; 7002 } else { 7003 ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN; 7004 } 7005 if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 7006 ai.enabled = true; 7007 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { 7008 ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0; 7009 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED 7010 || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { 7011 ai.enabled = false; 7012 } 7013 ai.enabledSetting = state.enabled; 7014 if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { 7015 ai.category = state.categoryHint; 7016 } 7017 if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { 7018 ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName); 7019 } 7020 ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state); 7021 ai.resourceDirs = state.overlayPaths; 7022 } 7023 7024 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 7025 PackageUserState state, int userId) { 7026 if (p == null) return null; 7027 if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) { 7028 return null; 7029 } 7030 if (!copyNeeded(flags, p, state, null, userId) 7031 && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0 7032 || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { 7033 // In this case it is safe to directly modify the internal ApplicationInfo state: 7034 // - CompatibilityMode is global state, so will be the same for every call. 7035 // - We only come in to here if the app should reported as installed; this is the 7036 // default state, and we will do a copy otherwise. 7037 // - The enable state will always be reported the same for the application across 7038 // calls; the only exception is for the UNTIL_USED mode, and in that case we will 7039 // be doing a copy. 7040 updateApplicationInfo(p.applicationInfo, flags, state); 7041 return p.applicationInfo; 7042 } 7043 7044 // Make shallow copy so we can store the metadata/libraries safely 7045 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo); 7046 ai.initForUser(userId); 7047 if ((flags & PackageManager.GET_META_DATA) != 0) { 7048 ai.metaData = p.mAppMetaData; 7049 } 7050 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { 7051 ai.sharedLibraryFiles = p.usesLibraryFiles; 7052 } 7053 if (state.stopped) { 7054 ai.flags |= ApplicationInfo.FLAG_STOPPED; 7055 } else { 7056 ai.flags &= ~ApplicationInfo.FLAG_STOPPED; 7057 } 7058 updateApplicationInfo(ai, flags, state); 7059 return ai; 7060 } 7061 7062 public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags, 7063 PackageUserState state, int userId) { 7064 if (ai == null) return null; 7065 if (!checkUseInstalledOrHidden(flags, state, ai)) { 7066 return null; 7067 } 7068 // This is only used to return the ResolverActivity; we will just always 7069 // make a copy. 7070 ai = new ApplicationInfo(ai); 7071 ai.initForUser(userId); 7072 if (state.stopped) { 7073 ai.flags |= ApplicationInfo.FLAG_STOPPED; 7074 } else { 7075 ai.flags &= ~ApplicationInfo.FLAG_STOPPED; 7076 } 7077 updateApplicationInfo(ai, flags, state); 7078 return ai; 7079 } 7080 7081 public static final PermissionInfo generatePermissionInfo( 7082 Permission p, int flags) { 7083 if (p == null) return null; 7084 if ((flags&PackageManager.GET_META_DATA) == 0) { 7085 return p.info; 7086 } 7087 PermissionInfo pi = new PermissionInfo(p.info); 7088 pi.metaData = p.metaData; 7089 return pi; 7090 } 7091 7092 public static final PermissionGroupInfo generatePermissionGroupInfo( 7093 PermissionGroup pg, int flags) { 7094 if (pg == null) return null; 7095 if ((flags&PackageManager.GET_META_DATA) == 0) { 7096 return pg.info; 7097 } 7098 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info); 7099 pgi.metaData = pg.metaData; 7100 return pgi; 7101 } 7102 7103 public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable { 7104 public final ActivityInfo info; 7105 private boolean mHasMaxAspectRatio; 7106 7107 private boolean hasMaxAspectRatio() { 7108 return mHasMaxAspectRatio; 7109 } 7110 7111 public Activity(final ParseComponentArgs args, final ActivityInfo _info) { 7112 super(args, _info); 7113 info = _info; 7114 info.applicationInfo = args.owner.applicationInfo; 7115 } 7116 7117 public void setPackageName(String packageName) { 7118 super.setPackageName(packageName); 7119 info.packageName = packageName; 7120 } 7121 7122 7123 private void setMaxAspectRatio(float maxAspectRatio) { 7124 if (info.resizeMode == RESIZE_MODE_RESIZEABLE 7125 || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { 7126 // Resizeable activities can be put in any aspect ratio. 7127 return; 7128 } 7129 7130 if (maxAspectRatio < 1.0f && maxAspectRatio != 0) { 7131 // Ignore any value lesser than 1.0. 7132 return; 7133 } 7134 7135 info.maxAspectRatio = maxAspectRatio; 7136 mHasMaxAspectRatio = true; 7137 } 7138 7139 public String toString() { 7140 StringBuilder sb = new StringBuilder(128); 7141 sb.append("Activity{"); 7142 sb.append(Integer.toHexString(System.identityHashCode(this))); 7143 sb.append(' '); 7144 appendComponentShortName(sb); 7145 sb.append('}'); 7146 return sb.toString(); 7147 } 7148 7149 @Override 7150 public int describeContents() { 7151 return 0; 7152 } 7153 7154 @Override 7155 public void writeToParcel(Parcel dest, int flags) { 7156 super.writeToParcel(dest, flags); 7157 dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES); 7158 dest.writeBoolean(mHasMaxAspectRatio); 7159 } 7160 7161 private Activity(Parcel in) { 7162 super(in); 7163 info = in.readParcelable(Object.class.getClassLoader()); 7164 mHasMaxAspectRatio = in.readBoolean(); 7165 7166 for (ActivityIntentInfo aii : intents) { 7167 aii.activity = this; 7168 } 7169 7170 if (info.permission != null) { 7171 info.permission = info.permission.intern(); 7172 } 7173 } 7174 7175 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Activity>() { 7176 public Activity createFromParcel(Parcel in) { 7177 return new Activity(in); 7178 } 7179 7180 public Activity[] newArray(int size) { 7181 return new Activity[size]; 7182 } 7183 }; 7184 } 7185 7186 public static final ActivityInfo generateActivityInfo(Activity a, int flags, 7187 PackageUserState state, int userId) { 7188 if (a == null) return null; 7189 if (!checkUseInstalledOrHidden(flags, state, a.owner.applicationInfo)) { 7190 return null; 7191 } 7192 if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) { 7193 updateApplicationInfo(a.info.applicationInfo, flags, state); 7194 return a.info; 7195 } 7196 // Make shallow copies so we can store the metadata safely 7197 ActivityInfo ai = new ActivityInfo(a.info); 7198 ai.metaData = a.metaData; 7199 ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId); 7200 return ai; 7201 } 7202 7203 public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags, 7204 PackageUserState state, int userId) { 7205 if (ai == null) return null; 7206 if (!checkUseInstalledOrHidden(flags, state, ai.applicationInfo)) { 7207 return null; 7208 } 7209 // This is only used to return the ResolverActivity; we will just always 7210 // make a copy. 7211 ai = new ActivityInfo(ai); 7212 ai.applicationInfo = generateApplicationInfo(ai.applicationInfo, flags, state, userId); 7213 return ai; 7214 } 7215 7216 public final static class Service extends Component<ServiceIntentInfo> implements Parcelable { 7217 public final ServiceInfo info; 7218 7219 public Service(final ParseComponentArgs args, final ServiceInfo _info) { 7220 super(args, _info); 7221 info = _info; 7222 info.applicationInfo = args.owner.applicationInfo; 7223 } 7224 7225 public void setPackageName(String packageName) { 7226 super.setPackageName(packageName); 7227 info.packageName = packageName; 7228 } 7229 7230 public String toString() { 7231 StringBuilder sb = new StringBuilder(128); 7232 sb.append("Service{"); 7233 sb.append(Integer.toHexString(System.identityHashCode(this))); 7234 sb.append(' '); 7235 appendComponentShortName(sb); 7236 sb.append('}'); 7237 return sb.toString(); 7238 } 7239 7240 @Override 7241 public int describeContents() { 7242 return 0; 7243 } 7244 7245 @Override 7246 public void writeToParcel(Parcel dest, int flags) { 7247 super.writeToParcel(dest, flags); 7248 dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES); 7249 } 7250 7251 private Service(Parcel in) { 7252 super(in); 7253 info = in.readParcelable(Object.class.getClassLoader()); 7254 7255 for (ServiceIntentInfo aii : intents) { 7256 aii.service = this; 7257 } 7258 7259 if (info.permission != null) { 7260 info.permission = info.permission.intern(); 7261 } 7262 } 7263 7264 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Service>() { 7265 public Service createFromParcel(Parcel in) { 7266 return new Service(in); 7267 } 7268 7269 public Service[] newArray(int size) { 7270 return new Service[size]; 7271 } 7272 }; 7273 } 7274 7275 public static final ServiceInfo generateServiceInfo(Service s, int flags, 7276 PackageUserState state, int userId) { 7277 if (s == null) return null; 7278 if (!checkUseInstalledOrHidden(flags, state, s.owner.applicationInfo)) { 7279 return null; 7280 } 7281 if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) { 7282 updateApplicationInfo(s.info.applicationInfo, flags, state); 7283 return s.info; 7284 } 7285 // Make shallow copies so we can store the metadata safely 7286 ServiceInfo si = new ServiceInfo(s.info); 7287 si.metaData = s.metaData; 7288 si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId); 7289 return si; 7290 } 7291 7292 public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable { 7293 public final ProviderInfo info; 7294 public boolean syncable; 7295 7296 public Provider(final ParseComponentArgs args, final ProviderInfo _info) { 7297 super(args, _info); 7298 info = _info; 7299 info.applicationInfo = args.owner.applicationInfo; 7300 syncable = false; 7301 } 7302 7303 public Provider(Provider existingProvider) { 7304 super(existingProvider); 7305 this.info = existingProvider.info; 7306 this.syncable = existingProvider.syncable; 7307 } 7308 7309 public void setPackageName(String packageName) { 7310 super.setPackageName(packageName); 7311 info.packageName = packageName; 7312 } 7313 7314 public String toString() { 7315 StringBuilder sb = new StringBuilder(128); 7316 sb.append("Provider{"); 7317 sb.append(Integer.toHexString(System.identityHashCode(this))); 7318 sb.append(' '); 7319 appendComponentShortName(sb); 7320 sb.append('}'); 7321 return sb.toString(); 7322 } 7323 7324 @Override 7325 public int describeContents() { 7326 return 0; 7327 } 7328 7329 @Override 7330 public void writeToParcel(Parcel dest, int flags) { 7331 super.writeToParcel(dest, flags); 7332 dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES); 7333 dest.writeInt((syncable) ? 1 : 0); 7334 } 7335 7336 private Provider(Parcel in) { 7337 super(in); 7338 info = in.readParcelable(Object.class.getClassLoader()); 7339 syncable = (in.readInt() == 1); 7340 7341 for (ProviderIntentInfo aii : intents) { 7342 aii.provider = this; 7343 } 7344 7345 if (info.readPermission != null) { 7346 info.readPermission = info.readPermission.intern(); 7347 } 7348 7349 if (info.writePermission != null) { 7350 info.writePermission = info.writePermission.intern(); 7351 } 7352 7353 if (info.authority != null) { 7354 info.authority = info.authority.intern(); 7355 } 7356 } 7357 7358 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Provider>() { 7359 public Provider createFromParcel(Parcel in) { 7360 return new Provider(in); 7361 } 7362 7363 public Provider[] newArray(int size) { 7364 return new Provider[size]; 7365 } 7366 }; 7367 } 7368 7369 public static final ProviderInfo generateProviderInfo(Provider p, int flags, 7370 PackageUserState state, int userId) { 7371 if (p == null) return null; 7372 if (!checkUseInstalledOrHidden(flags, state, p.owner.applicationInfo)) { 7373 return null; 7374 } 7375 if (!copyNeeded(flags, p.owner, state, p.metaData, userId) 7376 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 7377 || p.info.uriPermissionPatterns == null)) { 7378 updateApplicationInfo(p.info.applicationInfo, flags, state); 7379 return p.info; 7380 } 7381 // Make shallow copies so we can store the metadata safely 7382 ProviderInfo pi = new ProviderInfo(p.info); 7383 pi.metaData = p.metaData; 7384 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { 7385 pi.uriPermissionPatterns = null; 7386 } 7387 pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId); 7388 return pi; 7389 } 7390 7391 public final static class Instrumentation extends Component<IntentInfo> implements 7392 Parcelable { 7393 public final InstrumentationInfo info; 7394 7395 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) { 7396 super(args, _info); 7397 info = _info; 7398 } 7399 7400 public void setPackageName(String packageName) { 7401 super.setPackageName(packageName); 7402 info.packageName = packageName; 7403 } 7404 7405 public String toString() { 7406 StringBuilder sb = new StringBuilder(128); 7407 sb.append("Instrumentation{"); 7408 sb.append(Integer.toHexString(System.identityHashCode(this))); 7409 sb.append(' '); 7410 appendComponentShortName(sb); 7411 sb.append('}'); 7412 return sb.toString(); 7413 } 7414 7415 @Override 7416 public int describeContents() { 7417 return 0; 7418 } 7419 7420 @Override 7421 public void writeToParcel(Parcel dest, int flags) { 7422 super.writeToParcel(dest, flags); 7423 dest.writeParcelable(info, flags); 7424 } 7425 7426 private Instrumentation(Parcel in) { 7427 super(in); 7428 info = in.readParcelable(Object.class.getClassLoader()); 7429 7430 if (info.targetPackage != null) { 7431 info.targetPackage = info.targetPackage.intern(); 7432 } 7433 7434 if (info.targetProcesses != null) { 7435 info.targetProcesses = info.targetProcesses.intern(); 7436 } 7437 } 7438 7439 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Instrumentation>() { 7440 public Instrumentation createFromParcel(Parcel in) { 7441 return new Instrumentation(in); 7442 } 7443 7444 public Instrumentation[] newArray(int size) { 7445 return new Instrumentation[size]; 7446 } 7447 }; 7448 } 7449 7450 public static final InstrumentationInfo generateInstrumentationInfo( 7451 Instrumentation i, int flags) { 7452 if (i == null) return null; 7453 if ((flags&PackageManager.GET_META_DATA) == 0) { 7454 return i.info; 7455 } 7456 InstrumentationInfo ii = new InstrumentationInfo(i.info); 7457 ii.metaData = i.metaData; 7458 return ii; 7459 } 7460 7461 public static abstract class IntentInfo extends IntentFilter { 7462 public boolean hasDefault; 7463 public int labelRes; 7464 public CharSequence nonLocalizedLabel; 7465 public int icon; 7466 public int logo; 7467 public int banner; 7468 public int preferred; 7469 7470 protected IntentInfo() { 7471 } 7472 7473 protected IntentInfo(Parcel dest) { 7474 super(dest); 7475 hasDefault = (dest.readInt() == 1); 7476 labelRes = dest.readInt(); 7477 nonLocalizedLabel = dest.readCharSequence(); 7478 icon = dest.readInt(); 7479 logo = dest.readInt(); 7480 banner = dest.readInt(); 7481 preferred = dest.readInt(); 7482 } 7483 7484 7485 public void writeIntentInfoToParcel(Parcel dest, int flags) { 7486 super.writeToParcel(dest, flags); 7487 dest.writeInt(hasDefault ? 1 : 0); 7488 dest.writeInt(labelRes); 7489 dest.writeCharSequence(nonLocalizedLabel); 7490 dest.writeInt(icon); 7491 dest.writeInt(logo); 7492 dest.writeInt(banner); 7493 dest.writeInt(preferred); 7494 } 7495 } 7496 7497 public final static class ActivityIntentInfo extends IntentInfo { 7498 public Activity activity; 7499 7500 public ActivityIntentInfo(Activity _activity) { 7501 activity = _activity; 7502 } 7503 7504 public String toString() { 7505 StringBuilder sb = new StringBuilder(128); 7506 sb.append("ActivityIntentInfo{"); 7507 sb.append(Integer.toHexString(System.identityHashCode(this))); 7508 sb.append(' '); 7509 activity.appendComponentShortName(sb); 7510 sb.append('}'); 7511 return sb.toString(); 7512 } 7513 7514 public ActivityIntentInfo(Parcel in) { 7515 super(in); 7516 } 7517 } 7518 7519 public final static class ServiceIntentInfo extends IntentInfo { 7520 public Service service; 7521 7522 public ServiceIntentInfo(Service _service) { 7523 service = _service; 7524 } 7525 7526 public String toString() { 7527 StringBuilder sb = new StringBuilder(128); 7528 sb.append("ServiceIntentInfo{"); 7529 sb.append(Integer.toHexString(System.identityHashCode(this))); 7530 sb.append(' '); 7531 service.appendComponentShortName(sb); 7532 sb.append('}'); 7533 return sb.toString(); 7534 } 7535 7536 public ServiceIntentInfo(Parcel in) { 7537 super(in); 7538 } 7539 } 7540 7541 public static final class ProviderIntentInfo extends IntentInfo { 7542 public Provider provider; 7543 7544 public ProviderIntentInfo(Provider provider) { 7545 this.provider = provider; 7546 } 7547 7548 public String toString() { 7549 StringBuilder sb = new StringBuilder(128); 7550 sb.append("ProviderIntentInfo{"); 7551 sb.append(Integer.toHexString(System.identityHashCode(this))); 7552 sb.append(' '); 7553 provider.appendComponentShortName(sb); 7554 sb.append('}'); 7555 return sb.toString(); 7556 } 7557 7558 public ProviderIntentInfo(Parcel in) { 7559 super(in); 7560 } 7561 } 7562 7563 /** 7564 * @hide 7565 */ 7566 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { 7567 sCompatibilityModeEnabled = compatibilityModeEnabled; 7568 } 7569 7570 private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>(); 7571 7572 public static long readFullyIgnoringContents(InputStream in) throws IOException { 7573 byte[] buffer = sBuffer.getAndSet(null); 7574 if (buffer == null) { 7575 buffer = new byte[4096]; 7576 } 7577 7578 int n = 0; 7579 int count = 0; 7580 while ((n = in.read(buffer, 0, buffer.length)) != -1) { 7581 count += n; 7582 } 7583 7584 sBuffer.set(buffer); 7585 return count; 7586 } 7587 7588 public static void closeQuietly(StrictJarFile jarFile) { 7589 if (jarFile != null) { 7590 try { 7591 jarFile.close(); 7592 } catch (Exception ignored) { 7593 } 7594 } 7595 } 7596 7597 public static class PackageParserException extends Exception { 7598 public final int error; 7599 7600 public PackageParserException(int error, String detailMessage) { 7601 super(detailMessage); 7602 this.error = error; 7603 } 7604 7605 public PackageParserException(int error, String detailMessage, Throwable throwable) { 7606 super(detailMessage, throwable); 7607 this.error = error; 7608 } 7609 } 7610 } 7611