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