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