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