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