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