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.areExactMatch(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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1460 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.areEffectiveMatch(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.areExactMatch(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.areExactMatch(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.areExactMatch() because order matters with the past signing certs 6681 if (!Arrays.equals(pastSigningCertificates, that.pastSigningCertificates)) { 6682 return false; 6683 } 6684 // The capabilities for the past signing certs must match as well. 6685 for (int i = 0; i < pastSigningCertificates.length; i++) { 6686 if (pastSigningCertificates[i].getFlags() 6687 != that.pastSigningCertificates[i].getFlags()) { 6688 return false; 6689 } 6690 } 6691 return true; 6692 } 6693 6694 @Override hashCode()6695 public int hashCode() { 6696 int result = +Arrays.hashCode(signatures); 6697 result = 31 * result + signatureSchemeVersion; 6698 result = 31 * result + (publicKeys != null ? publicKeys.hashCode() : 0); 6699 result = 31 * result + Arrays.hashCode(pastSigningCertificates); 6700 return result; 6701 } 6702 6703 /** 6704 * Builder of {@code SigningDetails} instances. 6705 */ 6706 public static class Builder { 6707 private Signature[] mSignatures; 6708 private int mSignatureSchemeVersion = SignatureSchemeVersion.UNKNOWN; 6709 private Signature[] mPastSigningCertificates; 6710 6711 @UnsupportedAppUsage Builder()6712 public Builder() { 6713 } 6714 6715 /** get signing certificates used to sign the current APK */ 6716 @UnsupportedAppUsage setSignatures(Signature[] signatures)6717 public Builder setSignatures(Signature[] signatures) { 6718 mSignatures = signatures; 6719 return this; 6720 } 6721 6722 /** set the signature scheme version used to sign the APK */ 6723 @UnsupportedAppUsage setSignatureSchemeVersion(int signatureSchemeVersion)6724 public Builder setSignatureSchemeVersion(int signatureSchemeVersion) { 6725 mSignatureSchemeVersion = signatureSchemeVersion; 6726 return this; 6727 } 6728 6729 /** set the signing certificates by which the APK proved it can be authenticated */ 6730 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setPastSigningCertificates(Signature[] pastSigningCertificates)6731 public Builder setPastSigningCertificates(Signature[] pastSigningCertificates) { 6732 mPastSigningCertificates = pastSigningCertificates; 6733 return this; 6734 } 6735 checkInvariants()6736 private void checkInvariants() { 6737 // must have signatures and scheme version set 6738 if (mSignatures == null) { 6739 throw new IllegalStateException("SigningDetails requires the current signing" 6740 + " certificates."); 6741 } 6742 } 6743 /** build a {@code SigningDetails} object */ 6744 @UnsupportedAppUsage build()6745 public SigningDetails build() 6746 throws CertificateException { 6747 checkInvariants(); 6748 return new SigningDetails(mSignatures, mSignatureSchemeVersion, 6749 mPastSigningCertificates); 6750 } 6751 } 6752 } 6753 6754 /** 6755 * Representation of a full package parsed from APK files on disk. A package 6756 * consists of a single base APK, and zero or more split APKs. 6757 * 6758 * Deprecated internally. Use AndroidPackage instead. 6759 */ 6760 public final static class Package implements Parcelable { 6761 6762 @UnsupportedAppUsage 6763 public String packageName; 6764 6765 // The package name declared in the manifest as the package can be 6766 // renamed, for example static shared libs use synthetic package names. 6767 public String manifestPackageName; 6768 6769 /** Names of any split APKs, ordered by parsed splitName */ 6770 public String[] splitNames; 6771 6772 // TODO: work towards making these paths invariant 6773 6774 public String volumeUuid; 6775 6776 /** 6777 * Path where this package was found on disk. For monolithic packages 6778 * this is path to single base APK file; for cluster packages this is 6779 * path to the cluster directory. 6780 */ 6781 public String codePath; 6782 6783 /** Path of base APK */ 6784 public String baseCodePath; 6785 /** Paths of any split APKs, ordered by parsed splitName */ 6786 public String[] splitCodePaths; 6787 6788 /** Revision code of base APK */ 6789 public int baseRevisionCode; 6790 /** Revision codes of any split APKs, ordered by parsed splitName */ 6791 public int[] splitRevisionCodes; 6792 6793 /** Flags of any split APKs; ordered by parsed splitName */ 6794 public int[] splitFlags; 6795 6796 /** 6797 * Private flags of any split APKs; ordered by parsed splitName. 6798 * 6799 * {@hide} 6800 */ 6801 public int[] splitPrivateFlags; 6802 6803 public boolean baseHardwareAccelerated; 6804 6805 // For now we only support one application per package. 6806 @UnsupportedAppUsage 6807 public ApplicationInfo applicationInfo = new ApplicationInfo(); 6808 6809 @UnsupportedAppUsage 6810 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0); 6811 @UnsupportedAppUsage 6812 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0); 6813 @UnsupportedAppUsage 6814 public final ArrayList<Activity> activities = new ArrayList<Activity>(0); 6815 @UnsupportedAppUsage 6816 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0); 6817 @UnsupportedAppUsage 6818 public final ArrayList<Provider> providers = new ArrayList<Provider>(0); 6819 @UnsupportedAppUsage 6820 public final ArrayList<Service> services = new ArrayList<Service>(0); 6821 @UnsupportedAppUsage 6822 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0); 6823 6824 @UnsupportedAppUsage 6825 public final ArrayList<String> requestedPermissions = new ArrayList<String>(); 6826 6827 /** Permissions requested but not in the manifest. */ 6828 public final ArrayList<String> implicitPermissions = new ArrayList<>(); 6829 6830 @UnsupportedAppUsage 6831 public ArrayList<String> protectedBroadcasts; 6832 6833 public Package parentPackage; 6834 public ArrayList<Package> childPackages; 6835 6836 public String staticSharedLibName = null; 6837 public long staticSharedLibVersion = 0; 6838 public ArrayList<String> libraryNames = null; 6839 @UnsupportedAppUsage 6840 public ArrayList<String> usesLibraries = null; 6841 public ArrayList<String> usesStaticLibraries = null; 6842 public long[] usesStaticLibrariesVersions = null; 6843 public String[][] usesStaticLibrariesCertDigests = null; 6844 @UnsupportedAppUsage 6845 public ArrayList<String> usesOptionalLibraries = null; 6846 @UnsupportedAppUsage 6847 public String[] usesLibraryFiles = null; 6848 public ArrayList<SharedLibraryInfo> usesLibraryInfos = null; 6849 6850 public ArrayList<ActivityIntentInfo> preferredActivityFilters = null; 6851 6852 public ArrayList<String> mOriginalPackages = null; 6853 public String mRealPackage = null; 6854 public ArrayList<String> mAdoptPermissions = null; 6855 6856 // We store the application meta-data independently to avoid multiple unwanted references 6857 @UnsupportedAppUsage 6858 public Bundle mAppMetaData = null; 6859 6860 // The version code declared for this package. 6861 @UnsupportedAppUsage 6862 public int mVersionCode; 6863 6864 // The major version code declared for this package. 6865 public int mVersionCodeMajor; 6866 6867 // Return long containing mVersionCode and mVersionCodeMajor. getLongVersionCode()6868 public long getLongVersionCode() { 6869 return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode); 6870 } 6871 6872 // The version name declared for this package. 6873 @UnsupportedAppUsage 6874 public String mVersionName; 6875 6876 // The shared user id that this package wants to use. 6877 @UnsupportedAppUsage 6878 public String mSharedUserId; 6879 6880 // The shared user label that this package wants to use. 6881 @UnsupportedAppUsage 6882 public int mSharedUserLabel; 6883 6884 // Signatures that were read from the package. 6885 @UnsupportedAppUsage 6886 @NonNull public SigningDetails mSigningDetails = SigningDetails.UNKNOWN; 6887 6888 // For use by package manager service for quick lookup of 6889 // preferred up order. 6890 @UnsupportedAppUsage 6891 public int mPreferredOrder = 0; 6892 6893 // For use by package manager to keep track of when a package was last used. 6894 public long[] mLastPackageUsageTimeInMills = 6895 new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT]; 6896 6897 // // User set enabled state. 6898 // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; 6899 // 6900 // // Whether the package has been stopped. 6901 // public boolean mSetStopped = false; 6902 6903 // Additional data supplied by callers. 6904 @UnsupportedAppUsage 6905 public Object mExtras; 6906 6907 // Applications hardware preferences 6908 @UnsupportedAppUsage 6909 public ArrayList<ConfigurationInfo> configPreferences = null; 6910 6911 // Applications requested features 6912 @UnsupportedAppUsage 6913 public ArrayList<FeatureInfo> reqFeatures = null; 6914 6915 // Applications requested feature groups 6916 public ArrayList<FeatureGroupInfo> featureGroups = null; 6917 6918 @UnsupportedAppUsage 6919 public int installLocation; 6920 6921 public boolean coreApp; 6922 6923 /* An app that's required for all users and cannot be uninstalled for a user */ 6924 public boolean mRequiredForAllUsers; 6925 6926 /* The restricted account authenticator type that is used by this application */ 6927 public String mRestrictedAccountType; 6928 6929 /* The required account type without which this application will not function */ 6930 public String mRequiredAccountType; 6931 6932 public String mOverlayTarget; 6933 public String mOverlayTargetName; 6934 public String mOverlayCategory; 6935 public int mOverlayPriority; 6936 public boolean mOverlayIsStatic; 6937 6938 public int mCompileSdkVersion; 6939 public String mCompileSdkVersionCodename; 6940 6941 /** 6942 * Data used to feed the KeySetManagerService 6943 */ 6944 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 6945 public ArraySet<String> mUpgradeKeySets; 6946 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 6947 public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping; 6948 6949 /** 6950 * The install time abi override for this package, if any. 6951 * 6952 * TODO: This seems like a horrible place to put the abiOverride because 6953 * this isn't something the packageParser parsers. However, this fits in with 6954 * the rest of the PackageManager where package scanning randomly pushes 6955 * and prods fields out of {@code this.applicationInfo}. 6956 */ 6957 public String cpuAbiOverride; 6958 /** 6959 * The install time abi override to choose 32bit abi's when multiple abi's 6960 * are present. This is only meaningfull for multiarch applications. 6961 * The use32bitAbi attribute is ignored if cpuAbiOverride is also set. 6962 */ 6963 public boolean use32bitAbi; 6964 6965 public byte[] restrictUpdateHash; 6966 6967 /** Set if the app or any of its components are visible to instant applications. */ 6968 public boolean visibleToInstantApps; 6969 /** Whether or not the package is a stub and must be replaced by the full version. */ 6970 public boolean isStub; 6971 6972 @UnsupportedAppUsage Package(String packageName)6973 public Package(String packageName) { 6974 this.packageName = packageName; 6975 this.manifestPackageName = packageName; 6976 applicationInfo.packageName = packageName; 6977 applicationInfo.uid = -1; 6978 } 6979 setApplicationVolumeUuid(String volumeUuid)6980 public void setApplicationVolumeUuid(String volumeUuid) { 6981 final UUID storageUuid = StorageManager.convert(volumeUuid); 6982 this.applicationInfo.volumeUuid = volumeUuid; 6983 this.applicationInfo.storageUuid = storageUuid; 6984 if (childPackages != null) { 6985 final int packageCount = childPackages.size(); 6986 for (int i = 0; i < packageCount; i++) { 6987 childPackages.get(i).applicationInfo.volumeUuid = volumeUuid; 6988 childPackages.get(i).applicationInfo.storageUuid = storageUuid; 6989 } 6990 } 6991 } 6992 setApplicationInfoCodePath(String codePath)6993 public void setApplicationInfoCodePath(String codePath) { 6994 this.applicationInfo.setCodePath(codePath); 6995 if (childPackages != null) { 6996 final int packageCount = childPackages.size(); 6997 for (int i = 0; i < packageCount; i++) { 6998 childPackages.get(i).applicationInfo.setCodePath(codePath); 6999 } 7000 } 7001 } 7002 7003 /** @deprecated Forward locked apps no longer supported. Resource path not needed. */ 7004 @Deprecated setApplicationInfoResourcePath(String resourcePath)7005 public void setApplicationInfoResourcePath(String resourcePath) { 7006 this.applicationInfo.setResourcePath(resourcePath); 7007 if (childPackages != null) { 7008 final int packageCount = childPackages.size(); 7009 for (int i = 0; i < packageCount; i++) { 7010 childPackages.get(i).applicationInfo.setResourcePath(resourcePath); 7011 } 7012 } 7013 } 7014 7015 /** @deprecated Forward locked apps no longer supported. Resource path not needed. */ 7016 @Deprecated setApplicationInfoBaseResourcePath(String resourcePath)7017 public void setApplicationInfoBaseResourcePath(String resourcePath) { 7018 this.applicationInfo.setBaseResourcePath(resourcePath); 7019 if (childPackages != null) { 7020 final int packageCount = childPackages.size(); 7021 for (int i = 0; i < packageCount; i++) { 7022 childPackages.get(i).applicationInfo.setBaseResourcePath(resourcePath); 7023 } 7024 } 7025 } 7026 setApplicationInfoBaseCodePath(String baseCodePath)7027 public void setApplicationInfoBaseCodePath(String baseCodePath) { 7028 this.applicationInfo.setBaseCodePath(baseCodePath); 7029 if (childPackages != null) { 7030 final int packageCount = childPackages.size(); 7031 for (int i = 0; i < packageCount; i++) { 7032 childPackages.get(i).applicationInfo.setBaseCodePath(baseCodePath); 7033 } 7034 } 7035 } 7036 getChildPackageNames()7037 public List<String> getChildPackageNames() { 7038 if (childPackages == null) { 7039 return null; 7040 } 7041 final int childCount = childPackages.size(); 7042 final List<String> childPackageNames = new ArrayList<>(childCount); 7043 for (int i = 0; i < childCount; i++) { 7044 String childPackageName = childPackages.get(i).packageName; 7045 childPackageNames.add(childPackageName); 7046 } 7047 return childPackageNames; 7048 } 7049 hasChildPackage(String packageName)7050 public boolean hasChildPackage(String packageName) { 7051 final int childCount = (childPackages != null) ? childPackages.size() : 0; 7052 for (int i = 0; i < childCount; i++) { 7053 if (childPackages.get(i).packageName.equals(packageName)) { 7054 return true; 7055 } 7056 } 7057 return false; 7058 } 7059 setApplicationInfoSplitCodePaths(String[] splitCodePaths)7060 public void setApplicationInfoSplitCodePaths(String[] splitCodePaths) { 7061 this.applicationInfo.setSplitCodePaths(splitCodePaths); 7062 // Children have no splits 7063 } 7064 7065 /** @deprecated Forward locked apps no longer supported. Resource path not needed. */ 7066 @Deprecated setApplicationInfoSplitResourcePaths(String[] resroucePaths)7067 public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) { 7068 this.applicationInfo.setSplitResourcePaths(resroucePaths); 7069 // Children have no splits 7070 } 7071 setSplitCodePaths(String[] codePaths)7072 public void setSplitCodePaths(String[] codePaths) { 7073 this.splitCodePaths = codePaths; 7074 } 7075 setCodePath(String codePath)7076 public void setCodePath(String codePath) { 7077 this.codePath = codePath; 7078 if (childPackages != null) { 7079 final int packageCount = childPackages.size(); 7080 for (int i = 0; i < packageCount; i++) { 7081 childPackages.get(i).codePath = codePath; 7082 } 7083 } 7084 } 7085 setBaseCodePath(String baseCodePath)7086 public void setBaseCodePath(String baseCodePath) { 7087 this.baseCodePath = baseCodePath; 7088 if (childPackages != null) { 7089 final int packageCount = childPackages.size(); 7090 for (int i = 0; i < packageCount; i++) { 7091 childPackages.get(i).baseCodePath = baseCodePath; 7092 } 7093 } 7094 } 7095 7096 /** Sets signing details on the package and any of its children. */ setSigningDetails(@onNull SigningDetails signingDetails)7097 public void setSigningDetails(@NonNull SigningDetails signingDetails) { 7098 mSigningDetails = signingDetails; 7099 if (childPackages != null) { 7100 final int packageCount = childPackages.size(); 7101 for (int i = 0; i < packageCount; i++) { 7102 childPackages.get(i).mSigningDetails = signingDetails; 7103 } 7104 } 7105 } 7106 setVolumeUuid(String volumeUuid)7107 public void setVolumeUuid(String volumeUuid) { 7108 this.volumeUuid = volumeUuid; 7109 if (childPackages != null) { 7110 final int packageCount = childPackages.size(); 7111 for (int i = 0; i < packageCount; i++) { 7112 childPackages.get(i).volumeUuid = volumeUuid; 7113 } 7114 } 7115 } 7116 setApplicationInfoFlags(int mask, int flags)7117 public void setApplicationInfoFlags(int mask, int flags) { 7118 applicationInfo.flags = (applicationInfo.flags & ~mask) | (mask & flags); 7119 if (childPackages != null) { 7120 final int packageCount = childPackages.size(); 7121 for (int i = 0; i < packageCount; i++) { 7122 childPackages.get(i).applicationInfo.flags = 7123 (applicationInfo.flags & ~mask) | (mask & flags); 7124 } 7125 } 7126 } 7127 setUse32bitAbi(boolean use32bitAbi)7128 public void setUse32bitAbi(boolean use32bitAbi) { 7129 this.use32bitAbi = use32bitAbi; 7130 if (childPackages != null) { 7131 final int packageCount = childPackages.size(); 7132 for (int i = 0; i < packageCount; i++) { 7133 childPackages.get(i).use32bitAbi = use32bitAbi; 7134 } 7135 } 7136 } 7137 isLibrary()7138 public boolean isLibrary() { 7139 return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames); 7140 } 7141 getAllCodePaths()7142 public List<String> getAllCodePaths() { 7143 ArrayList<String> paths = new ArrayList<>(); 7144 paths.add(baseCodePath); 7145 if (!ArrayUtils.isEmpty(splitCodePaths)) { 7146 Collections.addAll(paths, splitCodePaths); 7147 } 7148 return paths; 7149 } 7150 7151 /** 7152 * Filtered set of {@link #getAllCodePaths()} that excludes 7153 * resource-only APKs. 7154 */ getAllCodePathsExcludingResourceOnly()7155 public List<String> getAllCodePathsExcludingResourceOnly() { 7156 ArrayList<String> paths = new ArrayList<>(); 7157 if ((applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { 7158 paths.add(baseCodePath); 7159 } 7160 if (!ArrayUtils.isEmpty(splitCodePaths)) { 7161 for (int i = 0; i < splitCodePaths.length; i++) { 7162 if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { 7163 paths.add(splitCodePaths[i]); 7164 } 7165 } 7166 } 7167 return paths; 7168 } 7169 7170 @UnsupportedAppUsage setPackageName(String newName)7171 public void setPackageName(String newName) { 7172 packageName = newName; 7173 applicationInfo.packageName = newName; 7174 for (int i=permissions.size()-1; i>=0; i--) { 7175 permissions.get(i).setPackageName(newName); 7176 } 7177 for (int i=permissionGroups.size()-1; i>=0; i--) { 7178 permissionGroups.get(i).setPackageName(newName); 7179 } 7180 for (int i=activities.size()-1; i>=0; i--) { 7181 activities.get(i).setPackageName(newName); 7182 } 7183 for (int i=receivers.size()-1; i>=0; i--) { 7184 receivers.get(i).setPackageName(newName); 7185 } 7186 for (int i=providers.size()-1; i>=0; i--) { 7187 providers.get(i).setPackageName(newName); 7188 } 7189 for (int i=services.size()-1; i>=0; i--) { 7190 services.get(i).setPackageName(newName); 7191 } 7192 for (int i=instrumentation.size()-1; i>=0; i--) { 7193 instrumentation.get(i).setPackageName(newName); 7194 } 7195 } 7196 hasComponentClassName(String name)7197 public boolean hasComponentClassName(String name) { 7198 for (int i=activities.size()-1; i>=0; i--) { 7199 if (name.equals(activities.get(i).className)) { 7200 return true; 7201 } 7202 } 7203 for (int i=receivers.size()-1; i>=0; i--) { 7204 if (name.equals(receivers.get(i).className)) { 7205 return true; 7206 } 7207 } 7208 for (int i=providers.size()-1; i>=0; i--) { 7209 if (name.equals(providers.get(i).className)) { 7210 return true; 7211 } 7212 } 7213 for (int i=services.size()-1; i>=0; i--) { 7214 if (name.equals(services.get(i).className)) { 7215 return true; 7216 } 7217 } 7218 for (int i=instrumentation.size()-1; i>=0; i--) { 7219 if (name.equals(instrumentation.get(i).className)) { 7220 return true; 7221 } 7222 } 7223 return false; 7224 } 7225 7226 /** @hide */ isExternal()7227 public boolean isExternal() { 7228 return applicationInfo.isExternal(); 7229 } 7230 7231 /** @hide */ isForwardLocked()7232 public boolean isForwardLocked() { 7233 return false; 7234 } 7235 7236 /** @hide */ isOem()7237 public boolean isOem() { 7238 return applicationInfo.isOem(); 7239 } 7240 7241 /** @hide */ isVendor()7242 public boolean isVendor() { 7243 return applicationInfo.isVendor(); 7244 } 7245 7246 /** @hide */ isProduct()7247 public boolean isProduct() { 7248 return applicationInfo.isProduct(); 7249 } 7250 7251 /** @hide */ isSystemExt()7252 public boolean isSystemExt() { 7253 return applicationInfo.isSystemExt(); 7254 } 7255 7256 /** @hide */ isOdm()7257 public boolean isOdm() { 7258 return applicationInfo.isOdm(); 7259 } 7260 7261 /** @hide */ isPrivileged()7262 public boolean isPrivileged() { 7263 return applicationInfo.isPrivilegedApp(); 7264 } 7265 7266 /** @hide */ isSystem()7267 public boolean isSystem() { 7268 return applicationInfo.isSystemApp(); 7269 } 7270 7271 /** @hide */ isUpdatedSystemApp()7272 public boolean isUpdatedSystemApp() { 7273 return applicationInfo.isUpdatedSystemApp(); 7274 } 7275 7276 /** @hide */ canHaveOatDir()7277 public boolean canHaveOatDir() { 7278 // Nobody should be calling this method ever, but we can't rely on this. 7279 // Thus no logic here and a reasonable return value. 7280 return true; 7281 } 7282 isMatch(int flags)7283 public boolean isMatch(int flags) { 7284 if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { 7285 return isSystem(); 7286 } 7287 return true; 7288 } 7289 getLatestPackageUseTimeInMills()7290 public long getLatestPackageUseTimeInMills() { 7291 long latestUse = 0L; 7292 for (long use : mLastPackageUsageTimeInMills) { 7293 latestUse = Math.max(latestUse, use); 7294 } 7295 return latestUse; 7296 } 7297 getLatestForegroundPackageUseTimeInMills()7298 public long getLatestForegroundPackageUseTimeInMills() { 7299 int[] foregroundReasons = { 7300 PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY, 7301 PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE 7302 }; 7303 7304 long latestUse = 0L; 7305 for (int reason : foregroundReasons) { 7306 latestUse = Math.max(latestUse, mLastPackageUsageTimeInMills[reason]); 7307 } 7308 return latestUse; 7309 } 7310 toString()7311 public String toString() { 7312 return "Package{" 7313 + Integer.toHexString(System.identityHashCode(this)) 7314 + " " + packageName + "}"; 7315 } 7316 7317 @Override describeContents()7318 public int describeContents() { 7319 return 0; 7320 } 7321 Package(Parcel dest)7322 public Package(Parcel dest) { 7323 // We use the boot classloader for all classes that we load. 7324 final ClassLoader boot = Object.class.getClassLoader(); 7325 7326 packageName = dest.readString().intern(); 7327 manifestPackageName = dest.readString(); 7328 splitNames = dest.readStringArray(); 7329 volumeUuid = dest.readString(); 7330 codePath = dest.readString(); 7331 baseCodePath = dest.readString(); 7332 splitCodePaths = dest.readStringArray(); 7333 baseRevisionCode = dest.readInt(); 7334 splitRevisionCodes = dest.createIntArray(); 7335 splitFlags = dest.createIntArray(); 7336 splitPrivateFlags = dest.createIntArray(); 7337 baseHardwareAccelerated = (dest.readInt() == 1); 7338 applicationInfo = dest.readParcelable(boot, android.content.pm.ApplicationInfo.class); 7339 if (applicationInfo.permission != null) { 7340 applicationInfo.permission = applicationInfo.permission.intern(); 7341 } 7342 7343 // We don't serialize the "owner" package and the application info object for each of 7344 // these components, in order to save space and to avoid circular dependencies while 7345 // serialization. We need to fix them all up here. 7346 dest.readParcelableList(permissions, boot, android.content.pm.PackageParser.Permission.class); 7347 fixupOwner(permissions); 7348 dest.readParcelableList(permissionGroups, boot, android.content.pm.PackageParser.PermissionGroup.class); 7349 fixupOwner(permissionGroups); 7350 dest.readParcelableList(activities, boot, android.content.pm.PackageParser.Activity.class); 7351 fixupOwner(activities); 7352 dest.readParcelableList(receivers, boot, android.content.pm.PackageParser.Activity.class); 7353 fixupOwner(receivers); 7354 dest.readParcelableList(providers, boot, android.content.pm.PackageParser.Provider.class); 7355 fixupOwner(providers); 7356 dest.readParcelableList(services, boot, android.content.pm.PackageParser.Service.class); 7357 fixupOwner(services); 7358 dest.readParcelableList(instrumentation, boot, android.content.pm.PackageParser.Instrumentation.class); 7359 fixupOwner(instrumentation); 7360 7361 dest.readStringList(requestedPermissions); 7362 internStringArrayList(requestedPermissions); 7363 dest.readStringList(implicitPermissions); 7364 internStringArrayList(implicitPermissions); 7365 protectedBroadcasts = dest.createStringArrayList(); 7366 internStringArrayList(protectedBroadcasts); 7367 7368 parentPackage = dest.readParcelable(boot, android.content.pm.PackageParser.Package.class); 7369 7370 childPackages = new ArrayList<>(); 7371 dest.readParcelableList(childPackages, boot, android.content.pm.PackageParser.Package.class); 7372 if (childPackages.size() == 0) { 7373 childPackages = null; 7374 } 7375 7376 staticSharedLibName = dest.readString(); 7377 if (staticSharedLibName != null) { 7378 staticSharedLibName = staticSharedLibName.intern(); 7379 } 7380 staticSharedLibVersion = dest.readLong(); 7381 libraryNames = dest.createStringArrayList(); 7382 internStringArrayList(libraryNames); 7383 usesLibraries = dest.createStringArrayList(); 7384 internStringArrayList(usesLibraries); 7385 usesOptionalLibraries = dest.createStringArrayList(); 7386 internStringArrayList(usesOptionalLibraries); 7387 usesLibraryFiles = dest.readStringArray(); 7388 7389 usesLibraryInfos = dest.createTypedArrayList(SharedLibraryInfo.CREATOR); 7390 7391 final int libCount = dest.readInt(); 7392 if (libCount > 0) { 7393 usesStaticLibraries = new ArrayList<>(libCount); 7394 dest.readStringList(usesStaticLibraries); 7395 internStringArrayList(usesStaticLibraries); 7396 usesStaticLibrariesVersions = new long[libCount]; 7397 dest.readLongArray(usesStaticLibrariesVersions); 7398 usesStaticLibrariesCertDigests = new String[libCount][]; 7399 for (int i = 0; i < libCount; i++) { 7400 usesStaticLibrariesCertDigests[i] = dest.createStringArray(); 7401 } 7402 } 7403 7404 preferredActivityFilters = new ArrayList<>(); 7405 dest.readParcelableList(preferredActivityFilters, boot, android.content.pm.PackageParser.ActivityIntentInfo.class); 7406 if (preferredActivityFilters.size() == 0) { 7407 preferredActivityFilters = null; 7408 } 7409 7410 mOriginalPackages = dest.createStringArrayList(); 7411 mRealPackage = dest.readString(); 7412 mAdoptPermissions = dest.createStringArrayList(); 7413 mAppMetaData = dest.readBundle(); 7414 mVersionCode = dest.readInt(); 7415 mVersionCodeMajor = dest.readInt(); 7416 mVersionName = dest.readString(); 7417 if (mVersionName != null) { 7418 mVersionName = mVersionName.intern(); 7419 } 7420 mSharedUserId = dest.readString(); 7421 if (mSharedUserId != null) { 7422 mSharedUserId = mSharedUserId.intern(); 7423 } 7424 mSharedUserLabel = dest.readInt(); 7425 7426 mSigningDetails = dest.readParcelable(boot, android.content.pm.PackageParser.SigningDetails.class); 7427 7428 mPreferredOrder = dest.readInt(); 7429 7430 // long[] packageUsageTimeMillis is not persisted because it isn't information that 7431 // is parsed from the APK. 7432 7433 // Object mExtras is not persisted because it is not information that is read from 7434 // the APK, rather, it is supplied by callers. 7435 7436 7437 configPreferences = new ArrayList<>(); 7438 dest.readParcelableList(configPreferences, boot, android.content.pm.ConfigurationInfo.class); 7439 if (configPreferences.size() == 0) { 7440 configPreferences = null; 7441 } 7442 7443 reqFeatures = new ArrayList<>(); 7444 dest.readParcelableList(reqFeatures, boot, android.content.pm.FeatureInfo.class); 7445 if (reqFeatures.size() == 0) { 7446 reqFeatures = null; 7447 } 7448 7449 featureGroups = new ArrayList<>(); 7450 dest.readParcelableList(featureGroups, boot, android.content.pm.FeatureGroupInfo.class); 7451 if (featureGroups.size() == 0) { 7452 featureGroups = null; 7453 } 7454 7455 installLocation = dest.readInt(); 7456 coreApp = (dest.readInt() == 1); 7457 mRequiredForAllUsers = (dest.readInt() == 1); 7458 mRestrictedAccountType = dest.readString(); 7459 mRequiredAccountType = dest.readString(); 7460 mOverlayTarget = dest.readString(); 7461 mOverlayTargetName = dest.readString(); 7462 mOverlayCategory = dest.readString(); 7463 mOverlayPriority = dest.readInt(); 7464 mOverlayIsStatic = (dest.readInt() == 1); 7465 mCompileSdkVersion = dest.readInt(); 7466 mCompileSdkVersionCodename = dest.readString(); 7467 mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot); 7468 7469 mKeySetMapping = readKeySetMapping(dest); 7470 7471 cpuAbiOverride = dest.readString(); 7472 use32bitAbi = (dest.readInt() == 1); 7473 restrictUpdateHash = dest.createByteArray(); 7474 visibleToInstantApps = dest.readInt() == 1; 7475 } 7476 internStringArrayList(List<String> list)7477 private static void internStringArrayList(List<String> list) { 7478 if (list != null) { 7479 final int N = list.size(); 7480 for (int i = 0; i < N; ++i) { 7481 list.set(i, list.get(i).intern()); 7482 } 7483 } 7484 } 7485 7486 /** 7487 * Sets the package owner and the the {@code applicationInfo} for every component 7488 * owner by this package. 7489 */ fixupOwner(List<? extends Component<?>> list)7490 public void fixupOwner(List<? extends Component<?>> list) { 7491 if (list != null) { 7492 for (Component<?> c : list) { 7493 c.owner = this; 7494 if (c instanceof Activity) { 7495 ((Activity) c).info.applicationInfo = this.applicationInfo; 7496 } else if (c instanceof Service) { 7497 ((Service) c).info.applicationInfo = this.applicationInfo; 7498 } else if (c instanceof Provider) { 7499 ((Provider) c).info.applicationInfo = this.applicationInfo; 7500 } 7501 } 7502 } 7503 } 7504 7505 @Override writeToParcel(Parcel dest, int flags)7506 public void writeToParcel(Parcel dest, int flags) { 7507 dest.writeString(packageName); 7508 dest.writeString(manifestPackageName); 7509 dest.writeStringArray(splitNames); 7510 dest.writeString(volumeUuid); 7511 dest.writeString(codePath); 7512 dest.writeString(baseCodePath); 7513 dest.writeStringArray(splitCodePaths); 7514 dest.writeInt(baseRevisionCode); 7515 dest.writeIntArray(splitRevisionCodes); 7516 dest.writeIntArray(splitFlags); 7517 dest.writeIntArray(splitPrivateFlags); 7518 dest.writeInt(baseHardwareAccelerated ? 1 : 0); 7519 dest.writeParcelable(applicationInfo, flags); 7520 7521 dest.writeParcelableList(permissions, flags); 7522 dest.writeParcelableList(permissionGroups, flags); 7523 dest.writeParcelableList(activities, flags); 7524 dest.writeParcelableList(receivers, flags); 7525 dest.writeParcelableList(providers, flags); 7526 dest.writeParcelableList(services, flags); 7527 dest.writeParcelableList(instrumentation, flags); 7528 7529 dest.writeStringList(requestedPermissions); 7530 dest.writeStringList(implicitPermissions); 7531 dest.writeStringList(protectedBroadcasts); 7532 7533 // TODO: This doesn't work: b/64295061 7534 dest.writeParcelable(parentPackage, flags); 7535 dest.writeParcelableList(childPackages, flags); 7536 7537 dest.writeString(staticSharedLibName); 7538 dest.writeLong(staticSharedLibVersion); 7539 dest.writeStringList(libraryNames); 7540 dest.writeStringList(usesLibraries); 7541 dest.writeStringList(usesOptionalLibraries); 7542 dest.writeStringArray(usesLibraryFiles); 7543 dest.writeTypedList(usesLibraryInfos); 7544 7545 if (ArrayUtils.isEmpty(usesStaticLibraries)) { 7546 dest.writeInt(-1); 7547 } else { 7548 dest.writeInt(usesStaticLibraries.size()); 7549 dest.writeStringList(usesStaticLibraries); 7550 dest.writeLongArray(usesStaticLibrariesVersions); 7551 for (String[] usesStaticLibrariesCertDigest : usesStaticLibrariesCertDigests) { 7552 dest.writeStringArray(usesStaticLibrariesCertDigest); 7553 } 7554 } 7555 7556 dest.writeParcelableList(preferredActivityFilters, flags); 7557 7558 dest.writeStringList(mOriginalPackages); 7559 dest.writeString(mRealPackage); 7560 dest.writeStringList(mAdoptPermissions); 7561 dest.writeBundle(mAppMetaData); 7562 dest.writeInt(mVersionCode); 7563 dest.writeInt(mVersionCodeMajor); 7564 dest.writeString(mVersionName); 7565 dest.writeString(mSharedUserId); 7566 dest.writeInt(mSharedUserLabel); 7567 7568 dest.writeParcelable(mSigningDetails, flags); 7569 7570 dest.writeInt(mPreferredOrder); 7571 7572 // long[] packageUsageTimeMillis is not persisted because it isn't information that 7573 // is parsed from the APK. 7574 7575 // Object mExtras is not persisted because it is not information that is read from 7576 // the APK, rather, it is supplied by callers. 7577 7578 dest.writeParcelableList(configPreferences, flags); 7579 dest.writeParcelableList(reqFeatures, flags); 7580 dest.writeParcelableList(featureGroups, flags); 7581 7582 dest.writeInt(installLocation); 7583 dest.writeInt(coreApp ? 1 : 0); 7584 dest.writeInt(mRequiredForAllUsers ? 1 : 0); 7585 dest.writeString(mRestrictedAccountType); 7586 dest.writeString(mRequiredAccountType); 7587 dest.writeString(mOverlayTarget); 7588 dest.writeString(mOverlayTargetName); 7589 dest.writeString(mOverlayCategory); 7590 dest.writeInt(mOverlayPriority); 7591 dest.writeInt(mOverlayIsStatic ? 1 : 0); 7592 dest.writeInt(mCompileSdkVersion); 7593 dest.writeString(mCompileSdkVersionCodename); 7594 dest.writeArraySet(mUpgradeKeySets); 7595 writeKeySetMapping(dest, mKeySetMapping); 7596 dest.writeString(cpuAbiOverride); 7597 dest.writeInt(use32bitAbi ? 1 : 0); 7598 dest.writeByteArray(restrictUpdateHash); 7599 dest.writeInt(visibleToInstantApps ? 1 : 0); 7600 } 7601 7602 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Package>() { 7603 public Package createFromParcel(Parcel in) { 7604 return new Package(in); 7605 } 7606 7607 public Package[] newArray(int size) { 7608 return new Package[size]; 7609 } 7610 }; 7611 } 7612 7613 public static abstract class Component<II extends IntentInfo> { 7614 @UnsupportedAppUsage 7615 public final ArrayList<II> intents; 7616 @UnsupportedAppUsage 7617 public final String className; 7618 7619 @UnsupportedAppUsage 7620 public Bundle metaData; 7621 @UnsupportedAppUsage 7622 public Package owner; 7623 /** The order of this component in relation to its peers */ 7624 public int order; 7625 7626 ComponentName componentName; 7627 String componentShortName; 7628 Component(Package owner, ArrayList<II> intents, String className)7629 public Component(Package owner, ArrayList<II> intents, String className) { 7630 this.owner = owner; 7631 this.intents = intents; 7632 this.className = className; 7633 } 7634 Component(Package owner)7635 public Component(Package owner) { 7636 this.owner = owner; 7637 this.intents = null; 7638 this.className = null; 7639 } 7640 Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo)7641 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) { 7642 owner = args.owner; 7643 intents = new ArrayList<II>(0); 7644 if (parsePackageItemInfo(args.owner, outInfo, args.outError, args.tag, args.sa, 7645 true /*nameRequired*/, args.nameRes, args.labelRes, args.iconRes, 7646 args.roundIconRes, args.logoRes, args.bannerRes)) { 7647 className = outInfo.name; 7648 } else { 7649 className = null; 7650 } 7651 } 7652 Component(final ParseComponentArgs args, final ComponentInfo outInfo)7653 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) { 7654 this(args, (PackageItemInfo)outInfo); 7655 if (args.outError[0] != null) { 7656 return; 7657 } 7658 7659 if (args.processRes != 0) { 7660 CharSequence pname; 7661 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 7662 pname = args.sa.getNonConfigurationString(args.processRes, 7663 Configuration.NATIVE_CONFIG_VERSION); 7664 } else { 7665 // Some older apps have been seen to use a resource reference 7666 // here that on older builds was ignored (with a warning). We 7667 // need to continue to do this for them so they don't break. 7668 pname = args.sa.getNonResourceString(args.processRes); 7669 } 7670 outInfo.processName = buildProcessName(owner.applicationInfo.packageName, 7671 owner.applicationInfo.processName, pname, 7672 args.flags, args.sepProcesses, args.outError); 7673 } 7674 7675 if (args.descriptionRes != 0) { 7676 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0); 7677 } 7678 7679 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true); 7680 } 7681 Component(Component<II> clone)7682 public Component(Component<II> clone) { 7683 owner = clone.owner; 7684 intents = clone.intents; 7685 className = clone.className; 7686 componentName = clone.componentName; 7687 componentShortName = clone.componentShortName; 7688 } 7689 7690 @UnsupportedAppUsage getComponentName()7691 public ComponentName getComponentName() { 7692 if (componentName != null) { 7693 return componentName; 7694 } 7695 if (className != null) { 7696 componentName = new ComponentName(owner.applicationInfo.packageName, 7697 className); 7698 } 7699 return componentName; 7700 } 7701 Component(Parcel in)7702 protected Component(Parcel in) { 7703 className = in.readString(); 7704 metaData = in.readBundle(); 7705 intents = createIntentsList(in); 7706 7707 owner = null; 7708 } 7709 writeToParcel(Parcel dest, int flags)7710 protected void writeToParcel(Parcel dest, int flags) { 7711 dest.writeString(className); 7712 dest.writeBundle(metaData); 7713 7714 writeIntentsList(intents, dest, flags); 7715 } 7716 7717 /** 7718 * <p> 7719 * Implementation note: The serialized form for the intent list also contains the name 7720 * of the concrete class that's stored in the list, and assumes that every element of the 7721 * list is of the same type. This is very similar to the original parcelable mechanism. 7722 * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable 7723 * and is public API. It also declares Parcelable related methods as final which means 7724 * we can't extend them. The approach of using composition instead of inheritance leads to 7725 * a large set of cascading changes in the PackageManagerService, which seem undesirable. 7726 * 7727 * <p> 7728 * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up 7729 * to make sure their owner fields are consistent. See {@code fixupOwner}. 7730 */ writeIntentsList(ArrayList<? extends IntentInfo> list, Parcel out, int flags)7731 private static void writeIntentsList(ArrayList<? extends IntentInfo> list, Parcel out, 7732 int flags) { 7733 if (list == null) { 7734 out.writeInt(-1); 7735 return; 7736 } 7737 7738 final int N = list.size(); 7739 out.writeInt(N); 7740 7741 // Don't bother writing the component name if the list is empty. 7742 if (N > 0) { 7743 IntentInfo info = list.get(0); 7744 out.writeString(info.getClass().getName()); 7745 7746 for (int i = 0; i < N;i++) { 7747 list.get(i).writeIntentInfoToParcel(out, flags); 7748 } 7749 } 7750 } 7751 createIntentsList(Parcel in)7752 private static <T extends IntentInfo> ArrayList<T> createIntentsList(Parcel in) { 7753 int N = in.readInt(); 7754 if (N == -1) { 7755 return null; 7756 } 7757 7758 if (N == 0) { 7759 return new ArrayList<>(0); 7760 } 7761 7762 String componentName = in.readString(); 7763 final ArrayList<T> intentsList; 7764 try { 7765 final Class<T> cls = (Class<T>) Class.forName(componentName); 7766 final Constructor<T> cons = cls.getConstructor(Parcel.class); 7767 7768 intentsList = new ArrayList<>(N); 7769 for (int i = 0; i < N; ++i) { 7770 intentsList.add(cons.newInstance(in)); 7771 } 7772 } catch (ReflectiveOperationException ree) { 7773 throw new AssertionError("Unable to construct intent list for: " + componentName); 7774 } 7775 7776 return intentsList; 7777 } 7778 appendComponentShortName(StringBuilder sb)7779 public void appendComponentShortName(StringBuilder sb) { 7780 ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className); 7781 } 7782 printComponentShortName(PrintWriter pw)7783 public void printComponentShortName(PrintWriter pw) { 7784 ComponentName.printShortString(pw, owner.applicationInfo.packageName, className); 7785 } 7786 setPackageName(String packageName)7787 public void setPackageName(String packageName) { 7788 componentName = null; 7789 componentShortName = null; 7790 } 7791 } 7792 7793 public final static class Permission extends Component<IntentInfo> implements Parcelable { 7794 @UnsupportedAppUsage 7795 public final PermissionInfo info; 7796 @UnsupportedAppUsage 7797 public boolean tree; 7798 @UnsupportedAppUsage 7799 public PermissionGroup group; 7800 7801 /** 7802 * @hide 7803 */ Permission(Package owner, @Nullable String backgroundPermission)7804 public Permission(Package owner, @Nullable String backgroundPermission) { 7805 super(owner); 7806 info = new PermissionInfo(backgroundPermission); 7807 } 7808 7809 @UnsupportedAppUsage Permission(Package _owner, PermissionInfo _info)7810 public Permission(Package _owner, PermissionInfo _info) { 7811 super(_owner); 7812 info = _info; 7813 } 7814 setPackageName(String packageName)7815 public void setPackageName(String packageName) { 7816 super.setPackageName(packageName); 7817 info.packageName = packageName; 7818 } 7819 toString()7820 public String toString() { 7821 return "Permission{" 7822 + Integer.toHexString(System.identityHashCode(this)) 7823 + " " + info.name + "}"; 7824 } 7825 7826 @Override describeContents()7827 public int describeContents() { 7828 return 0; 7829 } 7830 7831 @Override writeToParcel(Parcel dest, int flags)7832 public void writeToParcel(Parcel dest, int flags) { 7833 super.writeToParcel(dest, flags); 7834 dest.writeParcelable(info, flags); 7835 dest.writeInt(tree ? 1 : 0); 7836 dest.writeParcelable(group, flags); 7837 } 7838 7839 /** @hide */ isAppOp()7840 public boolean isAppOp() { 7841 return info.isAppOp(); 7842 } 7843 Permission(Parcel in)7844 private Permission(Parcel in) { 7845 super(in); 7846 final ClassLoader boot = Object.class.getClassLoader(); 7847 info = in.readParcelable(boot, android.content.pm.PermissionInfo.class); 7848 if (info.group != null) { 7849 info.group = info.group.intern(); 7850 } 7851 7852 tree = (in.readInt() == 1); 7853 group = in.readParcelable(boot, android.content.pm.PackageParser.PermissionGroup.class); 7854 } 7855 7856 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Permission>() { 7857 public Permission createFromParcel(Parcel in) { 7858 return new Permission(in); 7859 } 7860 7861 public Permission[] newArray(int size) { 7862 return new Permission[size]; 7863 } 7864 }; 7865 } 7866 7867 public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable { 7868 @UnsupportedAppUsage 7869 public final PermissionGroupInfo info; 7870 PermissionGroup(Package owner, @StringRes int requestDetailResourceId, @StringRes int backgroundRequestResourceId, @StringRes int backgroundRequestDetailResourceId)7871 public PermissionGroup(Package owner, @StringRes int requestDetailResourceId, 7872 @StringRes int backgroundRequestResourceId, 7873 @StringRes int backgroundRequestDetailResourceId) { 7874 super(owner); 7875 info = new PermissionGroupInfo(requestDetailResourceId, backgroundRequestResourceId, 7876 backgroundRequestDetailResourceId); 7877 } 7878 PermissionGroup(Package _owner, PermissionGroupInfo _info)7879 public PermissionGroup(Package _owner, PermissionGroupInfo _info) { 7880 super(_owner); 7881 info = _info; 7882 } 7883 setPackageName(String packageName)7884 public void setPackageName(String packageName) { 7885 super.setPackageName(packageName); 7886 info.packageName = packageName; 7887 } 7888 toString()7889 public String toString() { 7890 return "PermissionGroup{" 7891 + Integer.toHexString(System.identityHashCode(this)) 7892 + " " + info.name + "}"; 7893 } 7894 7895 @Override describeContents()7896 public int describeContents() { 7897 return 0; 7898 } 7899 7900 @Override writeToParcel(Parcel dest, int flags)7901 public void writeToParcel(Parcel dest, int flags) { 7902 super.writeToParcel(dest, flags); 7903 dest.writeParcelable(info, flags); 7904 } 7905 PermissionGroup(Parcel in)7906 private PermissionGroup(Parcel in) { 7907 super(in); 7908 info = in.readParcelable(Object.class.getClassLoader(), android.content.pm.PermissionGroupInfo.class); 7909 } 7910 7911 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<PermissionGroup>() { 7912 public PermissionGroup createFromParcel(Parcel in) { 7913 return new PermissionGroup(in); 7914 } 7915 7916 public PermissionGroup[] newArray(int size) { 7917 return new PermissionGroup[size]; 7918 } 7919 }; 7920 } 7921 copyNeeded(int flags, Package p, FrameworkPackageUserState state, Bundle metaData, int userId)7922 private static boolean copyNeeded(int flags, Package p, 7923 FrameworkPackageUserState state, Bundle metaData, int userId) { 7924 if (userId != UserHandle.USER_SYSTEM) { 7925 // We always need to copy for other users, since we need 7926 // to fix up the uid. 7927 return true; 7928 } 7929 if (state.getEnabledState() != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 7930 boolean enabled = 7931 state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 7932 if (p.applicationInfo.enabled != enabled) { 7933 return true; 7934 } 7935 } 7936 boolean suspended = (p.applicationInfo.flags & FLAG_SUSPENDED) != 0; 7937 if (state.isSuspended() != suspended) { 7938 return true; 7939 } 7940 if (!state.isInstalled() || state.isHidden()) { 7941 return true; 7942 } 7943 if (state.isStopped()) { 7944 return true; 7945 } 7946 if (state.isInstantApp() != p.applicationInfo.isInstantApp()) { 7947 return true; 7948 } 7949 if ((flags & PackageManager.GET_META_DATA) != 0 7950 && (metaData != null || p.mAppMetaData != null)) { 7951 return true; 7952 } 7953 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 7954 && p.usesLibraryFiles != null) { 7955 return true; 7956 } 7957 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 7958 && p.usesLibraryInfos != null) { 7959 return true; 7960 } 7961 if (p.staticSharedLibName != null) { 7962 return true; 7963 } 7964 return false; 7965 } 7966 7967 @UnsupportedAppUsage generateApplicationInfo(Package p, int flags, FrameworkPackageUserState state)7968 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 7969 FrameworkPackageUserState state) { 7970 return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId()); 7971 } 7972 updateApplicationInfo(ApplicationInfo ai, int flags, FrameworkPackageUserState state)7973 private static void updateApplicationInfo(ApplicationInfo ai, int flags, 7974 FrameworkPackageUserState state) { 7975 // CompatibilityMode is global state. 7976 if (!sCompatibilityModeEnabled) { 7977 ai.disableCompatibilityMode(); 7978 } 7979 if (state.isInstalled()) { 7980 ai.flags |= ApplicationInfo.FLAG_INSTALLED; 7981 } else { 7982 ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; 7983 } 7984 if (state.isSuspended()) { 7985 ai.flags |= ApplicationInfo.FLAG_SUSPENDED; 7986 } else { 7987 ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED; 7988 } 7989 if (state.isInstantApp()) { 7990 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT; 7991 } else { 7992 ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT; 7993 } 7994 if (state.isVirtualPreload()) { 7995 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD; 7996 } else { 7997 ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD; 7998 } 7999 if (state.isHidden()) { 8000 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN; 8001 } else { 8002 ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN; 8003 } 8004 if (state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 8005 ai.enabled = true; 8006 } else if (state.getEnabledState() 8007 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { 8008 ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0; 8009 } else if (state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_DISABLED 8010 || state.getEnabledState() 8011 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { 8012 ai.enabled = false; 8013 } 8014 ai.enabledSetting = state.getEnabledState(); 8015 if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { 8016 ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName); 8017 } 8018 ai.seInfoUser = getSeinfoUser(state); 8019 final OverlayPaths overlayPaths = state.getAllOverlayPaths(); 8020 if (overlayPaths != null) { 8021 ai.resourceDirs = overlayPaths.getResourceDirs().toArray(new String[0]); 8022 ai.overlayPaths = overlayPaths.getOverlayPaths().toArray(new String[0]); 8023 } 8024 ai.icon = (sUseRoundIcon && ai.roundIconRes != 0) ? ai.roundIconRes : ai.iconRes; 8025 } 8026 8027 @UnsupportedAppUsage generateApplicationInfo(Package p, int flags, FrameworkPackageUserState state, int userId)8028 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 8029 FrameworkPackageUserState state, int userId) { 8030 if (p == null) return null; 8031 if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) { 8032 return null; 8033 } 8034 if (!copyNeeded(flags, p, state, null, userId) 8035 && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0 8036 || state.getEnabledState() 8037 != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { 8038 // In this case it is safe to directly modify the internal ApplicationInfo state: 8039 // - CompatibilityMode is global state, so will be the same for every call. 8040 // - We only come in to here if the app should reported as installed; this is the 8041 // default state, and we will do a copy otherwise. 8042 // - The enable state will always be reported the same for the application across 8043 // calls; the only exception is for the UNTIL_USED mode, and in that case we will 8044 // be doing a copy. 8045 updateApplicationInfo(p.applicationInfo, flags, state); 8046 return p.applicationInfo; 8047 } 8048 8049 // Make shallow copy so we can store the metadata/libraries safely 8050 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo); 8051 ai.initForUser(userId); 8052 if ((flags & PackageManager.GET_META_DATA) != 0) { 8053 ai.metaData = p.mAppMetaData; 8054 } 8055 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { 8056 ai.sharedLibraryFiles = p.usesLibraryFiles; 8057 ai.sharedLibraryInfos = p.usesLibraryInfos; 8058 } 8059 if (state.isStopped()) { 8060 ai.flags |= ApplicationInfo.FLAG_STOPPED; 8061 } else { 8062 ai.flags &= ~ApplicationInfo.FLAG_STOPPED; 8063 } 8064 updateApplicationInfo(ai, flags, state); 8065 return ai; 8066 } 8067 generateApplicationInfo(ApplicationInfo ai, int flags, FrameworkPackageUserState state, int userId)8068 public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags, 8069 FrameworkPackageUserState state, int userId) { 8070 if (ai == null) return null; 8071 if (!checkUseInstalledOrHidden(flags, state, ai)) { 8072 return null; 8073 } 8074 // This is only used to return the ResolverActivity; we will just always 8075 // make a copy. 8076 ai = new ApplicationInfo(ai); 8077 ai.initForUser(userId); 8078 if (state.isStopped()) { 8079 ai.flags |= ApplicationInfo.FLAG_STOPPED; 8080 } else { 8081 ai.flags &= ~ApplicationInfo.FLAG_STOPPED; 8082 } 8083 updateApplicationInfo(ai, flags, state); 8084 return ai; 8085 } 8086 8087 @UnsupportedAppUsage generatePermissionInfo( Permission p, int flags)8088 public static final PermissionInfo generatePermissionInfo( 8089 Permission p, int flags) { 8090 if (p == null) return null; 8091 if ((flags&PackageManager.GET_META_DATA) == 0) { 8092 return p.info; 8093 } 8094 PermissionInfo pi = new PermissionInfo(p.info); 8095 pi.metaData = p.metaData; 8096 return pi; 8097 } 8098 8099 @UnsupportedAppUsage generatePermissionGroupInfo( PermissionGroup pg, int flags)8100 public static final PermissionGroupInfo generatePermissionGroupInfo( 8101 PermissionGroup pg, int flags) { 8102 if (pg == null) return null; 8103 if ((flags&PackageManager.GET_META_DATA) == 0) { 8104 return pg.info; 8105 } 8106 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info); 8107 pgi.metaData = pg.metaData; 8108 return pgi; 8109 } 8110 8111 public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable { 8112 @UnsupportedAppUsage 8113 public final ActivityInfo info; 8114 private boolean mHasMaxAspectRatio; 8115 private boolean mHasMinAspectRatio; 8116 hasMaxAspectRatio()8117 private boolean hasMaxAspectRatio() { 8118 return mHasMaxAspectRatio; 8119 } 8120 hasMinAspectRatio()8121 private boolean hasMinAspectRatio() { 8122 return mHasMinAspectRatio; 8123 } 8124 8125 // To construct custom activity which does not exist in manifest Activity(final Package owner, final String className, final ActivityInfo info)8126 Activity(final Package owner, final String className, final ActivityInfo info) { 8127 super(owner, new ArrayList<>(0), className); 8128 this.info = info; 8129 this.info.applicationInfo = owner.applicationInfo; 8130 } 8131 Activity(final ParseComponentArgs args, final ActivityInfo _info)8132 public Activity(final ParseComponentArgs args, final ActivityInfo _info) { 8133 super(args, _info); 8134 info = _info; 8135 info.applicationInfo = args.owner.applicationInfo; 8136 } 8137 setPackageName(String packageName)8138 public void setPackageName(String packageName) { 8139 super.setPackageName(packageName); 8140 info.packageName = packageName; 8141 } 8142 8143 setMaxAspectRatio(float maxAspectRatio)8144 private void setMaxAspectRatio(float maxAspectRatio) { 8145 if (info.resizeMode == RESIZE_MODE_RESIZEABLE 8146 || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { 8147 // Resizeable activities can be put in any aspect ratio. 8148 return; 8149 } 8150 8151 if (maxAspectRatio < 1.0f && maxAspectRatio != 0) { 8152 // Ignore any value lesser than 1.0. 8153 return; 8154 } 8155 8156 info.setMaxAspectRatio(maxAspectRatio); 8157 mHasMaxAspectRatio = true; 8158 } 8159 setMinAspectRatio(float minAspectRatio)8160 private void setMinAspectRatio(float minAspectRatio) { 8161 if (info.resizeMode == RESIZE_MODE_RESIZEABLE 8162 || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { 8163 // Resizeable activities can be put in any aspect ratio. 8164 return; 8165 } 8166 8167 if (minAspectRatio < 1.0f && minAspectRatio != 0) { 8168 // Ignore any value lesser than 1.0. 8169 return; 8170 } 8171 8172 info.setMinAspectRatio(minAspectRatio); 8173 mHasMinAspectRatio = true; 8174 } 8175 toString()8176 public String toString() { 8177 StringBuilder sb = new StringBuilder(128); 8178 sb.append("Activity{"); 8179 sb.append(Integer.toHexString(System.identityHashCode(this))); 8180 sb.append(' '); 8181 appendComponentShortName(sb); 8182 sb.append('}'); 8183 return sb.toString(); 8184 } 8185 8186 @Override describeContents()8187 public int describeContents() { 8188 return 0; 8189 } 8190 8191 @Override writeToParcel(Parcel dest, int flags)8192 public void writeToParcel(Parcel dest, int flags) { 8193 super.writeToParcel(dest, flags); 8194 dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES); 8195 dest.writeBoolean(mHasMaxAspectRatio); 8196 dest.writeBoolean(mHasMinAspectRatio); 8197 } 8198 Activity(Parcel in)8199 private Activity(Parcel in) { 8200 super(in); 8201 info = in.readParcelable(Object.class.getClassLoader(), android.content.pm.ActivityInfo.class); 8202 mHasMaxAspectRatio = in.readBoolean(); 8203 mHasMinAspectRatio = in.readBoolean(); 8204 8205 for (ActivityIntentInfo aii : intents) { 8206 aii.activity = this; 8207 order = Math.max(aii.getOrder(), order); 8208 } 8209 8210 if (info.permission != null) { 8211 info.permission = info.permission.intern(); 8212 } 8213 } 8214 8215 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Activity>() { 8216 public Activity createFromParcel(Parcel in) { 8217 return new Activity(in); 8218 } 8219 8220 public Activity[] newArray(int size) { 8221 return new Activity[size]; 8222 } 8223 }; 8224 } 8225 8226 @UnsupportedAppUsage generateActivityInfo(Activity a, int flags, FrameworkPackageUserState state, int userId)8227 public static final ActivityInfo generateActivityInfo(Activity a, int flags, 8228 FrameworkPackageUserState state, int userId) { 8229 return generateActivityInfo(a, flags, state, userId, null); 8230 } 8231 generateActivityInfo(Activity a, int flags, FrameworkPackageUserState state, int userId, ApplicationInfo applicationInfo)8232 private static ActivityInfo generateActivityInfo(Activity a, int flags, 8233 FrameworkPackageUserState state, int userId, ApplicationInfo applicationInfo) { 8234 if (a == null) return null; 8235 if (!checkUseInstalledOrHidden(flags, state, a.owner.applicationInfo)) { 8236 return null; 8237 } 8238 if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) { 8239 updateApplicationInfo(a.info.applicationInfo, flags, state); 8240 return a.info; 8241 } 8242 // Make shallow copies so we can store the metadata safely 8243 ActivityInfo ai = new ActivityInfo(a.info); 8244 ai.metaData = a.metaData; 8245 8246 if (applicationInfo == null) { 8247 applicationInfo = generateApplicationInfo(a.owner, flags, state, userId); 8248 } 8249 ai.applicationInfo = applicationInfo; 8250 8251 return ai; 8252 } 8253 generateActivityInfo(ActivityInfo ai, int flags, FrameworkPackageUserState state, int userId)8254 public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags, 8255 FrameworkPackageUserState state, int userId) { 8256 if (ai == null) return null; 8257 if (!checkUseInstalledOrHidden(flags, state, ai.applicationInfo)) { 8258 return null; 8259 } 8260 // This is only used to return the ResolverActivity; we will just always 8261 // make a copy. 8262 ai = new ActivityInfo(ai); 8263 ai.applicationInfo = generateApplicationInfo(ai.applicationInfo, flags, state, userId); 8264 return ai; 8265 } 8266 8267 public final static class Service extends Component<ServiceIntentInfo> implements Parcelable { 8268 @UnsupportedAppUsage 8269 public final ServiceInfo info; 8270 Service(final ParseComponentArgs args, final ServiceInfo _info)8271 public Service(final ParseComponentArgs args, final ServiceInfo _info) { 8272 super(args, _info); 8273 info = _info; 8274 info.applicationInfo = args.owner.applicationInfo; 8275 } 8276 setPackageName(String packageName)8277 public void setPackageName(String packageName) { 8278 super.setPackageName(packageName); 8279 info.packageName = packageName; 8280 } 8281 toString()8282 public String toString() { 8283 StringBuilder sb = new StringBuilder(128); 8284 sb.append("Service{"); 8285 sb.append(Integer.toHexString(System.identityHashCode(this))); 8286 sb.append(' '); 8287 appendComponentShortName(sb); 8288 sb.append('}'); 8289 return sb.toString(); 8290 } 8291 8292 @Override describeContents()8293 public int describeContents() { 8294 return 0; 8295 } 8296 8297 @Override writeToParcel(Parcel dest, int flags)8298 public void writeToParcel(Parcel dest, int flags) { 8299 super.writeToParcel(dest, flags); 8300 dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES); 8301 } 8302 Service(Parcel in)8303 private Service(Parcel in) { 8304 super(in); 8305 info = in.readParcelable(Object.class.getClassLoader(), android.content.pm.ServiceInfo.class); 8306 8307 for (ServiceIntentInfo aii : intents) { 8308 aii.service = this; 8309 order = Math.max(aii.getOrder(), order); 8310 } 8311 8312 if (info.permission != null) { 8313 info.permission = info.permission.intern(); 8314 } 8315 } 8316 8317 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Service>() { 8318 public Service createFromParcel(Parcel in) { 8319 return new Service(in); 8320 } 8321 8322 public Service[] newArray(int size) { 8323 return new Service[size]; 8324 } 8325 }; 8326 } 8327 8328 @UnsupportedAppUsage generateServiceInfo(Service s, int flags, FrameworkPackageUserState state, int userId)8329 public static final ServiceInfo generateServiceInfo(Service s, int flags, 8330 FrameworkPackageUserState state, int userId) { 8331 return generateServiceInfo(s, flags, state, userId, null); 8332 } 8333 generateServiceInfo(Service s, int flags, FrameworkPackageUserState state, int userId, ApplicationInfo applicationInfo)8334 private static ServiceInfo generateServiceInfo(Service s, int flags, 8335 FrameworkPackageUserState state, int userId, ApplicationInfo applicationInfo) { 8336 if (s == null) return null; 8337 if (!checkUseInstalledOrHidden(flags, state, s.owner.applicationInfo)) { 8338 return null; 8339 } 8340 if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) { 8341 updateApplicationInfo(s.info.applicationInfo, flags, state); 8342 return s.info; 8343 } 8344 // Make shallow copies so we can store the metadata safely 8345 ServiceInfo si = new ServiceInfo(s.info); 8346 si.metaData = s.metaData; 8347 8348 if (applicationInfo == null) { 8349 applicationInfo = generateApplicationInfo(s.owner, flags, state, userId); 8350 } 8351 si.applicationInfo = applicationInfo; 8352 8353 return si; 8354 } 8355 8356 public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable { 8357 @UnsupportedAppUsage 8358 public final ProviderInfo info; 8359 @UnsupportedAppUsage 8360 public boolean syncable; 8361 Provider(final ParseComponentArgs args, final ProviderInfo _info)8362 public Provider(final ParseComponentArgs args, final ProviderInfo _info) { 8363 super(args, _info); 8364 info = _info; 8365 info.applicationInfo = args.owner.applicationInfo; 8366 syncable = false; 8367 } 8368 8369 @UnsupportedAppUsage Provider(Provider existingProvider)8370 public Provider(Provider existingProvider) { 8371 super(existingProvider); 8372 this.info = existingProvider.info; 8373 this.syncable = existingProvider.syncable; 8374 } 8375 setPackageName(String packageName)8376 public void setPackageName(String packageName) { 8377 super.setPackageName(packageName); 8378 info.packageName = packageName; 8379 } 8380 toString()8381 public String toString() { 8382 StringBuilder sb = new StringBuilder(128); 8383 sb.append("Provider{"); 8384 sb.append(Integer.toHexString(System.identityHashCode(this))); 8385 sb.append(' '); 8386 appendComponentShortName(sb); 8387 sb.append('}'); 8388 return sb.toString(); 8389 } 8390 8391 @Override describeContents()8392 public int describeContents() { 8393 return 0; 8394 } 8395 8396 @Override writeToParcel(Parcel dest, int flags)8397 public void writeToParcel(Parcel dest, int flags) { 8398 super.writeToParcel(dest, flags); 8399 dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES); 8400 dest.writeInt((syncable) ? 1 : 0); 8401 } 8402 Provider(Parcel in)8403 private Provider(Parcel in) { 8404 super(in); 8405 info = in.readParcelable(Object.class.getClassLoader(), android.content.pm.ProviderInfo.class); 8406 syncable = (in.readInt() == 1); 8407 8408 for (ProviderIntentInfo aii : intents) { 8409 aii.provider = this; 8410 } 8411 8412 if (info.readPermission != null) { 8413 info.readPermission = info.readPermission.intern(); 8414 } 8415 8416 if (info.writePermission != null) { 8417 info.writePermission = info.writePermission.intern(); 8418 } 8419 8420 if (info.authority != null) { 8421 info.authority = info.authority.intern(); 8422 } 8423 } 8424 8425 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Provider>() { 8426 public Provider createFromParcel(Parcel in) { 8427 return new Provider(in); 8428 } 8429 8430 public Provider[] newArray(int size) { 8431 return new Provider[size]; 8432 } 8433 }; 8434 } 8435 8436 @UnsupportedAppUsage generateProviderInfo(Provider p, int flags, FrameworkPackageUserState state, int userId)8437 public static final ProviderInfo generateProviderInfo(Provider p, int flags, 8438 FrameworkPackageUserState state, int userId) { 8439 return generateProviderInfo(p, flags, state, userId, null); 8440 } 8441 generateProviderInfo(Provider p, int flags, FrameworkPackageUserState state, int userId, ApplicationInfo applicationInfo)8442 private static ProviderInfo generateProviderInfo(Provider p, int flags, 8443 FrameworkPackageUserState state, int userId, ApplicationInfo applicationInfo) { 8444 if (p == null) return null; 8445 if (!checkUseInstalledOrHidden(flags, state, p.owner.applicationInfo)) { 8446 return null; 8447 } 8448 if (!copyNeeded(flags, p.owner, state, p.metaData, userId) 8449 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 8450 || p.info.uriPermissionPatterns == null)) { 8451 updateApplicationInfo(p.info.applicationInfo, flags, state); 8452 return p.info; 8453 } 8454 // Make shallow copies so we can store the metadata safely 8455 ProviderInfo pi = new ProviderInfo(p.info); 8456 pi.metaData = p.metaData; 8457 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { 8458 pi.uriPermissionPatterns = null; 8459 } 8460 8461 if (applicationInfo == null) { 8462 applicationInfo = generateApplicationInfo(p.owner, flags, state, userId); 8463 } 8464 pi.applicationInfo = applicationInfo; 8465 8466 return pi; 8467 } 8468 8469 public final static class Instrumentation extends Component<IntentInfo> implements 8470 Parcelable { 8471 @UnsupportedAppUsage 8472 public final InstrumentationInfo info; 8473 Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info)8474 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) { 8475 super(args, _info); 8476 info = _info; 8477 } 8478 setPackageName(String packageName)8479 public void setPackageName(String packageName) { 8480 super.setPackageName(packageName); 8481 info.packageName = packageName; 8482 } 8483 toString()8484 public String toString() { 8485 StringBuilder sb = new StringBuilder(128); 8486 sb.append("Instrumentation{"); 8487 sb.append(Integer.toHexString(System.identityHashCode(this))); 8488 sb.append(' '); 8489 appendComponentShortName(sb); 8490 sb.append('}'); 8491 return sb.toString(); 8492 } 8493 8494 @Override describeContents()8495 public int describeContents() { 8496 return 0; 8497 } 8498 8499 @Override writeToParcel(Parcel dest, int flags)8500 public void writeToParcel(Parcel dest, int flags) { 8501 super.writeToParcel(dest, flags); 8502 dest.writeParcelable(info, flags); 8503 } 8504 Instrumentation(Parcel in)8505 private Instrumentation(Parcel in) { 8506 super(in); 8507 info = in.readParcelable(Object.class.getClassLoader(), android.content.pm.InstrumentationInfo.class); 8508 8509 if (info.targetPackage != null) { 8510 info.targetPackage = info.targetPackage.intern(); 8511 } 8512 8513 if (info.targetProcesses != null) { 8514 info.targetProcesses = info.targetProcesses.intern(); 8515 } 8516 } 8517 8518 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Instrumentation>() { 8519 public Instrumentation createFromParcel(Parcel in) { 8520 return new Instrumentation(in); 8521 } 8522 8523 public Instrumentation[] newArray(int size) { 8524 return new Instrumentation[size]; 8525 } 8526 }; 8527 } 8528 8529 @UnsupportedAppUsage generateInstrumentationInfo( Instrumentation i, int flags)8530 public static final InstrumentationInfo generateInstrumentationInfo( 8531 Instrumentation i, int flags) { 8532 if (i == null) return null; 8533 if ((flags&PackageManager.GET_META_DATA) == 0) { 8534 return i.info; 8535 } 8536 InstrumentationInfo ii = new InstrumentationInfo(i.info); 8537 ii.metaData = i.metaData; 8538 return ii; 8539 } 8540 8541 public static abstract class IntentInfo extends IntentFilter { 8542 @UnsupportedAppUsage 8543 public boolean hasDefault; 8544 @UnsupportedAppUsage 8545 public int labelRes; 8546 @UnsupportedAppUsage 8547 public CharSequence nonLocalizedLabel; 8548 @UnsupportedAppUsage 8549 public int icon; 8550 @UnsupportedAppUsage 8551 public int logo; 8552 @UnsupportedAppUsage 8553 public int banner; 8554 public int preferred; 8555 8556 @UnsupportedAppUsage IntentInfo()8557 protected IntentInfo() { 8558 } 8559 IntentInfo(Parcel dest)8560 protected IntentInfo(Parcel dest) { 8561 super(dest); 8562 hasDefault = (dest.readInt() == 1); 8563 labelRes = dest.readInt(); 8564 nonLocalizedLabel = dest.readCharSequence(); 8565 icon = dest.readInt(); 8566 logo = dest.readInt(); 8567 banner = dest.readInt(); 8568 preferred = dest.readInt(); 8569 } 8570 8571 writeIntentInfoToParcel(Parcel dest, int flags)8572 public void writeIntentInfoToParcel(Parcel dest, int flags) { 8573 super.writeToParcel(dest, flags); 8574 dest.writeInt(hasDefault ? 1 : 0); 8575 dest.writeInt(labelRes); 8576 dest.writeCharSequence(nonLocalizedLabel); 8577 dest.writeInt(icon); 8578 dest.writeInt(logo); 8579 dest.writeInt(banner); 8580 dest.writeInt(preferred); 8581 } 8582 } 8583 8584 public final static class ActivityIntentInfo extends IntentInfo { 8585 @UnsupportedAppUsage 8586 public Activity activity; 8587 ActivityIntentInfo(Activity _activity)8588 public ActivityIntentInfo(Activity _activity) { 8589 activity = _activity; 8590 } 8591 toString()8592 public String toString() { 8593 StringBuilder sb = new StringBuilder(128); 8594 sb.append("ActivityIntentInfo{"); 8595 sb.append(Integer.toHexString(System.identityHashCode(this))); 8596 sb.append(' '); 8597 activity.appendComponentShortName(sb); 8598 sb.append('}'); 8599 return sb.toString(); 8600 } 8601 ActivityIntentInfo(Parcel in)8602 public ActivityIntentInfo(Parcel in) { 8603 super(in); 8604 } 8605 } 8606 8607 public final static class ServiceIntentInfo extends IntentInfo { 8608 @UnsupportedAppUsage 8609 public Service service; 8610 ServiceIntentInfo(Service _service)8611 public ServiceIntentInfo(Service _service) { 8612 service = _service; 8613 } 8614 toString()8615 public String toString() { 8616 StringBuilder sb = new StringBuilder(128); 8617 sb.append("ServiceIntentInfo{"); 8618 sb.append(Integer.toHexString(System.identityHashCode(this))); 8619 sb.append(' '); 8620 service.appendComponentShortName(sb); 8621 sb.append('}'); 8622 return sb.toString(); 8623 } 8624 ServiceIntentInfo(Parcel in)8625 public ServiceIntentInfo(Parcel in) { 8626 super(in); 8627 } 8628 } 8629 8630 public static final class ProviderIntentInfo extends IntentInfo { 8631 @UnsupportedAppUsage 8632 public Provider provider; 8633 ProviderIntentInfo(Provider provider)8634 public ProviderIntentInfo(Provider provider) { 8635 this.provider = provider; 8636 } 8637 toString()8638 public String toString() { 8639 StringBuilder sb = new StringBuilder(128); 8640 sb.append("ProviderIntentInfo{"); 8641 sb.append(Integer.toHexString(System.identityHashCode(this))); 8642 sb.append(' '); 8643 provider.appendComponentShortName(sb); 8644 sb.append('}'); 8645 return sb.toString(); 8646 } 8647 ProviderIntentInfo(Parcel in)8648 public ProviderIntentInfo(Parcel in) { 8649 super(in); 8650 } 8651 } 8652 8653 /** 8654 * @hide 8655 */ 8656 @UnsupportedAppUsage setCompatibilityModeEnabled(boolean compatibilityModeEnabled)8657 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { 8658 sCompatibilityModeEnabled = compatibilityModeEnabled; 8659 } 8660 8661 /** 8662 * @hide 8663 */ readConfigUseRoundIcon(Resources r)8664 public static void readConfigUseRoundIcon(Resources r) { 8665 if (r != null) { 8666 sUseRoundIcon = r.getBoolean(com.android.internal.R.bool.config_useRoundIcon); 8667 return; 8668 } 8669 8670 ApplicationInfo androidAppInfo; 8671 try { 8672 androidAppInfo = ActivityThread.getPackageManager().getApplicationInfo( 8673 "android", 0 /* flags */, 8674 UserHandle.myUserId()); 8675 } catch (RemoteException e) { 8676 throw e.rethrowFromSystemServer(); 8677 } 8678 Resources systemResources = Resources.getSystem(); 8679 8680 // Create in-flight as this overlayable resource is only used when config changes 8681 Resources overlayableRes = ResourcesManager.getInstance().getResources(null, 8682 null, 8683 null, 8684 androidAppInfo.resourceDirs, 8685 androidAppInfo.overlayPaths, 8686 androidAppInfo.sharedLibraryFiles, 8687 null, 8688 null, 8689 systemResources.getCompatibilityInfo(), 8690 systemResources.getClassLoader(), 8691 null); 8692 8693 sUseRoundIcon = overlayableRes.getBoolean(com.android.internal.R.bool.config_useRoundIcon); 8694 } 8695 8696 public static class PackageParserException extends Exception { 8697 public final int error; 8698 PackageParserException(int error, String detailMessage)8699 public PackageParserException(int error, String detailMessage) { 8700 super(detailMessage); 8701 this.error = error; 8702 } 8703 PackageParserException(int error, String detailMessage, Throwable throwable)8704 public PackageParserException(int error, String detailMessage, Throwable throwable) { 8705 super(detailMessage, throwable); 8706 this.error = error; 8707 } 8708 } 8709 8710 // Duplicate the SplitAsset related classes with PackageParser.Package/ApkLite here, and 8711 // change the original one using new Package/ApkLite. The propose is that we don't want to 8712 // have two branches of methods in SplitAsset related classes so we can keep real classes 8713 // clean and move all the legacy code to one place. 8714 8715 /** 8716 * Simple interface for loading base Assets and Splits. Used by PackageParser when parsing 8717 * split APKs. 8718 * 8719 * @hide 8720 * @deprecated Do not use. New changes should use 8721 * {@link android.content.pm.split.SplitAssetLoader} instead. 8722 */ 8723 @Deprecated 8724 private interface SplitAssetLoader extends AutoCloseable { getBaseAssetManager()8725 AssetManager getBaseAssetManager() throws PackageParserException; getSplitAssetManager(int splitIdx)8726 AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException; 8727 getBaseApkAssets()8728 ApkAssets getBaseApkAssets(); 8729 } 8730 8731 /** 8732 * A helper class that implements the dependency tree traversal for splits. Callbacks 8733 * are implemented by subclasses to notify whether a split has already been constructed 8734 * and is cached, and to actually create the split requested. 8735 * 8736 * This helper is meant to be subclassed so as to reduce the number of allocations 8737 * needed to make use of it. 8738 * 8739 * All inputs and outputs are assumed to be indices into an array of splits. 8740 * 8741 * @hide 8742 * @deprecated Do not use. New changes should use 8743 * {@link android.content.pm.split.SplitDependencyLoader} instead. 8744 */ 8745 @Deprecated 8746 private abstract static class SplitDependencyLoader<E extends Exception> { 8747 private final @NonNull SparseArray<int[]> mDependencies; 8748 8749 /** 8750 * Construct a new SplitDependencyLoader. Meant to be called from the 8751 * subclass constructor. 8752 * @param dependencies The dependency tree of splits. 8753 */ SplitDependencyLoader(@onNull SparseArray<int[]> dependencies)8754 protected SplitDependencyLoader(@NonNull SparseArray<int[]> dependencies) { 8755 mDependencies = dependencies; 8756 } 8757 8758 /** 8759 * Traverses the dependency tree and constructs any splits that are not already 8760 * cached. This routine short-circuits and skips the creation of splits closer to the 8761 * root if they are cached, as reported by the subclass implementation of 8762 * {@link #isSplitCached(int)}. The construction of splits is delegated to the subclass 8763 * implementation of {@link #constructSplit(int, int[], int)}. 8764 * @param splitIdx The index of the split to load. 0 represents the base Application. 8765 */ loadDependenciesForSplit(@ntRangefrom = 0) int splitIdx)8766 protected void loadDependenciesForSplit(@IntRange(from = 0) int splitIdx) throws E { 8767 // Quick check before any allocations are done. 8768 if (isSplitCached(splitIdx)) { 8769 return; 8770 } 8771 8772 // Special case the base, since it has no dependencies. 8773 if (splitIdx == 0) { 8774 final int[] configSplitIndices = collectConfigSplitIndices(0); 8775 constructSplit(0, configSplitIndices, -1); 8776 return; 8777 } 8778 8779 // Build up the dependency hierarchy. 8780 final IntArray linearDependencies = new IntArray(); 8781 linearDependencies.add(splitIdx); 8782 8783 // Collect all the dependencies that need to be constructed. 8784 // They will be listed from leaf to root. 8785 while (true) { 8786 // Only follow the first index into the array. The others are config splits and 8787 // get loaded with the split. 8788 final int[] deps = mDependencies.get(splitIdx); 8789 if (deps != null && deps.length > 0) { 8790 splitIdx = deps[0]; 8791 } else { 8792 splitIdx = -1; 8793 } 8794 8795 if (splitIdx < 0 || isSplitCached(splitIdx)) { 8796 break; 8797 } 8798 8799 linearDependencies.add(splitIdx); 8800 } 8801 8802 // Visit each index, from right to left (root to leaf). 8803 int parentIdx = splitIdx; 8804 for (int i = linearDependencies.size() - 1; i >= 0; i--) { 8805 final int idx = linearDependencies.get(i); 8806 final int[] configSplitIndices = collectConfigSplitIndices(idx); 8807 constructSplit(idx, configSplitIndices, parentIdx); 8808 parentIdx = idx; 8809 } 8810 } 8811 collectConfigSplitIndices(int splitIdx)8812 private @NonNull int[] collectConfigSplitIndices(int splitIdx) { 8813 // The config splits appear after the first element. 8814 final int[] deps = mDependencies.get(splitIdx); 8815 if (deps == null || deps.length <= 1) { 8816 return EmptyArray.INT; 8817 } 8818 return Arrays.copyOfRange(deps, 1, deps.length); 8819 } 8820 8821 /** 8822 * Subclass to report whether the split at `splitIdx` is cached and need not be constructed. 8823 * It is assumed that if `splitIdx` is cached, any parent of `splitIdx` is also cached. 8824 * @param splitIdx The index of the split to check for in the cache. 8825 * @return true if the split is cached and does not need to be constructed. 8826 */ isSplitCached(@ntRangefrom = 0) int splitIdx)8827 protected abstract boolean isSplitCached(@IntRange(from = 0) int splitIdx); 8828 8829 /** 8830 * Subclass to construct a split at index `splitIdx` with parent split `parentSplitIdx`. 8831 * The result is expected to be cached by the subclass in its own structures. 8832 * @param splitIdx The index of the split to construct. 0 represents the base Application. 8833 * @param configSplitIndices The array of configuration splits to load along with this 8834 * split. May be empty (length == 0) but never null. 8835 * @param parentSplitIdx The index of the parent split. -1 if there is no parent. 8836 * @throws E Subclass defined exception representing failure to construct a split. 8837 */ constructSplit(@ntRangefrom = 0) int splitIdx, @NonNull @IntRange(from = 1) int[] configSplitIndices, @IntRange(from = -1) int parentSplitIdx)8838 protected abstract void constructSplit(@IntRange(from = 0) int splitIdx, 8839 @NonNull @IntRange(from = 1) int[] configSplitIndices, 8840 @IntRange(from = -1) int parentSplitIdx) throws E; 8841 8842 public static class IllegalDependencyException extends Exception { IllegalDependencyException(String message)8843 private IllegalDependencyException(String message) { 8844 super(message); 8845 } 8846 } 8847 append(int[] src, int elem)8848 private static int[] append(int[] src, int elem) { 8849 if (src == null) { 8850 return new int[] { elem }; 8851 } 8852 int[] dst = Arrays.copyOf(src, src.length + 1); 8853 dst[src.length] = elem; 8854 return dst; 8855 } 8856 createDependenciesFromPackage( PackageLite pkg)8857 public static @NonNull SparseArray<int[]> createDependenciesFromPackage( 8858 PackageLite pkg) 8859 throws SplitDependencyLoader.IllegalDependencyException { 8860 // The data structure that holds the dependencies. In PackageParser, splits are stored 8861 // in their own array, separate from the base. We treat all paths as equals, so 8862 // we need to insert the base as index 0, and shift all other splits. 8863 final SparseArray<int[]> splitDependencies = new SparseArray<>(); 8864 8865 // The base depends on nothing. 8866 splitDependencies.put(0, new int[] {-1}); 8867 8868 // First write out the <uses-split> dependencies. These must appear first in the 8869 // array of ints, as is convention in this class. 8870 for (int splitIdx = 0; splitIdx < pkg.splitNames.length; splitIdx++) { 8871 if (!pkg.isFeatureSplits[splitIdx]) { 8872 // Non-feature splits don't have dependencies. 8873 continue; 8874 } 8875 8876 // Implicit dependency on the base. 8877 final int targetIdx; 8878 final String splitDependency = pkg.usesSplitNames[splitIdx]; 8879 if (splitDependency != null) { 8880 final int depIdx = Arrays.binarySearch(pkg.splitNames, splitDependency); 8881 if (depIdx < 0) { 8882 throw new SplitDependencyLoader.IllegalDependencyException( 8883 "Split '" + pkg.splitNames[splitIdx] + "' requires split '" 8884 + splitDependency + "', which is missing."); 8885 } 8886 targetIdx = depIdx + 1; 8887 } else { 8888 // Implicitly depend on the base. 8889 targetIdx = 0; 8890 } 8891 splitDependencies.put(splitIdx + 1, new int[] {targetIdx}); 8892 } 8893 8894 // Write out the configForSplit reverse-dependencies. These appear after the 8895 // <uses-split> dependencies and are considered leaves. 8896 // 8897 // At this point, all splits in splitDependencies have the first element in their 8898 // array set. 8899 for (int splitIdx = 0, size = pkg.splitNames.length; splitIdx < size; splitIdx++) { 8900 if (pkg.isFeatureSplits[splitIdx]) { 8901 // Feature splits are not configForSplits. 8902 continue; 8903 } 8904 8905 // Implicit feature for the base. 8906 final int targetSplitIdx; 8907 final String configForSplit = pkg.configForSplit[splitIdx]; 8908 if (configForSplit != null) { 8909 final int depIdx = Arrays.binarySearch(pkg.splitNames, configForSplit); 8910 if (depIdx < 0) { 8911 throw new SplitDependencyLoader.IllegalDependencyException( 8912 "Split '" + pkg.splitNames[splitIdx] + "' targets split '" 8913 + configForSplit + "', which is missing."); 8914 } 8915 8916 if (!pkg.isFeatureSplits[depIdx]) { 8917 throw new SplitDependencyLoader.IllegalDependencyException( 8918 "Split '" + pkg.splitNames[splitIdx] + "' declares itself as " 8919 + "configuration split for a non-feature split '" 8920 + pkg.splitNames[depIdx] + "'"); 8921 } 8922 targetSplitIdx = depIdx + 1; 8923 } else { 8924 targetSplitIdx = 0; 8925 } 8926 splitDependencies.put(targetSplitIdx, 8927 append(splitDependencies.get(targetSplitIdx), splitIdx + 1)); 8928 } 8929 8930 // Verify that there are no cycles. 8931 final BitSet bitset = new BitSet(); 8932 for (int i = 0, size = splitDependencies.size(); i < size; i++) { 8933 int splitIdx = splitDependencies.keyAt(i); 8934 8935 bitset.clear(); 8936 while (splitIdx != -1) { 8937 // Check if this split has been visited yet. 8938 if (bitset.get(splitIdx)) { 8939 throw new SplitDependencyLoader.IllegalDependencyException( 8940 "Cycle detected in split dependencies."); 8941 } 8942 8943 // Mark the split so that if we visit it again, we no there is a cycle. 8944 bitset.set(splitIdx); 8945 8946 // Follow the first dependency only, the others are leaves by definition. 8947 final int[] deps = splitDependencies.get(splitIdx); 8948 splitIdx = deps != null ? deps[0] : -1; 8949 } 8950 } 8951 return splitDependencies; 8952 } 8953 } 8954 8955 /** 8956 * Loads the base and split APKs into a single AssetManager. 8957 * @hide 8958 * @deprecated Do not use. New changes should use 8959 * {@link android.content.pm.split.DefaultSplitAssetLoader} instead. 8960 */ 8961 @Deprecated 8962 private static class DefaultSplitAssetLoader implements SplitAssetLoader { 8963 private final String mBaseCodePath; 8964 private final String[] mSplitCodePaths; 8965 private final @ParseFlags int mFlags; 8966 private AssetManager mCachedAssetManager; 8967 8968 private ApkAssets mBaseApkAssets; 8969 DefaultSplitAssetLoader(PackageLite pkg, @ParseFlags int flags)8970 DefaultSplitAssetLoader(PackageLite pkg, @ParseFlags int flags) { 8971 mBaseCodePath = pkg.baseCodePath; 8972 mSplitCodePaths = pkg.splitCodePaths; 8973 mFlags = flags; 8974 } 8975 loadApkAssets(String path, @ParseFlags int flags)8976 private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) 8977 throws PackageParserException { 8978 if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) { 8979 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 8980 "Invalid package file: " + path); 8981 } 8982 8983 try { 8984 return ApkAssets.loadFromPath(path); 8985 } catch (IOException e) { 8986 throw new PackageParserException(INSTALL_FAILED_INVALID_APK, 8987 "Failed to load APK at path " + path, e); 8988 } 8989 } 8990 8991 @Override getBaseAssetManager()8992 public AssetManager getBaseAssetManager() throws PackageParserException { 8993 if (mCachedAssetManager != null) { 8994 return mCachedAssetManager; 8995 } 8996 8997 ApkAssets[] apkAssets = new ApkAssets[(mSplitCodePaths != null 8998 ? mSplitCodePaths.length : 0) + 1]; 8999 9000 mBaseApkAssets = loadApkAssets(mBaseCodePath, mFlags); 9001 9002 // Load the base. 9003 int splitIdx = 0; 9004 apkAssets[splitIdx++] = mBaseApkAssets; 9005 9006 // Load any splits. 9007 if (!ArrayUtils.isEmpty(mSplitCodePaths)) { 9008 for (String apkPath : mSplitCodePaths) { 9009 apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags); 9010 } 9011 } 9012 9013 AssetManager assets = new AssetManager(); 9014 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9015 Build.VERSION.RESOURCES_SDK_INT); 9016 assets.setApkAssets(apkAssets, false /*invalidateCaches*/); 9017 9018 mCachedAssetManager = assets; 9019 return mCachedAssetManager; 9020 } 9021 9022 @Override getSplitAssetManager(int splitIdx)9023 public AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException { 9024 return getBaseAssetManager(); 9025 } 9026 9027 @Override close()9028 public void close() throws Exception { 9029 IoUtils.closeQuietly(mCachedAssetManager); 9030 } 9031 9032 @Override getBaseApkAssets()9033 public ApkAssets getBaseApkAssets() { 9034 return mBaseApkAssets; 9035 } 9036 } 9037 9038 /** 9039 * Loads AssetManagers for splits and their dependencies. This SplitAssetLoader implementation 9040 * is to be used when an application opts-in to isolated split loading. 9041 * @hide 9042 * @deprecated Do not use. New changes should use 9043 * {@link android.content.pm.split.SplitAssetDependencyLoader} instead. 9044 */ 9045 @Deprecated 9046 private static class SplitAssetDependencyLoader extends 9047 SplitDependencyLoader<PackageParserException> implements SplitAssetLoader { 9048 private final String[] mSplitPaths; 9049 private final @ParseFlags int mFlags; 9050 private final ApkAssets[][] mCachedSplitApks; 9051 private final AssetManager[] mCachedAssetManagers; 9052 SplitAssetDependencyLoader(PackageLite pkg, SparseArray<int[]> dependencies, @ParseFlags int flags)9053 SplitAssetDependencyLoader(PackageLite pkg, 9054 SparseArray<int[]> dependencies, @ParseFlags int flags) { 9055 super(dependencies); 9056 9057 // The base is inserted into index 0, so we need to shift all the splits by 1. 9058 mSplitPaths = new String[pkg.splitCodePaths.length + 1]; 9059 mSplitPaths[0] = pkg.baseCodePath; 9060 System.arraycopy(pkg.splitCodePaths, 0, mSplitPaths, 1, pkg.splitCodePaths.length); 9061 9062 mFlags = flags; 9063 mCachedSplitApks = new ApkAssets[mSplitPaths.length][]; 9064 mCachedAssetManagers = new AssetManager[mSplitPaths.length]; 9065 } 9066 9067 @Override isSplitCached(int splitIdx)9068 protected boolean isSplitCached(int splitIdx) { 9069 return mCachedAssetManagers[splitIdx] != null; 9070 } 9071 loadApkAssets(String path, @ParseFlags int flags)9072 private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) 9073 throws PackageParserException { 9074 if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) { 9075 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 9076 "Invalid package file: " + path); 9077 } 9078 9079 try { 9080 return ApkAssets.loadFromPath(path); 9081 } catch (IOException e) { 9082 throw new PackageParserException(PackageManager.INSTALL_FAILED_INVALID_APK, 9083 "Failed to load APK at path " + path, e); 9084 } 9085 } 9086 createAssetManagerWithAssets(ApkAssets[] apkAssets)9087 private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) { 9088 final AssetManager assets = new AssetManager(); 9089 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9090 Build.VERSION.RESOURCES_SDK_INT); 9091 assets.setApkAssets(apkAssets, false /*invalidateCaches*/); 9092 return assets; 9093 } 9094 9095 @Override constructSplit(int splitIdx, @NonNull int[] configSplitIndices, int parentSplitIdx)9096 protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices, 9097 int parentSplitIdx) throws PackageParserException { 9098 final ArrayList<ApkAssets> assets = new ArrayList<>(); 9099 9100 // Include parent ApkAssets. 9101 if (parentSplitIdx >= 0) { 9102 Collections.addAll(assets, mCachedSplitApks[parentSplitIdx]); 9103 } 9104 9105 // Include this ApkAssets. 9106 assets.add(loadApkAssets(mSplitPaths[splitIdx], mFlags)); 9107 9108 // Load and include all config splits for this feature. 9109 for (int configSplitIdx : configSplitIndices) { 9110 assets.add(loadApkAssets(mSplitPaths[configSplitIdx], mFlags)); 9111 } 9112 9113 // Cache the results. 9114 mCachedSplitApks[splitIdx] = assets.toArray(new ApkAssets[assets.size()]); 9115 mCachedAssetManagers[splitIdx] = createAssetManagerWithAssets( 9116 mCachedSplitApks[splitIdx]); 9117 } 9118 9119 @Override getBaseAssetManager()9120 public AssetManager getBaseAssetManager() throws PackageParserException { 9121 loadDependenciesForSplit(0); 9122 return mCachedAssetManagers[0]; 9123 } 9124 9125 @Override getSplitAssetManager(int idx)9126 public AssetManager getSplitAssetManager(int idx) throws PackageParserException { 9127 // Since we insert the base at position 0, and PackageParser keeps splits separate from 9128 // the base, we need to adjust the index. 9129 loadDependenciesForSplit(idx + 1); 9130 return mCachedAssetManagers[idx + 1]; 9131 } 9132 9133 @Override close()9134 public void close() throws Exception { 9135 for (AssetManager assets : mCachedAssetManagers) { 9136 IoUtils.closeQuietly(assets); 9137 } 9138 } 9139 9140 @Override getBaseApkAssets()9141 public ApkAssets getBaseApkAssets() { 9142 return mCachedSplitApks[0][0]; 9143 } 9144 } 9145 9146 9147 isMatch(@onNull FrameworkPackageUserState state, ComponentInfo componentInfo, long flags)9148 public static boolean isMatch(@NonNull FrameworkPackageUserState state, 9149 ComponentInfo componentInfo, long flags) { 9150 return isMatch(state, componentInfo.applicationInfo.isSystemApp(), 9151 componentInfo.applicationInfo.enabled, componentInfo.enabled, 9152 componentInfo.directBootAware, componentInfo.name, flags); 9153 } 9154 isMatch(@onNull FrameworkPackageUserState state, boolean isSystem, boolean isPackageEnabled, ComponentInfo component, long flags)9155 public static boolean isMatch(@NonNull FrameworkPackageUserState state, boolean isSystem, 9156 boolean isPackageEnabled, ComponentInfo component, long flags) { 9157 return isMatch(state, isSystem, isPackageEnabled, component.isEnabled(), 9158 component.directBootAware, component.name, flags); 9159 } 9160 9161 /** 9162 * Test if the given component is considered installed, enabled and a match for the given 9163 * flags. 9164 * 9165 * <p> 9166 * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and {@link 9167 * PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}. 9168 * </p> 9169 */ isMatch(@onNull FrameworkPackageUserState state, boolean isSystem, boolean isPackageEnabled, boolean isComponentEnabled, boolean isComponentDirectBootAware, String componentName, long flags)9170 public static boolean isMatch(@NonNull FrameworkPackageUserState state, boolean isSystem, 9171 boolean isPackageEnabled, boolean isComponentEnabled, 9172 boolean isComponentDirectBootAware, String componentName, long flags) { 9173 final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0; 9174 if (!isAvailable(state, flags) && !(isSystem && matchUninstalled)) { 9175 return reportIfDebug(false, flags); 9176 } 9177 9178 if (!isEnabled(state, isPackageEnabled, isComponentEnabled, componentName, flags)) { 9179 return reportIfDebug(false, flags); 9180 } 9181 9182 if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { 9183 if (!isSystem) { 9184 return reportIfDebug(false, flags); 9185 } 9186 } 9187 9188 final boolean matchesUnaware = ((flags & PackageManager.MATCH_DIRECT_BOOT_UNAWARE) != 0) 9189 && !isComponentDirectBootAware; 9190 final boolean matchesAware = ((flags & PackageManager.MATCH_DIRECT_BOOT_AWARE) != 0) 9191 && isComponentDirectBootAware; 9192 return reportIfDebug(matchesUnaware || matchesAware, flags); 9193 } 9194 isAvailable(@onNull FrameworkPackageUserState state, long flags)9195 public static boolean isAvailable(@NonNull FrameworkPackageUserState state, long flags) { 9196 // True if it is installed for this user and it is not hidden. If it is hidden, 9197 // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES 9198 final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0; 9199 final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0; 9200 return matchAnyUser 9201 || (state.isInstalled() 9202 && (!state.isHidden() || matchUninstalled)); 9203 } 9204 reportIfDebug(boolean result, long flags)9205 public static boolean reportIfDebug(boolean result, long flags) { 9206 if (DEBUG_PARSER && !result) { 9207 Slog.i(TAG, "No match!; flags: " 9208 + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " " 9209 + Debug.getCaller()); 9210 } 9211 return result; 9212 } 9213 isEnabled(@onNull FrameworkPackageUserState state, ComponentInfo componentInfo, long flags)9214 public static boolean isEnabled(@NonNull FrameworkPackageUserState state, ComponentInfo componentInfo, 9215 long flags) { 9216 return isEnabled(state, componentInfo.applicationInfo.enabled, componentInfo.enabled, 9217 componentInfo.name, flags); 9218 } 9219 isEnabled(@onNull FrameworkPackageUserState state, boolean isPackageEnabled, ComponentInfo parsedComponent, long flags)9220 public static boolean isEnabled(@NonNull FrameworkPackageUserState state, boolean isPackageEnabled, 9221 ComponentInfo parsedComponent, long flags) { 9222 return isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(), 9223 parsedComponent.name, flags); 9224 } 9225 9226 /** 9227 * Test if the given component is considered enabled. 9228 */ isEnabled(@onNull FrameworkPackageUserState state, boolean isPackageEnabled, boolean isComponentEnabled, String componentName, long flags)9229 public static boolean isEnabled(@NonNull FrameworkPackageUserState state, 9230 boolean isPackageEnabled, boolean isComponentEnabled, String componentName, 9231 long flags) { 9232 if ((flags & MATCH_DISABLED_COMPONENTS) != 0) { 9233 return true; 9234 } 9235 9236 // First check if the overall package is disabled; if the package is 9237 // enabled then fall through to check specific component 9238 switch (state.getEnabledState()) { 9239 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: 9240 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: 9241 return false; 9242 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: 9243 if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) { 9244 return false; 9245 } 9246 // fallthrough 9247 case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: 9248 if (!isPackageEnabled) { 9249 return false; 9250 } 9251 // fallthrough 9252 case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: 9253 break; 9254 } 9255 9256 // Check if component has explicit state before falling through to 9257 // the manifest default 9258 if (state.isComponentEnabled(componentName)) { 9259 return true; 9260 } else if (state.isComponentDisabled(componentName)) { 9261 return false; 9262 } 9263 9264 return isComponentEnabled; 9265 } 9266 9267 /** 9268 * Writes the keyset mapping to the provided package. {@code null} mappings are permitted. 9269 */ writeKeySetMapping(@onNull Parcel dest, @NonNull Map<String, ArraySet<PublicKey>> keySetMapping)9270 public static void writeKeySetMapping(@NonNull Parcel dest, 9271 @NonNull Map<String, ArraySet<PublicKey>> keySetMapping) { 9272 if (keySetMapping == null) { 9273 dest.writeInt(-1); 9274 return; 9275 } 9276 9277 final int N = keySetMapping.size(); 9278 dest.writeInt(N); 9279 9280 for (String key : keySetMapping.keySet()) { 9281 dest.writeString(key); 9282 ArraySet<PublicKey> keys = keySetMapping.get(key); 9283 if (keys == null) { 9284 dest.writeInt(-1); 9285 continue; 9286 } 9287 9288 final int M = keys.size(); 9289 dest.writeInt(M); 9290 for (int j = 0; j < M; j++) { 9291 dest.writeSerializable(keys.valueAt(j)); 9292 } 9293 } 9294 } 9295 9296 /** 9297 * Reads a keyset mapping from the given parcel at the given data position. May return 9298 * {@code null} if the serialized mapping was {@code null}. 9299 */ 9300 @NonNull readKeySetMapping(@onNull Parcel in)9301 public static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(@NonNull Parcel in) { 9302 final int N = in.readInt(); 9303 if (N == -1) { 9304 return null; 9305 } 9306 9307 ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>(); 9308 for (int i = 0; i < N; ++i) { 9309 String key = in.readString(); 9310 final int M = in.readInt(); 9311 if (M == -1) { 9312 keySetMapping.put(key, null); 9313 continue; 9314 } 9315 9316 ArraySet<PublicKey> keys = new ArraySet<>(M); 9317 for (int j = 0; j < M; ++j) { 9318 PublicKey pk = 9319 in.readSerializable(PublicKey.class.getClassLoader(), PublicKey.class); 9320 keys.add(pk); 9321 } 9322 9323 keySetMapping.put(key, keys); 9324 } 9325 9326 return keySetMapping; 9327 } 9328 getSeinfoUser(FrameworkPackageUserState userState)9329 public static String getSeinfoUser(FrameworkPackageUserState userState) { 9330 if (userState.isInstantApp()) { 9331 return ":ephemeralapp:complete"; 9332 } 9333 return ":complete"; 9334 } 9335 } 9336