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