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