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