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