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