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