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 com.android.internal.R; 20 import com.android.internal.util.ArrayUtils; 21 import com.android.internal.util.XmlUtils; 22 23 import org.xmlpull.v1.XmlPullParser; 24 import org.xmlpull.v1.XmlPullParserException; 25 26 import android.app.ActivityManager; 27 import android.content.ComponentName; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.content.res.AssetManager; 31 import android.content.res.Configuration; 32 import android.content.res.Resources; 33 import android.content.res.TypedArray; 34 import android.content.res.XmlResourceParser; 35 import android.os.Build; 36 import android.os.Bundle; 37 import android.os.FileUtils; 38 import android.os.PatternMatcher; 39 import android.os.Trace; 40 import android.os.UserHandle; 41 import android.text.TextUtils; 42 import android.util.ArrayMap; 43 import android.util.ArraySet; 44 import android.util.AttributeSet; 45 import android.util.Base64; 46 import android.util.DisplayMetrics; 47 import android.util.Log; 48 import android.util.Pair; 49 import android.util.Slog; 50 import android.util.TypedValue; 51 import android.util.apk.ApkSignatureSchemeV2Verifier; 52 import android.util.jar.StrictJarFile; 53 import android.view.Gravity; 54 55 import java.io.File; 56 import java.io.IOException; 57 import java.io.InputStream; 58 import java.io.PrintWriter; 59 import java.security.GeneralSecurityException; 60 import java.security.KeyFactory; 61 import java.security.NoSuchAlgorithmException; 62 import java.security.PublicKey; 63 import java.security.cert.Certificate; 64 import java.security.cert.CertificateEncodingException; 65 import java.security.spec.EncodedKeySpec; 66 import java.security.spec.InvalidKeySpecException; 67 import java.security.spec.X509EncodedKeySpec; 68 import java.util.ArrayList; 69 import java.util.Arrays; 70 import java.util.Collections; 71 import java.util.Comparator; 72 import java.util.Iterator; 73 import java.util.List; 74 import java.util.Set; 75 import java.util.concurrent.atomic.AtomicReference; 76 import java.util.zip.ZipEntry; 77 78 import libcore.io.IoUtils; 79 80 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; 81 import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE; 82 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; 83 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 84 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE; 85 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; 86 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 87 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED; 88 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES; 89 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; 90 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 91 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; 92 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; 93 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 94 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; 95 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; 96 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; 97 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; 98 99 /** 100 * Parser for package files (APKs) on disk. This supports apps packaged either 101 * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple 102 * APKs in a single directory. 103 * <p> 104 * Apps packaged as multiple APKs always consist of a single "base" APK (with a 105 * {@code null} split name) and zero or more "split" APKs (with unique split 106 * names). Any subset of those split APKs are a valid install, as long as the 107 * following constraints are met: 108 * <ul> 109 * <li>All APKs must have the exact same package name, version code, and signing 110 * certificates. 111 * <li>All APKs must have unique split names. 112 * <li>All installations must contain a single base APK. 113 * </ul> 114 * 115 * @hide 116 */ 117 public class PackageParser { 118 private static final boolean DEBUG_JAR = false; 119 private static final boolean DEBUG_PARSER = false; 120 private static final boolean DEBUG_BACKUP = false; 121 122 private static final boolean MULTI_PACKAGE_APK_ENABLED = false; 123 private static final int MAX_PACKAGES_PER_APK = 5; 124 125 public static final int APK_SIGNING_UNKNOWN = 0; 126 public static final int APK_SIGNING_V1 = 1; 127 public static final int APK_SIGNING_V2 = 2; 128 129 // TODO: switch outError users to PackageParserException 130 // TODO: refactor "codePath" to "apkPath" 131 132 /** File name in an APK for the Android manifest. */ 133 private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; 134 135 /** Path prefix for apps on expanded storage */ 136 private static final String MNT_EXPAND = "/mnt/expand/"; 137 138 private static final String TAG_MANIFEST = "manifest"; 139 private static final String TAG_APPLICATION = "application"; 140 private static final String TAG_OVERLAY = "overlay"; 141 private static final String TAG_KEY_SETS = "key-sets"; 142 private static final String TAG_PERMISSION_GROUP = "permission-group"; 143 private static final String TAG_PERMISSION = "permission"; 144 private static final String TAG_PERMISSION_TREE = "permission-tree"; 145 private static final String TAG_USES_PERMISSION = "uses-permission"; 146 private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; 147 private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23"; 148 private static final String TAG_USES_CONFIGURATION = "uses-configuration"; 149 private static final String TAG_USES_FEATURE = "uses-feature"; 150 private static final String TAG_FEATURE_GROUP = "feature-group"; 151 private static final String TAG_USES_SDK = "uses-sdk"; 152 private static final String TAG_SUPPORT_SCREENS = "supports-screens"; 153 private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast"; 154 private static final String TAG_INSTRUMENTATION = "instrumentation"; 155 private static final String TAG_ORIGINAL_PACKAGE = "original-package"; 156 private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; 157 private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture"; 158 private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens"; 159 private static final String TAG_SUPPORTS_INPUT = "supports-input"; 160 private static final String TAG_EAT_COMMENT = "eat-comment"; 161 private static final String TAG_PACKAGE = "package"; 162 private static final String TAG_RESTRICT_UPDATE = "restrict-update"; 163 164 // These are the tags supported by child packages 165 private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>(); 166 static { 167 CHILD_PACKAGE_TAGS.add(TAG_APPLICATION); 168 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION); 169 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M); 170 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23); 171 CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION); 172 CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE); 173 CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP); 174 CHILD_PACKAGE_TAGS.add(TAG_USES_SDK); 175 CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS); 176 CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION); 177 CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE); 178 CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS); 179 CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT); 180 CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT); 181 } 182 183 /** @hide */ 184 public static class NewPermissionInfo { 185 public final String name; 186 public final int sdkVersion; 187 public final int fileVersion; 188 189 public NewPermissionInfo(String name, int sdkVersion, int fileVersion) { 190 this.name = name; 191 this.sdkVersion = sdkVersion; 192 this.fileVersion = fileVersion; 193 } 194 } 195 196 /** @hide */ 197 public static class SplitPermissionInfo { 198 public final String rootPerm; 199 public final String[] newPerms; 200 public final int targetSdk; 201 202 public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) { 203 this.rootPerm = rootPerm; 204 this.newPerms = newPerms; 205 this.targetSdk = targetSdk; 206 } 207 } 208 209 /** 210 * List of new permissions that have been added since 1.0. 211 * NOTE: These must be declared in SDK version order, with permissions 212 * added to older SDKs appearing before those added to newer SDKs. 213 * If sdkVersion is 0, then this is not a permission that we want to 214 * automatically add to older apps, but we do want to allow it to be 215 * granted during a platform update. 216 * @hide 217 */ 218 public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] = 219 new PackageParser.NewPermissionInfo[] { 220 new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 221 android.os.Build.VERSION_CODES.DONUT, 0), 222 new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE, 223 android.os.Build.VERSION_CODES.DONUT, 0) 224 }; 225 226 /** 227 * List of permissions that have been split into more granular or dependent 228 * permissions. 229 * @hide 230 */ 231 public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] = 232 new PackageParser.SplitPermissionInfo[] { 233 // READ_EXTERNAL_STORAGE is always required when an app requests 234 // WRITE_EXTERNAL_STORAGE, because we can't have an app that has 235 // write access without read access. The hack here with the target 236 // target SDK version ensures that this grant is always done. 237 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 238 new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE }, 239 android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1), 240 new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS, 241 new String[] { android.Manifest.permission.READ_CALL_LOG }, 242 android.os.Build.VERSION_CODES.JELLY_BEAN), 243 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS, 244 new String[] { android.Manifest.permission.WRITE_CALL_LOG }, 245 android.os.Build.VERSION_CODES.JELLY_BEAN) 246 }; 247 248 /** 249 * @deprecated callers should move to explicitly passing around source path. 250 */ 251 @Deprecated 252 private String mArchiveSourcePath; 253 254 private String[] mSeparateProcesses; 255 private boolean mOnlyCoreApps; 256 private DisplayMetrics mMetrics; 257 258 private static final int SDK_VERSION = Build.VERSION.SDK_INT; 259 private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES; 260 261 private int mParseError = PackageManager.INSTALL_SUCCEEDED; 262 263 private static boolean sCompatibilityModeEnabled = true; 264 private static final int PARSE_DEFAULT_INSTALL_LOCATION = 265 PackageInfo.INSTALL_LOCATION_UNSPECIFIED; 266 267 static class ParsePackageItemArgs { 268 final Package owner; 269 final String[] outError; 270 final int nameRes; 271 final int labelRes; 272 final int iconRes; 273 final int roundIconRes; 274 final int logoRes; 275 final int bannerRes; 276 277 String tag; 278 TypedArray sa; 279 280 ParsePackageItemArgs(Package _owner, String[] _outError, 281 int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes, 282 int _bannerRes) { 283 owner = _owner; 284 outError = _outError; 285 nameRes = _nameRes; 286 labelRes = _labelRes; 287 iconRes = _iconRes; 288 logoRes = _logoRes; 289 bannerRes = _bannerRes; 290 roundIconRes = _roundIconRes; 291 } 292 } 293 294 static class ParseComponentArgs extends ParsePackageItemArgs { 295 final String[] sepProcesses; 296 final int processRes; 297 final int descriptionRes; 298 final int enabledRes; 299 int flags; 300 301 ParseComponentArgs(Package _owner, String[] _outError, 302 int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes, 303 int _bannerRes, 304 String[] _sepProcesses, int _processRes, 305 int _descriptionRes, int _enabledRes) { 306 super(_owner, _outError, _nameRes, _labelRes, _iconRes, _roundIconRes, _logoRes, 307 _bannerRes); 308 sepProcesses = _sepProcesses; 309 processRes = _processRes; 310 descriptionRes = _descriptionRes; 311 enabledRes = _enabledRes; 312 } 313 } 314 315 /** 316 * Lightweight parsed details about a single package. 317 */ 318 public static class PackageLite { 319 public final String packageName; 320 public final int versionCode; 321 public final int installLocation; 322 public final VerifierInfo[] verifiers; 323 324 /** Names of any split APKs, ordered by parsed splitName */ 325 public final String[] splitNames; 326 327 /** 328 * Path where this package was found on disk. For monolithic packages 329 * this is path to single base APK file; for cluster packages this is 330 * path to the cluster directory. 331 */ 332 public final String codePath; 333 334 /** Path of base APK */ 335 public final String baseCodePath; 336 /** Paths of any split APKs, ordered by parsed splitName */ 337 public final String[] splitCodePaths; 338 339 /** Revision code of base APK */ 340 public final int baseRevisionCode; 341 /** Revision codes of any split APKs, ordered by parsed splitName */ 342 public final int[] splitRevisionCodes; 343 344 public final boolean coreApp; 345 public final boolean multiArch; 346 public final boolean use32bitAbi; 347 public final boolean extractNativeLibs; 348 349 public PackageLite(String codePath, ApkLite baseApk, String[] splitNames, 350 String[] splitCodePaths, int[] splitRevisionCodes) { 351 this.packageName = baseApk.packageName; 352 this.versionCode = baseApk.versionCode; 353 this.installLocation = baseApk.installLocation; 354 this.verifiers = baseApk.verifiers; 355 this.splitNames = splitNames; 356 this.codePath = codePath; 357 this.baseCodePath = baseApk.codePath; 358 this.splitCodePaths = splitCodePaths; 359 this.baseRevisionCode = baseApk.revisionCode; 360 this.splitRevisionCodes = splitRevisionCodes; 361 this.coreApp = baseApk.coreApp; 362 this.multiArch = baseApk.multiArch; 363 this.use32bitAbi = baseApk.use32bitAbi; 364 this.extractNativeLibs = baseApk.extractNativeLibs; 365 } 366 367 public List<String> getAllCodePaths() { 368 ArrayList<String> paths = new ArrayList<>(); 369 paths.add(baseCodePath); 370 if (!ArrayUtils.isEmpty(splitCodePaths)) { 371 Collections.addAll(paths, splitCodePaths); 372 } 373 return paths; 374 } 375 } 376 377 /** 378 * Lightweight parsed details about a single APK file. 379 */ 380 public static class ApkLite { 381 public final String codePath; 382 public final String packageName; 383 public final String splitName; 384 public final int versionCode; 385 public final int revisionCode; 386 public final int installLocation; 387 public final VerifierInfo[] verifiers; 388 public final Signature[] signatures; 389 public final Certificate[][] certificates; 390 public final boolean coreApp; 391 public final boolean multiArch; 392 public final boolean use32bitAbi; 393 public final boolean extractNativeLibs; 394 395 public ApkLite(String codePath, String packageName, String splitName, int versionCode, 396 int revisionCode, int installLocation, List<VerifierInfo> verifiers, 397 Signature[] signatures, Certificate[][] certificates, boolean coreApp, 398 boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs) { 399 this.codePath = codePath; 400 this.packageName = packageName; 401 this.splitName = splitName; 402 this.versionCode = versionCode; 403 this.revisionCode = revisionCode; 404 this.installLocation = installLocation; 405 this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]); 406 this.signatures = signatures; 407 this.certificates = certificates; 408 this.coreApp = coreApp; 409 this.multiArch = multiArch; 410 this.use32bitAbi = use32bitAbi; 411 this.extractNativeLibs = extractNativeLibs; 412 } 413 } 414 415 private ParsePackageItemArgs mParseInstrumentationArgs; 416 private ParseComponentArgs mParseActivityArgs; 417 private ParseComponentArgs mParseActivityAliasArgs; 418 private ParseComponentArgs mParseServiceArgs; 419 private ParseComponentArgs mParseProviderArgs; 420 421 /** If set to true, we will only allow package files that exactly match 422 * the DTD. Otherwise, we try to get as much from the package as we 423 * can without failing. This should normally be set to false, to 424 * support extensions to the DTD in future versions. */ 425 private static final boolean RIGID_PARSER = false; 426 427 private static final String TAG = "PackageParser"; 428 429 public PackageParser() { 430 mMetrics = new DisplayMetrics(); 431 mMetrics.setToDefaults(); 432 } 433 434 public void setSeparateProcesses(String[] procs) { 435 mSeparateProcesses = procs; 436 } 437 438 /** 439 * Flag indicating this parser should only consider apps with 440 * {@code coreApp} manifest attribute to be valid apps. This is useful when 441 * creating a minimalist boot environment. 442 */ 443 public void setOnlyCoreApps(boolean onlyCoreApps) { 444 mOnlyCoreApps = onlyCoreApps; 445 } 446 447 public void setDisplayMetrics(DisplayMetrics metrics) { 448 mMetrics = metrics; 449 } 450 451 public static final boolean isApkFile(File file) { 452 return isApkPath(file.getName()); 453 } 454 455 private static boolean isApkPath(String path) { 456 return path.endsWith(".apk"); 457 } 458 459 /** 460 * Generate and return the {@link PackageInfo} for a parsed package. 461 * 462 * @param p the parsed package. 463 * @param flags indicating which optional information is included. 464 */ 465 public static PackageInfo generatePackageInfo(PackageParser.Package p, 466 int gids[], int flags, long firstInstallTime, long lastUpdateTime, 467 Set<String> grantedPermissions, PackageUserState state) { 468 469 return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, 470 grantedPermissions, state, UserHandle.getCallingUserId()); 471 } 472 473 /** 474 * Returns true if the package is installed and not hidden, or if the caller 475 * explicitly wanted all uninstalled and hidden packages as well. 476 */ 477 private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state) { 478 return (state.installed && !state.hidden) 479 || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; 480 } 481 482 public static boolean isAvailable(PackageUserState state) { 483 return checkUseInstalledOrHidden(0, state); 484 } 485 486 public static PackageInfo generatePackageInfo(PackageParser.Package p, 487 int gids[], int flags, long firstInstallTime, long lastUpdateTime, 488 Set<String> grantedPermissions, PackageUserState state, int userId) { 489 if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) { 490 return null; 491 } 492 PackageInfo pi = new PackageInfo(); 493 pi.packageName = p.packageName; 494 pi.splitNames = p.splitNames; 495 pi.versionCode = p.mVersionCode; 496 pi.baseRevisionCode = p.baseRevisionCode; 497 pi.splitRevisionCodes = p.splitRevisionCodes; 498 pi.versionName = p.mVersionName; 499 pi.sharedUserId = p.mSharedUserId; 500 pi.sharedUserLabel = p.mSharedUserLabel; 501 pi.applicationInfo = generateApplicationInfo(p, flags, state, userId); 502 pi.installLocation = p.installLocation; 503 pi.coreApp = p.coreApp; 504 if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0 505 || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { 506 pi.requiredForAllUsers = p.mRequiredForAllUsers; 507 } 508 pi.restrictedAccountType = p.mRestrictedAccountType; 509 pi.requiredAccountType = p.mRequiredAccountType; 510 pi.overlayTarget = p.mOverlayTarget; 511 pi.firstInstallTime = firstInstallTime; 512 pi.lastUpdateTime = lastUpdateTime; 513 if ((flags&PackageManager.GET_GIDS) != 0) { 514 pi.gids = gids; 515 } 516 if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) { 517 int N = p.configPreferences != null ? p.configPreferences.size() : 0; 518 if (N > 0) { 519 pi.configPreferences = new ConfigurationInfo[N]; 520 p.configPreferences.toArray(pi.configPreferences); 521 } 522 N = p.reqFeatures != null ? p.reqFeatures.size() : 0; 523 if (N > 0) { 524 pi.reqFeatures = new FeatureInfo[N]; 525 p.reqFeatures.toArray(pi.reqFeatures); 526 } 527 N = p.featureGroups != null ? p.featureGroups.size() : 0; 528 if (N > 0) { 529 pi.featureGroups = new FeatureGroupInfo[N]; 530 p.featureGroups.toArray(pi.featureGroups); 531 } 532 } 533 if ((flags & PackageManager.GET_ACTIVITIES) != 0) { 534 final int N = p.activities.size(); 535 if (N > 0) { 536 int num = 0; 537 final ActivityInfo[] res = new ActivityInfo[N]; 538 for (int i = 0; i < N; i++) { 539 final Activity a = p.activities.get(i); 540 if (state.isMatch(a.info, flags)) { 541 res[num++] = generateActivityInfo(a, flags, state, userId); 542 } 543 } 544 pi.activities = ArrayUtils.trimToSize(res, num); 545 } 546 } 547 if ((flags & PackageManager.GET_RECEIVERS) != 0) { 548 final int N = p.receivers.size(); 549 if (N > 0) { 550 int num = 0; 551 final ActivityInfo[] res = new ActivityInfo[N]; 552 for (int i = 0; i < N; i++) { 553 final Activity a = p.receivers.get(i); 554 if (state.isMatch(a.info, flags)) { 555 res[num++] = generateActivityInfo(a, flags, state, userId); 556 } 557 } 558 pi.receivers = ArrayUtils.trimToSize(res, num); 559 } 560 } 561 if ((flags & PackageManager.GET_SERVICES) != 0) { 562 final int N = p.services.size(); 563 if (N > 0) { 564 int num = 0; 565 final ServiceInfo[] res = new ServiceInfo[N]; 566 for (int i = 0; i < N; i++) { 567 final Service s = p.services.get(i); 568 if (state.isMatch(s.info, flags)) { 569 res[num++] = generateServiceInfo(s, flags, state, userId); 570 } 571 } 572 pi.services = ArrayUtils.trimToSize(res, num); 573 } 574 } 575 if ((flags & PackageManager.GET_PROVIDERS) != 0) { 576 final int N = p.providers.size(); 577 if (N > 0) { 578 int num = 0; 579 final ProviderInfo[] res = new ProviderInfo[N]; 580 for (int i = 0; i < N; i++) { 581 final Provider pr = p.providers.get(i); 582 if (state.isMatch(pr.info, flags)) { 583 res[num++] = generateProviderInfo(pr, flags, state, userId); 584 } 585 } 586 pi.providers = ArrayUtils.trimToSize(res, num); 587 } 588 } 589 if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) { 590 int N = p.instrumentation.size(); 591 if (N > 0) { 592 pi.instrumentation = new InstrumentationInfo[N]; 593 for (int i=0; i<N; i++) { 594 pi.instrumentation[i] = generateInstrumentationInfo( 595 p.instrumentation.get(i), flags); 596 } 597 } 598 } 599 if ((flags&PackageManager.GET_PERMISSIONS) != 0) { 600 int N = p.permissions.size(); 601 if (N > 0) { 602 pi.permissions = new PermissionInfo[N]; 603 for (int i=0; i<N; i++) { 604 pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags); 605 } 606 } 607 N = p.requestedPermissions.size(); 608 if (N > 0) { 609 pi.requestedPermissions = new String[N]; 610 pi.requestedPermissionsFlags = new int[N]; 611 for (int i=0; i<N; i++) { 612 final String perm = p.requestedPermissions.get(i); 613 pi.requestedPermissions[i] = perm; 614 // The notion of required permissions is deprecated but for compatibility. 615 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED; 616 if (grantedPermissions != null && grantedPermissions.contains(perm)) { 617 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED; 618 } 619 } 620 } 621 } 622 if ((flags&PackageManager.GET_SIGNATURES) != 0) { 623 int N = (p.mSignatures != null) ? p.mSignatures.length : 0; 624 if (N > 0) { 625 pi.signatures = new Signature[N]; 626 System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N); 627 } 628 } 629 return pi; 630 } 631 632 private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry) 633 throws PackageParserException { 634 InputStream is = null; 635 try { 636 // We must read the stream for the JarEntry to retrieve 637 // its certificates. 638 is = jarFile.getInputStream(entry); 639 readFullyIgnoringContents(is); 640 return jarFile.getCertificateChains(entry); 641 } catch (IOException | RuntimeException e) { 642 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 643 "Failed reading " + entry.getName() + " in " + jarFile, e); 644 } finally { 645 IoUtils.closeQuietly(is); 646 } 647 } 648 649 public final static int PARSE_IS_SYSTEM = 1<<0; 650 public final static int PARSE_CHATTY = 1<<1; 651 public final static int PARSE_MUST_BE_APK = 1<<2; 652 public final static int PARSE_IGNORE_PROCESSES = 1<<3; 653 public final static int PARSE_FORWARD_LOCK = 1<<4; 654 public final static int PARSE_EXTERNAL_STORAGE = 1<<5; 655 public final static int PARSE_IS_SYSTEM_DIR = 1<<6; 656 public final static int PARSE_IS_PRIVILEGED = 1<<7; 657 public final static int PARSE_COLLECT_CERTIFICATES = 1<<8; 658 public final static int PARSE_TRUSTED_OVERLAY = 1<<9; 659 public final static int PARSE_ENFORCE_CODE = 1<<10; 660 public final static int PARSE_IS_EPHEMERAL = 1<<11; 661 public final static int PARSE_FORCE_SDK = 1<<12; 662 663 private static final Comparator<String> sSplitNameComparator = new SplitNameComparator(); 664 665 /** 666 * Used to sort a set of APKs based on their split names, always placing the 667 * base APK (with {@code null} split name) first. 668 */ 669 private static class SplitNameComparator implements Comparator<String> { 670 @Override 671 public int compare(String lhs, String rhs) { 672 if (lhs == null) { 673 return -1; 674 } else if (rhs == null) { 675 return 1; 676 } else { 677 return lhs.compareTo(rhs); 678 } 679 } 680 } 681 682 /** 683 * Parse only lightweight details about the package at the given location. 684 * Automatically detects if the package is a monolithic style (single APK 685 * file) or cluster style (directory of APKs). 686 * <p> 687 * This performs sanity checking on cluster style packages, such as 688 * requiring identical package name and version codes, a single base APK, 689 * and unique split names. 690 * 691 * @see PackageParser#parsePackage(File, int) 692 */ 693 public static PackageLite parsePackageLite(File packageFile, int flags) 694 throws PackageParserException { 695 if (packageFile.isDirectory()) { 696 return parseClusterPackageLite(packageFile, flags); 697 } else { 698 return parseMonolithicPackageLite(packageFile, flags); 699 } 700 } 701 702 private static PackageLite parseMonolithicPackageLite(File packageFile, int flags) 703 throws PackageParserException { 704 final ApkLite baseApk = parseApkLite(packageFile, flags); 705 final String packagePath = packageFile.getAbsolutePath(); 706 return new PackageLite(packagePath, baseApk, null, null, null); 707 } 708 709 private static PackageLite parseClusterPackageLite(File packageDir, int flags) 710 throws PackageParserException { 711 final File[] files = packageDir.listFiles(); 712 if (ArrayUtils.isEmpty(files)) { 713 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 714 "No packages found in split"); 715 } 716 717 String packageName = null; 718 int versionCode = 0; 719 720 final ArrayMap<String, ApkLite> apks = new ArrayMap<>(); 721 for (File file : files) { 722 if (isApkFile(file)) { 723 final ApkLite lite = parseApkLite(file, flags); 724 725 // Assert that all package names and version codes are 726 // consistent with the first one we encounter. 727 if (packageName == null) { 728 packageName = lite.packageName; 729 versionCode = lite.versionCode; 730 } else { 731 if (!packageName.equals(lite.packageName)) { 732 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 733 "Inconsistent package " + lite.packageName + " in " + file 734 + "; expected " + packageName); 735 } 736 if (versionCode != lite.versionCode) { 737 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 738 "Inconsistent version " + lite.versionCode + " in " + file 739 + "; expected " + versionCode); 740 } 741 } 742 743 // Assert that each split is defined only once 744 if (apks.put(lite.splitName, lite) != null) { 745 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 746 "Split name " + lite.splitName 747 + " defined more than once; most recent was " + file); 748 } 749 } 750 } 751 752 final ApkLite baseApk = apks.remove(null); 753 if (baseApk == null) { 754 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 755 "Missing base APK in " + packageDir); 756 } 757 758 // Always apply deterministic ordering based on splitName 759 final int size = apks.size(); 760 761 String[] splitNames = null; 762 String[] splitCodePaths = null; 763 int[] splitRevisionCodes = null; 764 if (size > 0) { 765 splitNames = new String[size]; 766 splitCodePaths = new String[size]; 767 splitRevisionCodes = new int[size]; 768 769 splitNames = apks.keySet().toArray(splitNames); 770 Arrays.sort(splitNames, sSplitNameComparator); 771 772 for (int i = 0; i < size; i++) { 773 splitCodePaths[i] = apks.get(splitNames[i]).codePath; 774 splitRevisionCodes[i] = apks.get(splitNames[i]).revisionCode; 775 } 776 } 777 778 final String codePath = packageDir.getAbsolutePath(); 779 return new PackageLite(codePath, baseApk, splitNames, splitCodePaths, 780 splitRevisionCodes); 781 } 782 783 /** 784 * Parse the package at the given location. Automatically detects if the 785 * package is a monolithic style (single APK file) or cluster style 786 * (directory of APKs). 787 * <p> 788 * This performs sanity checking on cluster style packages, such as 789 * requiring identical package name and version codes, a single base APK, 790 * and unique split names. 791 * <p> 792 * Note that this <em>does not</em> perform signature verification; that 793 * must be done separately in {@link #collectCertificates(Package, int)}. 794 * 795 * @see #parsePackageLite(File, int) 796 */ 797 public Package parsePackage(File packageFile, int flags) throws PackageParserException { 798 if (packageFile.isDirectory()) { 799 return parseClusterPackage(packageFile, flags); 800 } else { 801 return parseMonolithicPackage(packageFile, flags); 802 } 803 } 804 805 /** 806 * Parse all APKs contained in the given directory, treating them as a 807 * single package. This also performs sanity checking, such as requiring 808 * identical package name and version codes, a single base APK, and unique 809 * split names. 810 * <p> 811 * Note that this <em>does not</em> perform signature verification; that 812 * must be done separately in {@link #collectCertificates(Package, int)}. 813 */ 814 private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException { 815 final PackageLite lite = parseClusterPackageLite(packageDir, 0); 816 817 if (mOnlyCoreApps && !lite.coreApp) { 818 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 819 "Not a coreApp: " + packageDir); 820 } 821 822 final AssetManager assets = new AssetManager(); 823 try { 824 // Load the base and all splits into the AssetManager 825 // so that resources can be overriden when parsing the manifests. 826 loadApkIntoAssetManager(assets, lite.baseCodePath, flags); 827 828 if (!ArrayUtils.isEmpty(lite.splitCodePaths)) { 829 for (String path : lite.splitCodePaths) { 830 loadApkIntoAssetManager(assets, path, flags); 831 } 832 } 833 834 final File baseApk = new File(lite.baseCodePath); 835 final Package pkg = parseBaseApk(baseApk, assets, flags); 836 if (pkg == null) { 837 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 838 "Failed to parse base APK: " + baseApk); 839 } 840 841 if (!ArrayUtils.isEmpty(lite.splitNames)) { 842 final int num = lite.splitNames.length; 843 pkg.splitNames = lite.splitNames; 844 pkg.splitCodePaths = lite.splitCodePaths; 845 pkg.splitRevisionCodes = lite.splitRevisionCodes; 846 pkg.splitFlags = new int[num]; 847 pkg.splitPrivateFlags = new int[num]; 848 849 for (int i = 0; i < num; i++) { 850 parseSplitApk(pkg, i, assets, flags); 851 } 852 } 853 854 pkg.setCodePath(packageDir.getAbsolutePath()); 855 pkg.setUse32bitAbi(lite.use32bitAbi); 856 return pkg; 857 } finally { 858 IoUtils.closeQuietly(assets); 859 } 860 } 861 862 /** 863 * Parse the given APK file, treating it as as a single monolithic package. 864 * <p> 865 * Note that this <em>does not</em> perform signature verification; that 866 * must be done separately in {@link #collectCertificates(Package, int)}. 867 * 868 * @deprecated external callers should move to 869 * {@link #parsePackage(File, int)}. Eventually this method will 870 * be marked private. 871 */ 872 @Deprecated 873 public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException { 874 final PackageLite lite = parseMonolithicPackageLite(apkFile, flags); 875 if (mOnlyCoreApps) { 876 if (!lite.coreApp) { 877 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 878 "Not a coreApp: " + apkFile); 879 } 880 } 881 882 final AssetManager assets = new AssetManager(); 883 try { 884 final Package pkg = parseBaseApk(apkFile, assets, flags); 885 pkg.setCodePath(apkFile.getAbsolutePath()); 886 pkg.setUse32bitAbi(lite.use32bitAbi); 887 return pkg; 888 } finally { 889 IoUtils.closeQuietly(assets); 890 } 891 } 892 893 private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags) 894 throws PackageParserException { 895 if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) { 896 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 897 "Invalid package file: " + apkPath); 898 } 899 900 // The AssetManager guarantees uniqueness for asset paths, so if this asset path 901 // already exists in the AssetManager, addAssetPath will only return the cookie 902 // assigned to it. 903 int cookie = assets.addAssetPath(apkPath); 904 if (cookie == 0) { 905 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 906 "Failed adding asset path: " + apkPath); 907 } 908 return cookie; 909 } 910 911 private Package parseBaseApk(File apkFile, AssetManager assets, int flags) 912 throws PackageParserException { 913 final String apkPath = apkFile.getAbsolutePath(); 914 915 String volumeUuid = null; 916 if (apkPath.startsWith(MNT_EXPAND)) { 917 final int end = apkPath.indexOf('/', MNT_EXPAND.length()); 918 volumeUuid = apkPath.substring(MNT_EXPAND.length(), end); 919 } 920 921 mParseError = PackageManager.INSTALL_SUCCEEDED; 922 mArchiveSourcePath = apkFile.getAbsolutePath(); 923 924 if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); 925 926 final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); 927 928 Resources res = null; 929 XmlResourceParser parser = null; 930 try { 931 res = new Resources(assets, mMetrics, null); 932 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 933 Build.VERSION.RESOURCES_SDK_INT); 934 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 935 936 final String[] outError = new String[1]; 937 final Package pkg = parseBaseApk(res, parser, flags, outError); 938 if (pkg == null) { 939 throw new PackageParserException(mParseError, 940 apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]); 941 } 942 943 pkg.setVolumeUuid(volumeUuid); 944 pkg.setApplicationVolumeUuid(volumeUuid); 945 pkg.setBaseCodePath(apkPath); 946 pkg.setSignatures(null); 947 948 return pkg; 949 950 } catch (PackageParserException e) { 951 throw e; 952 } catch (Exception e) { 953 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 954 "Failed to read manifest from " + apkPath, e); 955 } finally { 956 IoUtils.closeQuietly(parser); 957 } 958 } 959 960 private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags) 961 throws PackageParserException { 962 final String apkPath = pkg.splitCodePaths[splitIndex]; 963 964 mParseError = PackageManager.INSTALL_SUCCEEDED; 965 mArchiveSourcePath = apkPath; 966 967 if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); 968 969 final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); 970 971 Resources res = null; 972 XmlResourceParser parser = null; 973 try { 974 res = new Resources(assets, mMetrics, null); 975 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 976 Build.VERSION.RESOURCES_SDK_INT); 977 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 978 979 final String[] outError = new String[1]; 980 pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError); 981 if (pkg == null) { 982 throw new PackageParserException(mParseError, 983 apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]); 984 } 985 986 } catch (PackageParserException e) { 987 throw e; 988 } catch (Exception e) { 989 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 990 "Failed to read manifest from " + apkPath, e); 991 } finally { 992 IoUtils.closeQuietly(parser); 993 } 994 } 995 996 /** 997 * Parse the manifest of a <em>split APK</em>. 998 * <p> 999 * Note that split APKs have many more restrictions on what they're capable 1000 * of doing, so many valid features of a base APK have been carefully 1001 * omitted here. 1002 */ 1003 private Package parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags, 1004 int splitIndex, String[] outError) throws XmlPullParserException, IOException, 1005 PackageParserException { 1006 AttributeSet attrs = parser; 1007 1008 // We parsed manifest tag earlier; just skip past it 1009 parsePackageSplitNames(parser, attrs); 1010 1011 mParseInstrumentationArgs = null; 1012 mParseActivityArgs = null; 1013 mParseServiceArgs = null; 1014 mParseProviderArgs = null; 1015 1016 int type; 1017 1018 boolean foundApp = false; 1019 1020 int outerDepth = parser.getDepth(); 1021 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1022 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1023 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1024 continue; 1025 } 1026 1027 String tagName = parser.getName(); 1028 if (tagName.equals("application")) { 1029 if (foundApp) { 1030 if (RIGID_PARSER) { 1031 outError[0] = "<manifest> has more than one <application>"; 1032 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1033 return null; 1034 } else { 1035 Slog.w(TAG, "<manifest> has more than one <application>"); 1036 XmlUtils.skipCurrentTag(parser); 1037 continue; 1038 } 1039 } 1040 1041 foundApp = true; 1042 if (!parseSplitApplication(pkg, res, parser, flags, splitIndex, outError)) { 1043 return null; 1044 } 1045 1046 } else if (RIGID_PARSER) { 1047 outError[0] = "Bad element under <manifest>: " 1048 + parser.getName(); 1049 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1050 return null; 1051 1052 } else { 1053 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() 1054 + " at " + mArchiveSourcePath + " " 1055 + parser.getPositionDescription()); 1056 XmlUtils.skipCurrentTag(parser); 1057 continue; 1058 } 1059 } 1060 1061 if (!foundApp) { 1062 outError[0] = "<manifest> does not contain an <application>"; 1063 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; 1064 } 1065 1066 return pkg; 1067 } 1068 1069 public static int getApkSigningVersion(Package pkg) { 1070 try { 1071 if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) { 1072 return APK_SIGNING_V2; 1073 } 1074 return APK_SIGNING_V1; 1075 } catch (IOException e) { 1076 } 1077 return APK_SIGNING_UNKNOWN; 1078 } 1079 1080 /** 1081 * Populates the correct packages fields with the given certificates. 1082 * <p> 1083 * This is useful when we've already processed the certificates [such as during package 1084 * installation through an installer session]. We don't re-process the archive and 1085 * simply populate the correct fields. 1086 */ 1087 public static void populateCertificates(Package pkg, Certificate[][] certificates) 1088 throws PackageParserException { 1089 pkg.mCertificates = null; 1090 pkg.mSignatures = null; 1091 pkg.mSigningKeys = null; 1092 1093 pkg.mCertificates = certificates; 1094 try { 1095 pkg.mSignatures = convertToSignatures(certificates); 1096 } catch (CertificateEncodingException e) { 1097 // certificates weren't encoded properly; something went wrong 1098 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1099 "Failed to collect certificates from " + pkg.baseCodePath, e); 1100 } 1101 pkg.mSigningKeys = new ArraySet<>(certificates.length); 1102 for (int i = 0; i < certificates.length; i++) { 1103 Certificate[] signerCerts = certificates[i]; 1104 Certificate signerCert = signerCerts[0]; 1105 pkg.mSigningKeys.add(signerCert.getPublicKey()); 1106 } 1107 // add signatures to child packages 1108 final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; 1109 for (int i = 0; i < childCount; i++) { 1110 Package childPkg = pkg.childPackages.get(i); 1111 childPkg.mCertificates = pkg.mCertificates; 1112 childPkg.mSignatures = pkg.mSignatures; 1113 childPkg.mSigningKeys = pkg.mSigningKeys; 1114 } 1115 } 1116 1117 /** 1118 * Collect certificates from all the APKs described in the given package, 1119 * populating {@link Package#mSignatures}. Also asserts that all APK 1120 * contents are signed correctly and consistently. 1121 */ 1122 public static void collectCertificates(Package pkg, int parseFlags) 1123 throws PackageParserException { 1124 collectCertificatesInternal(pkg, parseFlags); 1125 final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; 1126 for (int i = 0; i < childCount; i++) { 1127 Package childPkg = pkg.childPackages.get(i); 1128 childPkg.mCertificates = pkg.mCertificates; 1129 childPkg.mSignatures = pkg.mSignatures; 1130 childPkg.mSigningKeys = pkg.mSigningKeys; 1131 } 1132 } 1133 1134 private static void collectCertificatesInternal(Package pkg, int parseFlags) 1135 throws PackageParserException { 1136 pkg.mCertificates = null; 1137 pkg.mSignatures = null; 1138 pkg.mSigningKeys = null; 1139 1140 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); 1141 try { 1142 collectCertificates(pkg, new File(pkg.baseCodePath), parseFlags); 1143 1144 if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { 1145 for (int i = 0; i < pkg.splitCodePaths.length; i++) { 1146 collectCertificates(pkg, new File(pkg.splitCodePaths[i]), parseFlags); 1147 } 1148 } 1149 } finally { 1150 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1151 } 1152 } 1153 1154 private static void collectCertificates(Package pkg, File apkFile, int parseFlags) 1155 throws PackageParserException { 1156 final String apkPath = apkFile.getAbsolutePath(); 1157 1158 // Try to verify the APK using APK Signature Scheme v2. 1159 boolean verified = false; 1160 { 1161 Certificate[][] allSignersCerts = null; 1162 Signature[] signatures = null; 1163 try { 1164 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2"); 1165 allSignersCerts = ApkSignatureSchemeV2Verifier.verify(apkPath); 1166 signatures = convertToSignatures(allSignersCerts); 1167 // APK verified using APK Signature Scheme v2. 1168 verified = true; 1169 } catch (ApkSignatureSchemeV2Verifier.SignatureNotFoundException e) { 1170 // No APK Signature Scheme v2 signature found 1171 } catch (Exception e) { 1172 // APK Signature Scheme v2 signature was found but did not verify 1173 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1174 "Failed to collect certificates from " + apkPath 1175 + " using APK Signature Scheme v2", 1176 e); 1177 } finally { 1178 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1179 } 1180 1181 if (verified) { 1182 if (pkg.mCertificates == null) { 1183 pkg.mCertificates = allSignersCerts; 1184 pkg.mSignatures = signatures; 1185 pkg.mSigningKeys = new ArraySet<>(allSignersCerts.length); 1186 for (int i = 0; i < allSignersCerts.length; i++) { 1187 Certificate[] signerCerts = allSignersCerts[i]; 1188 Certificate signerCert = signerCerts[0]; 1189 pkg.mSigningKeys.add(signerCert.getPublicKey()); 1190 } 1191 } else { 1192 if (!Signature.areExactMatch(pkg.mSignatures, signatures)) { 1193 throw new PackageParserException( 1194 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, 1195 apkPath + " has mismatched certificates"); 1196 } 1197 } 1198 // Not yet done, because we need to confirm that AndroidManifest.xml exists and, 1199 // if requested, that classes.dex exists. 1200 } 1201 } 1202 1203 StrictJarFile jarFile = null; 1204 try { 1205 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor"); 1206 // Ignore signature stripping protections when verifying APKs from system partition. 1207 // For those APKs we only care about extracting signer certificates, and don't care 1208 // about verifying integrity. 1209 boolean signatureSchemeRollbackProtectionsEnforced = 1210 (parseFlags & PARSE_IS_SYSTEM_DIR) == 0; 1211 jarFile = new StrictJarFile( 1212 apkPath, 1213 !verified, // whether to verify JAR signature 1214 signatureSchemeRollbackProtectionsEnforced); 1215 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1216 1217 // Always verify manifest, regardless of source 1218 final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME); 1219 if (manifestEntry == null) { 1220 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 1221 "Package " + apkPath + " has no manifest"); 1222 } 1223 1224 // Optimization: early termination when APK already verified 1225 if (verified) { 1226 return; 1227 } 1228 1229 // APK's integrity needs to be verified using JAR signature scheme. 1230 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV1"); 1231 final List<ZipEntry> toVerify = new ArrayList<>(); 1232 toVerify.add(manifestEntry); 1233 1234 // If we're parsing an untrusted package, verify all contents 1235 if ((parseFlags & PARSE_IS_SYSTEM_DIR) == 0) { 1236 final Iterator<ZipEntry> i = jarFile.iterator(); 1237 while (i.hasNext()) { 1238 final ZipEntry entry = i.next(); 1239 1240 if (entry.isDirectory()) continue; 1241 1242 final String entryName = entry.getName(); 1243 if (entryName.startsWith("META-INF/")) continue; 1244 if (entryName.equals(ANDROID_MANIFEST_FILENAME)) continue; 1245 1246 toVerify.add(entry); 1247 } 1248 } 1249 1250 // Verify that entries are signed consistently with the first entry 1251 // we encountered. Note that for splits, certificates may have 1252 // already been populated during an earlier parse of a base APK. 1253 for (ZipEntry entry : toVerify) { 1254 final Certificate[][] entryCerts = loadCertificates(jarFile, entry); 1255 if (ArrayUtils.isEmpty(entryCerts)) { 1256 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1257 "Package " + apkPath + " has no certificates at entry " 1258 + entry.getName()); 1259 } 1260 final Signature[] entrySignatures = convertToSignatures(entryCerts); 1261 1262 if (pkg.mCertificates == null) { 1263 pkg.mCertificates = entryCerts; 1264 pkg.mSignatures = entrySignatures; 1265 pkg.mSigningKeys = new ArraySet<PublicKey>(); 1266 for (int i=0; i < entryCerts.length; i++) { 1267 pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey()); 1268 } 1269 } else { 1270 if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) { 1271 throw new PackageParserException( 1272 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath 1273 + " has mismatched certificates at entry " 1274 + entry.getName()); 1275 } 1276 } 1277 } 1278 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1279 } catch (GeneralSecurityException e) { 1280 throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING, 1281 "Failed to collect certificates from " + apkPath, e); 1282 } catch (IOException | RuntimeException e) { 1283 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1284 "Failed to collect certificates from " + apkPath, e); 1285 } finally { 1286 closeQuietly(jarFile); 1287 } 1288 } 1289 1290 private static Signature[] convertToSignatures(Certificate[][] certs) 1291 throws CertificateEncodingException { 1292 final Signature[] res = new Signature[certs.length]; 1293 for (int i = 0; i < certs.length; i++) { 1294 res[i] = new Signature(certs[i]); 1295 } 1296 return res; 1297 } 1298 1299 /** 1300 * Utility method that retrieves lightweight details about a single APK 1301 * file, including package name, split name, and install location. 1302 * 1303 * @param apkFile path to a single APK 1304 * @param flags optional parse flags, such as 1305 * {@link #PARSE_COLLECT_CERTIFICATES} 1306 */ 1307 public static ApkLite parseApkLite(File apkFile, int flags) 1308 throws PackageParserException { 1309 final String apkPath = apkFile.getAbsolutePath(); 1310 1311 AssetManager assets = null; 1312 XmlResourceParser parser = null; 1313 try { 1314 assets = new AssetManager(); 1315 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1316 Build.VERSION.RESOURCES_SDK_INT); 1317 1318 int cookie = assets.addAssetPath(apkPath); 1319 if (cookie == 0) { 1320 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 1321 "Failed to parse " + apkPath); 1322 } 1323 1324 final DisplayMetrics metrics = new DisplayMetrics(); 1325 metrics.setToDefaults(); 1326 1327 final Resources res = new Resources(assets, metrics, null); 1328 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 1329 1330 final Signature[] signatures; 1331 final Certificate[][] certificates; 1332 if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { 1333 // TODO: factor signature related items out of Package object 1334 final Package tempPkg = new Package(null); 1335 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); 1336 try { 1337 collectCertificates(tempPkg, apkFile, 0 /*parseFlags*/); 1338 } finally { 1339 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1340 } 1341 signatures = tempPkg.mSignatures; 1342 certificates = tempPkg.mCertificates; 1343 } else { 1344 signatures = null; 1345 certificates = null; 1346 } 1347 1348 final AttributeSet attrs = parser; 1349 return parseApkLite(apkPath, res, parser, attrs, flags, signatures, certificates); 1350 1351 } catch (XmlPullParserException | IOException | RuntimeException e) { 1352 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 1353 "Failed to parse " + apkPath, e); 1354 } finally { 1355 IoUtils.closeQuietly(parser); 1356 IoUtils.closeQuietly(assets); 1357 } 1358 } 1359 1360 private static String validateName(String name, boolean requireSeparator, 1361 boolean requireFilename) { 1362 final int N = name.length(); 1363 boolean hasSep = false; 1364 boolean front = true; 1365 for (int i=0; i<N; i++) { 1366 final char c = name.charAt(i); 1367 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { 1368 front = false; 1369 continue; 1370 } 1371 if (!front) { 1372 if ((c >= '0' && c <= '9') || c == '_') { 1373 continue; 1374 } 1375 } 1376 if (c == '.') { 1377 hasSep = true; 1378 front = true; 1379 continue; 1380 } 1381 return "bad character '" + c + "'"; 1382 } 1383 if (requireFilename && !FileUtils.isValidExtFilename(name)) { 1384 return "Invalid filename"; 1385 } 1386 return hasSep || !requireSeparator 1387 ? null : "must have at least one '.' separator"; 1388 } 1389 1390 private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser, 1391 AttributeSet attrs) throws IOException, XmlPullParserException, 1392 PackageParserException { 1393 1394 int type; 1395 while ((type = parser.next()) != XmlPullParser.START_TAG 1396 && type != XmlPullParser.END_DOCUMENT) { 1397 } 1398 1399 if (type != XmlPullParser.START_TAG) { 1400 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 1401 "No start tag found"); 1402 } 1403 if (!parser.getName().equals(TAG_MANIFEST)) { 1404 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 1405 "No <manifest> tag"); 1406 } 1407 1408 final String packageName = attrs.getAttributeValue(null, "package"); 1409 if (!"android".equals(packageName)) { 1410 final String error = validateName(packageName, true, true); 1411 if (error != null) { 1412 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, 1413 "Invalid manifest package: " + error); 1414 } 1415 } 1416 1417 String splitName = attrs.getAttributeValue(null, "split"); 1418 if (splitName != null) { 1419 if (splitName.length() == 0) { 1420 splitName = null; 1421 } else { 1422 final String error = validateName(splitName, false, false); 1423 if (error != null) { 1424 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, 1425 "Invalid manifest split: " + error); 1426 } 1427 } 1428 } 1429 1430 return Pair.create(packageName.intern(), 1431 (splitName != null) ? splitName.intern() : splitName); 1432 } 1433 1434 private static ApkLite parseApkLite(String codePath, Resources res, XmlPullParser parser, 1435 AttributeSet attrs, int flags, Signature[] signatures, Certificate[][] certificates) 1436 throws IOException, XmlPullParserException, PackageParserException { 1437 final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs); 1438 1439 int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; 1440 int versionCode = 0; 1441 int revisionCode = 0; 1442 boolean coreApp = false; 1443 boolean multiArch = false; 1444 boolean use32bitAbi = false; 1445 boolean extractNativeLibs = true; 1446 1447 for (int i = 0; i < attrs.getAttributeCount(); i++) { 1448 final String attr = attrs.getAttributeName(i); 1449 if (attr.equals("installLocation")) { 1450 installLocation = attrs.getAttributeIntValue(i, 1451 PARSE_DEFAULT_INSTALL_LOCATION); 1452 } else if (attr.equals("versionCode")) { 1453 versionCode = attrs.getAttributeIntValue(i, 0); 1454 } else if (attr.equals("revisionCode")) { 1455 revisionCode = attrs.getAttributeIntValue(i, 0); 1456 } else if (attr.equals("coreApp")) { 1457 coreApp = attrs.getAttributeBooleanValue(i, false); 1458 } 1459 } 1460 1461 // Only search the tree when the tag is directly below <manifest> 1462 int type; 1463 final int searchDepth = parser.getDepth() + 1; 1464 1465 final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>(); 1466 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1467 && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) { 1468 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1469 continue; 1470 } 1471 1472 if (parser.getDepth() == searchDepth && "package-verifier".equals(parser.getName())) { 1473 final VerifierInfo verifier = parseVerifier(res, parser, attrs, flags); 1474 if (verifier != null) { 1475 verifiers.add(verifier); 1476 } 1477 } 1478 1479 if (parser.getDepth() == searchDepth && "application".equals(parser.getName())) { 1480 for (int i = 0; i < attrs.getAttributeCount(); ++i) { 1481 final String attr = attrs.getAttributeName(i); 1482 if ("multiArch".equals(attr)) { 1483 multiArch = attrs.getAttributeBooleanValue(i, false); 1484 } 1485 if ("use32bitAbi".equals(attr)) { 1486 use32bitAbi = attrs.getAttributeBooleanValue(i, false); 1487 } 1488 if ("extractNativeLibs".equals(attr)) { 1489 extractNativeLibs = attrs.getAttributeBooleanValue(i, true); 1490 } 1491 } 1492 } 1493 } 1494 1495 return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode, 1496 revisionCode, installLocation, verifiers, signatures, certificates, coreApp, 1497 multiArch, use32bitAbi, extractNativeLibs); 1498 } 1499 1500 /** 1501 * Temporary. 1502 */ 1503 static public Signature stringToSignature(String str) { 1504 final int N = str.length(); 1505 byte[] sig = new byte[N]; 1506 for (int i=0; i<N; i++) { 1507 sig[i] = (byte)str.charAt(i); 1508 } 1509 return new Signature(sig); 1510 } 1511 1512 /** 1513 * Parses a child package and adds it to the parent if successful. If you add 1514 * new tags that need to be supported by child packages make sure to add them 1515 * to {@link #CHILD_PACKAGE_TAGS}. 1516 * 1517 * @param parentPkg The parent that contains the child 1518 * @param res Resources against which to resolve values 1519 * @param parser Parser of the manifest 1520 * @param flags Flags about how to parse 1521 * @param outError Human readable error if parsing fails 1522 * @return True of parsing succeeded. 1523 * 1524 * @throws XmlPullParserException 1525 * @throws IOException 1526 */ 1527 private boolean parseBaseApkChild(Package parentPkg, Resources res, XmlResourceParser parser, 1528 int flags, String[] outError) throws XmlPullParserException, IOException { 1529 // Let ppl not abuse this mechanism by limiting the packages per APK 1530 if (parentPkg.childPackages != null && parentPkg.childPackages.size() + 2 1531 > MAX_PACKAGES_PER_APK) { 1532 outError[0] = "Maximum number of packages per APK is: " + MAX_PACKAGES_PER_APK; 1533 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1534 return false; 1535 } 1536 1537 // Make sure we have a valid child package name 1538 String childPackageName = parser.getAttributeValue(null, "package"); 1539 if (validateName(childPackageName, true, false) != null) { 1540 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 1541 return false; 1542 } 1543 1544 // Child packages must be unique 1545 if (childPackageName.equals(parentPkg.packageName)) { 1546 String message = "Child package name cannot be equal to parent package name: " 1547 + parentPkg.packageName; 1548 Slog.w(TAG, message); 1549 outError[0] = message; 1550 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1551 return false; 1552 } 1553 1554 // Child packages must be unique 1555 if (parentPkg.hasChildPackage(childPackageName)) { 1556 String message = "Duplicate child package:" + childPackageName; 1557 Slog.w(TAG, message); 1558 outError[0] = message; 1559 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1560 return false; 1561 } 1562 1563 // Go ahead and parse the child 1564 Package childPkg = new Package(childPackageName); 1565 1566 // Child package inherits parent version code/name/target SDK 1567 childPkg.mVersionCode = parentPkg.mVersionCode; 1568 childPkg.baseRevisionCode = parentPkg.baseRevisionCode; 1569 childPkg.mVersionName = parentPkg.mVersionName; 1570 childPkg.applicationInfo.targetSdkVersion = parentPkg.applicationInfo.targetSdkVersion; 1571 childPkg.applicationInfo.minSdkVersion = parentPkg.applicationInfo.minSdkVersion; 1572 1573 childPkg = parseBaseApkCommon(childPkg, CHILD_PACKAGE_TAGS, res, parser, flags, outError); 1574 if (childPkg == null) { 1575 // If we got null then error was set during child parsing 1576 return false; 1577 } 1578 1579 // Set the parent-child relation 1580 if (parentPkg.childPackages == null) { 1581 parentPkg.childPackages = new ArrayList<>(); 1582 } 1583 parentPkg.childPackages.add(childPkg); 1584 childPkg.parentPackage = parentPkg; 1585 1586 return true; 1587 } 1588 1589 /** 1590 * Parse the manifest of a <em>base APK</em>. When adding new features you 1591 * need to consider whether they should be supported by split APKs and child 1592 * packages. 1593 * 1594 * @param res The resources from which to resolve values 1595 * @param parser The manifest parser 1596 * @param flags Flags how to parse 1597 * @param outError Human readable error message 1598 * @return Parsed package or null on error. 1599 * 1600 * @throws XmlPullParserException 1601 * @throws IOException 1602 */ 1603 private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags, 1604 String[] outError) throws XmlPullParserException, IOException { 1605 final String splitName; 1606 final String pkgName; 1607 1608 try { 1609 Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser); 1610 pkgName = packageSplit.first; 1611 splitName = packageSplit.second; 1612 1613 if (!TextUtils.isEmpty(splitName)) { 1614 outError[0] = "Expected base APK, but found split " + splitName; 1615 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 1616 return null; 1617 } 1618 } catch (PackageParserException e) { 1619 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 1620 return null; 1621 } 1622 1623 final Package pkg = new Package(pkgName); 1624 1625 TypedArray sa = res.obtainAttributes(parser, 1626 com.android.internal.R.styleable.AndroidManifest); 1627 1628 pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger( 1629 com.android.internal.R.styleable.AndroidManifest_versionCode, 0); 1630 pkg.baseRevisionCode = sa.getInteger( 1631 com.android.internal.R.styleable.AndroidManifest_revisionCode, 0); 1632 pkg.mVersionName = sa.getNonConfigurationString( 1633 com.android.internal.R.styleable.AndroidManifest_versionName, 0); 1634 if (pkg.mVersionName != null) { 1635 pkg.mVersionName = pkg.mVersionName.intern(); 1636 } 1637 1638 pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false); 1639 1640 sa.recycle(); 1641 1642 return parseBaseApkCommon(pkg, null, res, parser, flags, outError); 1643 } 1644 1645 /** 1646 * This is the common parsing routing for handling parent and child 1647 * packages in a base APK. The difference between parent and child 1648 * parsing is that some tags are not supported by child packages as 1649 * well as some manifest attributes are ignored. The implementation 1650 * assumes the calling code has already handled the manifest tag if needed 1651 * (this applies to the parent only). 1652 * 1653 * @param pkg The package which to populate 1654 * @param acceptedTags Which tags to handle, null to handle all 1655 * @param res Resources against which to resolve values 1656 * @param parser Parser of the manifest 1657 * @param flags Flags about how to parse 1658 * @param outError Human readable error if parsing fails 1659 * @return The package if parsing succeeded or null. 1660 * 1661 * @throws XmlPullParserException 1662 * @throws IOException 1663 */ 1664 private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res, 1665 XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, 1666 IOException { 1667 mParseInstrumentationArgs = null; 1668 mParseActivityArgs = null; 1669 mParseServiceArgs = null; 1670 mParseProviderArgs = null; 1671 1672 int type; 1673 boolean foundApp = false; 1674 1675 TypedArray sa = res.obtainAttributes(parser, 1676 com.android.internal.R.styleable.AndroidManifest); 1677 1678 String str = sa.getNonConfigurationString( 1679 com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); 1680 if (str != null && str.length() > 0) { 1681 String nameError = validateName(str, true, false); 1682 if (nameError != null && !"android".equals(pkg.packageName)) { 1683 outError[0] = "<manifest> specifies bad sharedUserId name \"" 1684 + str + "\": " + nameError; 1685 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; 1686 return null; 1687 } 1688 pkg.mSharedUserId = str.intern(); 1689 pkg.mSharedUserLabel = sa.getResourceId( 1690 com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0); 1691 } 1692 1693 pkg.installLocation = sa.getInteger( 1694 com.android.internal.R.styleable.AndroidManifest_installLocation, 1695 PARSE_DEFAULT_INSTALL_LOCATION); 1696 pkg.applicationInfo.installLocation = pkg.installLocation; 1697 1698 1699 /* Set the global "forward lock" flag */ 1700 if ((flags & PARSE_FORWARD_LOCK) != 0) { 1701 pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK; 1702 } 1703 1704 /* Set the global "on SD card" flag */ 1705 if ((flags & PARSE_EXTERNAL_STORAGE) != 0) { 1706 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; 1707 } 1708 1709 if ((flags & PARSE_IS_EPHEMERAL) != 0) { 1710 pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_EPHEMERAL; 1711 } 1712 1713 // Resource boolean are -1, so 1 means we don't know the value. 1714 int supportsSmallScreens = 1; 1715 int supportsNormalScreens = 1; 1716 int supportsLargeScreens = 1; 1717 int supportsXLargeScreens = 1; 1718 int resizeable = 1; 1719 int anyDensity = 1; 1720 1721 int outerDepth = parser.getDepth(); 1722 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1723 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1724 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1725 continue; 1726 } 1727 1728 String tagName = parser.getName(); 1729 1730 if (acceptedTags != null && !acceptedTags.contains(tagName)) { 1731 Slog.w(TAG, "Skipping unsupported element under <manifest>: " 1732 + tagName + " at " + mArchiveSourcePath + " " 1733 + parser.getPositionDescription()); 1734 XmlUtils.skipCurrentTag(parser); 1735 continue; 1736 } 1737 1738 if (tagName.equals(TAG_APPLICATION)) { 1739 if (foundApp) { 1740 if (RIGID_PARSER) { 1741 outError[0] = "<manifest> has more than one <application>"; 1742 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1743 return null; 1744 } else { 1745 Slog.w(TAG, "<manifest> has more than one <application>"); 1746 XmlUtils.skipCurrentTag(parser); 1747 continue; 1748 } 1749 } 1750 1751 foundApp = true; 1752 if (!parseBaseApplication(pkg, res, parser, flags, outError)) { 1753 return null; 1754 } 1755 } else if (tagName.equals(TAG_OVERLAY)) { 1756 sa = res.obtainAttributes(parser, 1757 com.android.internal.R.styleable.AndroidManifestResourceOverlay); 1758 pkg.mOverlayTarget = sa.getString( 1759 com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage); 1760 pkg.mOverlayPriority = sa.getInt( 1761 com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority, 1762 -1); 1763 sa.recycle(); 1764 1765 if (pkg.mOverlayTarget == null) { 1766 outError[0] = "<overlay> does not specify a target package"; 1767 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1768 return null; 1769 } 1770 if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) { 1771 outError[0] = "<overlay> priority must be between 0 and 9999"; 1772 mParseError = 1773 PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1774 return null; 1775 } 1776 XmlUtils.skipCurrentTag(parser); 1777 1778 } else if (tagName.equals(TAG_KEY_SETS)) { 1779 if (!parseKeySets(pkg, res, parser, outError)) { 1780 return null; 1781 } 1782 } else if (tagName.equals(TAG_PERMISSION_GROUP)) { 1783 if (parsePermissionGroup(pkg, flags, res, parser, outError) == null) { 1784 return null; 1785 } 1786 } else if (tagName.equals(TAG_PERMISSION)) { 1787 if (parsePermission(pkg, res, parser, outError) == null) { 1788 return null; 1789 } 1790 } else if (tagName.equals(TAG_PERMISSION_TREE)) { 1791 if (parsePermissionTree(pkg, res, parser, outError) == null) { 1792 return null; 1793 } 1794 } else if (tagName.equals(TAG_USES_PERMISSION)) { 1795 if (!parseUsesPermission(pkg, res, parser)) { 1796 return null; 1797 } 1798 } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M) 1799 || tagName.equals(TAG_USES_PERMISSION_SDK_23)) { 1800 if (!parseUsesPermission(pkg, res, parser)) { 1801 return null; 1802 } 1803 } else if (tagName.equals(TAG_USES_CONFIGURATION)) { 1804 ConfigurationInfo cPref = new ConfigurationInfo(); 1805 sa = res.obtainAttributes(parser, 1806 com.android.internal.R.styleable.AndroidManifestUsesConfiguration); 1807 cPref.reqTouchScreen = sa.getInt( 1808 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, 1809 Configuration.TOUCHSCREEN_UNDEFINED); 1810 cPref.reqKeyboardType = sa.getInt( 1811 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, 1812 Configuration.KEYBOARD_UNDEFINED); 1813 if (sa.getBoolean( 1814 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, 1815 false)) { 1816 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; 1817 } 1818 cPref.reqNavigation = sa.getInt( 1819 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation, 1820 Configuration.NAVIGATION_UNDEFINED); 1821 if (sa.getBoolean( 1822 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, 1823 false)) { 1824 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; 1825 } 1826 sa.recycle(); 1827 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref); 1828 1829 XmlUtils.skipCurrentTag(parser); 1830 1831 } else if (tagName.equals(TAG_USES_FEATURE)) { 1832 FeatureInfo fi = parseUsesFeature(res, parser); 1833 pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi); 1834 1835 if (fi.name == null) { 1836 ConfigurationInfo cPref = new ConfigurationInfo(); 1837 cPref.reqGlEsVersion = fi.reqGlEsVersion; 1838 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref); 1839 } 1840 1841 XmlUtils.skipCurrentTag(parser); 1842 1843 } else if (tagName.equals(TAG_FEATURE_GROUP)) { 1844 FeatureGroupInfo group = new FeatureGroupInfo(); 1845 ArrayList<FeatureInfo> features = null; 1846 final int innerDepth = parser.getDepth(); 1847 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1848 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 1849 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1850 continue; 1851 } 1852 1853 final String innerTagName = parser.getName(); 1854 if (innerTagName.equals("uses-feature")) { 1855 FeatureInfo featureInfo = parseUsesFeature(res, parser); 1856 // FeatureGroups are stricter and mandate that 1857 // any <uses-feature> declared are mandatory. 1858 featureInfo.flags |= FeatureInfo.FLAG_REQUIRED; 1859 features = ArrayUtils.add(features, featureInfo); 1860 } else { 1861 Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName + 1862 " at " + mArchiveSourcePath + " " + 1863 parser.getPositionDescription()); 1864 } 1865 XmlUtils.skipCurrentTag(parser); 1866 } 1867 1868 if (features != null) { 1869 group.features = new FeatureInfo[features.size()]; 1870 group.features = features.toArray(group.features); 1871 } 1872 pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group); 1873 1874 } else if (tagName.equals(TAG_USES_SDK)) { 1875 if (SDK_VERSION > 0) { 1876 sa = res.obtainAttributes(parser, 1877 com.android.internal.R.styleable.AndroidManifestUsesSdk); 1878 1879 int minVers = 1; 1880 String minCode = null; 1881 int targetVers = 0; 1882 String targetCode = null; 1883 1884 TypedValue val = sa.peekValue( 1885 com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); 1886 if (val != null) { 1887 if (val.type == TypedValue.TYPE_STRING && val.string != null) { 1888 targetCode = minCode = val.string.toString(); 1889 } else { 1890 // If it's not a string, it's an integer. 1891 targetVers = minVers = val.data; 1892 } 1893 } 1894 1895 val = sa.peekValue( 1896 com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); 1897 if (val != null) { 1898 if (val.type == TypedValue.TYPE_STRING && val.string != null) { 1899 targetCode = val.string.toString(); 1900 if (minCode == null) { 1901 minCode = targetCode; 1902 } 1903 } else { 1904 // If it's not a string, it's an integer. 1905 targetVers = val.data; 1906 } 1907 } 1908 1909 sa.recycle(); 1910 1911 if (minCode != null) { 1912 boolean allowedCodename = false; 1913 for (String codename : SDK_CODENAMES) { 1914 if (minCode.equals(codename)) { 1915 allowedCodename = true; 1916 break; 1917 } 1918 } 1919 if (!allowedCodename) { 1920 if (SDK_CODENAMES.length > 0) { 1921 outError[0] = "Requires development platform " + minCode 1922 + " (current platform is any of " 1923 + Arrays.toString(SDK_CODENAMES) + ")"; 1924 } else { 1925 outError[0] = "Requires development platform " + minCode 1926 + " but this is a release platform."; 1927 } 1928 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1929 return null; 1930 } 1931 pkg.applicationInfo.minSdkVersion = 1932 android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; 1933 } else if (minVers > SDK_VERSION) { 1934 outError[0] = "Requires newer sdk version #" + minVers 1935 + " (current version is #" + SDK_VERSION + ")"; 1936 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1937 return null; 1938 } else { 1939 pkg.applicationInfo.minSdkVersion = minVers; 1940 } 1941 1942 if (targetCode != null) { 1943 boolean allowedCodename = false; 1944 for (String codename : SDK_CODENAMES) { 1945 if (targetCode.equals(codename)) { 1946 allowedCodename = true; 1947 break; 1948 } 1949 } 1950 if (!allowedCodename) { 1951 if (SDK_CODENAMES.length > 0) { 1952 outError[0] = "Requires development platform " + targetCode 1953 + " (current platform is any of " 1954 + Arrays.toString(SDK_CODENAMES) + ")"; 1955 } else { 1956 outError[0] = "Requires development platform " + targetCode 1957 + " but this is a release platform."; 1958 } 1959 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1960 return null; 1961 } 1962 // If the code matches, it definitely targets this SDK. 1963 pkg.applicationInfo.targetSdkVersion 1964 = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; 1965 } else { 1966 pkg.applicationInfo.targetSdkVersion = targetVers; 1967 } 1968 } 1969 1970 XmlUtils.skipCurrentTag(parser); 1971 1972 } else if (tagName.equals(TAG_SUPPORT_SCREENS)) { 1973 sa = res.obtainAttributes(parser, 1974 com.android.internal.R.styleable.AndroidManifestSupportsScreens); 1975 1976 pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger( 1977 com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, 1978 0); 1979 pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger( 1980 com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, 1981 0); 1982 pkg.applicationInfo.largestWidthLimitDp = sa.getInteger( 1983 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, 1984 0); 1985 1986 // This is a trick to get a boolean and still able to detect 1987 // if a value was actually set. 1988 supportsSmallScreens = sa.getInteger( 1989 com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens, 1990 supportsSmallScreens); 1991 supportsNormalScreens = sa.getInteger( 1992 com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens, 1993 supportsNormalScreens); 1994 supportsLargeScreens = sa.getInteger( 1995 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens, 1996 supportsLargeScreens); 1997 supportsXLargeScreens = sa.getInteger( 1998 com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1999 supportsXLargeScreens); 2000 resizeable = sa.getInteger( 2001 com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable, 2002 resizeable); 2003 anyDensity = sa.getInteger( 2004 com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity, 2005 anyDensity); 2006 2007 sa.recycle(); 2008 2009 XmlUtils.skipCurrentTag(parser); 2010 2011 } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) { 2012 sa = res.obtainAttributes(parser, 2013 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast); 2014 2015 // Note: don't allow this value to be a reference to a resource 2016 // that may change. 2017 String name = sa.getNonResourceString( 2018 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name); 2019 2020 sa.recycle(); 2021 2022 if (name != null && (flags&PARSE_IS_SYSTEM) != 0) { 2023 if (pkg.protectedBroadcasts == null) { 2024 pkg.protectedBroadcasts = new ArrayList<String>(); 2025 } 2026 if (!pkg.protectedBroadcasts.contains(name)) { 2027 pkg.protectedBroadcasts.add(name.intern()); 2028 } 2029 } 2030 2031 XmlUtils.skipCurrentTag(parser); 2032 2033 } else if (tagName.equals(TAG_INSTRUMENTATION)) { 2034 if (parseInstrumentation(pkg, res, parser, outError) == null) { 2035 return null; 2036 } 2037 } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) { 2038 sa = res.obtainAttributes(parser, 2039 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 2040 2041 String orig =sa.getNonConfigurationString( 2042 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 2043 if (!pkg.packageName.equals(orig)) { 2044 if (pkg.mOriginalPackages == null) { 2045 pkg.mOriginalPackages = new ArrayList<String>(); 2046 pkg.mRealPackage = pkg.packageName; 2047 } 2048 pkg.mOriginalPackages.add(orig); 2049 } 2050 2051 sa.recycle(); 2052 2053 XmlUtils.skipCurrentTag(parser); 2054 2055 } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) { 2056 sa = res.obtainAttributes(parser, 2057 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 2058 2059 String name = sa.getNonConfigurationString( 2060 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 2061 2062 sa.recycle(); 2063 2064 if (name != null) { 2065 if (pkg.mAdoptPermissions == null) { 2066 pkg.mAdoptPermissions = new ArrayList<String>(); 2067 } 2068 pkg.mAdoptPermissions.add(name); 2069 } 2070 2071 XmlUtils.skipCurrentTag(parser); 2072 2073 } else if (tagName.equals(TAG_USES_GL_TEXTURE)) { 2074 // Just skip this tag 2075 XmlUtils.skipCurrentTag(parser); 2076 continue; 2077 2078 } else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) { 2079 // Just skip this tag 2080 XmlUtils.skipCurrentTag(parser); 2081 continue; 2082 } else if (tagName.equals(TAG_SUPPORTS_INPUT)) {// 2083 XmlUtils.skipCurrentTag(parser); 2084 continue; 2085 2086 } else if (tagName.equals(TAG_EAT_COMMENT)) { 2087 // Just skip this tag 2088 XmlUtils.skipCurrentTag(parser); 2089 continue; 2090 2091 } else if (tagName.equals(TAG_PACKAGE)) { 2092 if (!MULTI_PACKAGE_APK_ENABLED) { 2093 XmlUtils.skipCurrentTag(parser); 2094 continue; 2095 } 2096 if (!parseBaseApkChild(pkg, res, parser, flags, outError)) { 2097 // If parsing a child failed the error is already set 2098 return null; 2099 } 2100 2101 } else if (tagName.equals(TAG_RESTRICT_UPDATE)) { 2102 if ((flags & PARSE_IS_SYSTEM_DIR) != 0) { 2103 sa = res.obtainAttributes(parser, 2104 com.android.internal.R.styleable.AndroidManifestRestrictUpdate); 2105 final String hash = sa.getNonConfigurationString( 2106 com.android.internal.R.styleable.AndroidManifestRestrictUpdate_hash, 0); 2107 sa.recycle(); 2108 2109 pkg.restrictUpdateHash = null; 2110 if (hash != null) { 2111 final int hashLength = hash.length(); 2112 final byte[] hashBytes = new byte[hashLength / 2]; 2113 for (int i = 0; i < hashLength; i += 2){ 2114 hashBytes[i/2] = (byte) ((Character.digit(hash.charAt(i), 16) << 4) 2115 + Character.digit(hash.charAt(i + 1), 16)); 2116 } 2117 pkg.restrictUpdateHash = hashBytes; 2118 } 2119 } 2120 2121 XmlUtils.skipCurrentTag(parser); 2122 2123 } else if (RIGID_PARSER) { 2124 outError[0] = "Bad element under <manifest>: " 2125 + parser.getName(); 2126 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2127 return null; 2128 2129 } else { 2130 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() 2131 + " at " + mArchiveSourcePath + " " 2132 + parser.getPositionDescription()); 2133 XmlUtils.skipCurrentTag(parser); 2134 continue; 2135 } 2136 } 2137 2138 if (!foundApp && pkg.instrumentation.size() == 0) { 2139 outError[0] = "<manifest> does not contain an <application> or <instrumentation>"; 2140 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; 2141 } 2142 2143 final int NP = PackageParser.NEW_PERMISSIONS.length; 2144 StringBuilder implicitPerms = null; 2145 for (int ip=0; ip<NP; ip++) { 2146 final PackageParser.NewPermissionInfo npi 2147 = PackageParser.NEW_PERMISSIONS[ip]; 2148 if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) { 2149 break; 2150 } 2151 if (!pkg.requestedPermissions.contains(npi.name)) { 2152 if (implicitPerms == null) { 2153 implicitPerms = new StringBuilder(128); 2154 implicitPerms.append(pkg.packageName); 2155 implicitPerms.append(": compat added "); 2156 } else { 2157 implicitPerms.append(' '); 2158 } 2159 implicitPerms.append(npi.name); 2160 pkg.requestedPermissions.add(npi.name); 2161 } 2162 } 2163 if (implicitPerms != null) { 2164 Slog.i(TAG, implicitPerms.toString()); 2165 } 2166 2167 final int NS = PackageParser.SPLIT_PERMISSIONS.length; 2168 for (int is=0; is<NS; is++) { 2169 final PackageParser.SplitPermissionInfo spi 2170 = PackageParser.SPLIT_PERMISSIONS[is]; 2171 if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk 2172 || !pkg.requestedPermissions.contains(spi.rootPerm)) { 2173 continue; 2174 } 2175 for (int in=0; in<spi.newPerms.length; in++) { 2176 final String perm = spi.newPerms[in]; 2177 if (!pkg.requestedPermissions.contains(perm)) { 2178 pkg.requestedPermissions.add(perm); 2179 } 2180 } 2181 } 2182 2183 if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 2184 && pkg.applicationInfo.targetSdkVersion 2185 >= android.os.Build.VERSION_CODES.DONUT)) { 2186 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; 2187 } 2188 if (supportsNormalScreens != 0) { 2189 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; 2190 } 2191 if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 2192 && pkg.applicationInfo.targetSdkVersion 2193 >= android.os.Build.VERSION_CODES.DONUT)) { 2194 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; 2195 } 2196 if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 2197 && pkg.applicationInfo.targetSdkVersion 2198 >= android.os.Build.VERSION_CODES.GINGERBREAD)) { 2199 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; 2200 } 2201 if (resizeable < 0 || (resizeable > 0 2202 && pkg.applicationInfo.targetSdkVersion 2203 >= android.os.Build.VERSION_CODES.DONUT)) { 2204 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; 2205 } 2206 if (anyDensity < 0 || (anyDensity > 0 2207 && pkg.applicationInfo.targetSdkVersion 2208 >= android.os.Build.VERSION_CODES.DONUT)) { 2209 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; 2210 } 2211 2212 return pkg; 2213 } 2214 2215 private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs) { 2216 FeatureInfo fi = new FeatureInfo(); 2217 TypedArray sa = res.obtainAttributes(attrs, 2218 com.android.internal.R.styleable.AndroidManifestUsesFeature); 2219 // Note: don't allow this value to be a reference to a resource 2220 // that may change. 2221 fi.name = sa.getNonResourceString( 2222 com.android.internal.R.styleable.AndroidManifestUsesFeature_name); 2223 fi.version = sa.getInt( 2224 com.android.internal.R.styleable.AndroidManifestUsesFeature_version, 0); 2225 if (fi.name == null) { 2226 fi.reqGlEsVersion = sa.getInt( 2227 com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion, 2228 FeatureInfo.GL_ES_VERSION_UNDEFINED); 2229 } 2230 if (sa.getBoolean( 2231 com.android.internal.R.styleable.AndroidManifestUsesFeature_required, true)) { 2232 fi.flags |= FeatureInfo.FLAG_REQUIRED; 2233 } 2234 sa.recycle(); 2235 return fi; 2236 } 2237 2238 private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser) 2239 throws XmlPullParserException, IOException { 2240 TypedArray sa = res.obtainAttributes(parser, 2241 com.android.internal.R.styleable.AndroidManifestUsesPermission); 2242 2243 // Note: don't allow this value to be a reference to a resource 2244 // that may change. 2245 String name = sa.getNonResourceString( 2246 com.android.internal.R.styleable.AndroidManifestUsesPermission_name); 2247 2248 int maxSdkVersion = 0; 2249 TypedValue val = sa.peekValue( 2250 com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion); 2251 if (val != null) { 2252 if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) { 2253 maxSdkVersion = val.data; 2254 } 2255 } 2256 2257 sa.recycle(); 2258 2259 if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) { 2260 if (name != null) { 2261 int index = pkg.requestedPermissions.indexOf(name); 2262 if (index == -1) { 2263 pkg.requestedPermissions.add(name.intern()); 2264 } else { 2265 Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: " 2266 + name + " in package: " + pkg.packageName + " at: " 2267 + parser.getPositionDescription()); 2268 } 2269 } 2270 } 2271 2272 XmlUtils.skipCurrentTag(parser); 2273 return true; 2274 } 2275 2276 private static String buildClassName(String pkg, CharSequence clsSeq, 2277 String[] outError) { 2278 if (clsSeq == null || clsSeq.length() <= 0) { 2279 outError[0] = "Empty class name in package " + pkg; 2280 return null; 2281 } 2282 String cls = clsSeq.toString(); 2283 char c = cls.charAt(0); 2284 if (c == '.') { 2285 return (pkg + cls).intern(); 2286 } 2287 if (cls.indexOf('.') < 0) { 2288 StringBuilder b = new StringBuilder(pkg); 2289 b.append('.'); 2290 b.append(cls); 2291 return b.toString().intern(); 2292 } 2293 return cls.intern(); 2294 } 2295 2296 private static String buildCompoundName(String pkg, 2297 CharSequence procSeq, String type, String[] outError) { 2298 String proc = procSeq.toString(); 2299 char c = proc.charAt(0); 2300 if (pkg != null && c == ':') { 2301 if (proc.length() < 2) { 2302 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg 2303 + ": must be at least two characters"; 2304 return null; 2305 } 2306 String subName = proc.substring(1); 2307 String nameError = validateName(subName, false, false); 2308 if (nameError != null) { 2309 outError[0] = "Invalid " + type + " name " + proc + " in package " 2310 + pkg + ": " + nameError; 2311 return null; 2312 } 2313 return (pkg + proc).intern(); 2314 } 2315 String nameError = validateName(proc, true, false); 2316 if (nameError != null && !"system".equals(proc)) { 2317 outError[0] = "Invalid " + type + " name " + proc + " in package " 2318 + pkg + ": " + nameError; 2319 return null; 2320 } 2321 return proc.intern(); 2322 } 2323 2324 private static String buildProcessName(String pkg, String defProc, 2325 CharSequence procSeq, int flags, String[] separateProcesses, 2326 String[] outError) { 2327 if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) { 2328 return defProc != null ? defProc : pkg; 2329 } 2330 if (separateProcesses != null) { 2331 for (int i=separateProcesses.length-1; i>=0; i--) { 2332 String sp = separateProcesses[i]; 2333 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) { 2334 return pkg; 2335 } 2336 } 2337 } 2338 if (procSeq == null || procSeq.length() <= 0) { 2339 return defProc; 2340 } 2341 return buildCompoundName(pkg, procSeq, "process", outError); 2342 } 2343 2344 private static String buildTaskAffinityName(String pkg, String defProc, 2345 CharSequence procSeq, String[] outError) { 2346 if (procSeq == null) { 2347 return defProc; 2348 } 2349 if (procSeq.length() <= 0) { 2350 return null; 2351 } 2352 return buildCompoundName(pkg, procSeq, "taskAffinity", outError); 2353 } 2354 2355 private boolean parseKeySets(Package owner, Resources res, 2356 XmlResourceParser parser, String[] outError) 2357 throws XmlPullParserException, IOException { 2358 // we've encountered the 'key-sets' tag 2359 // all the keys and keysets that we want must be defined here 2360 // so we're going to iterate over the parser and pull out the things we want 2361 int outerDepth = parser.getDepth(); 2362 int currentKeySetDepth = -1; 2363 int type; 2364 String currentKeySet = null; 2365 ArrayMap<String, PublicKey> publicKeys = new ArrayMap<String, PublicKey>(); 2366 ArraySet<String> upgradeKeySets = new ArraySet<String>(); 2367 ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<String, ArraySet<String>>(); 2368 ArraySet<String> improperKeySets = new ArraySet<String>(); 2369 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 2370 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 2371 if (type == XmlPullParser.END_TAG) { 2372 if (parser.getDepth() == currentKeySetDepth) { 2373 currentKeySet = null; 2374 currentKeySetDepth = -1; 2375 } 2376 continue; 2377 } 2378 String tagName = parser.getName(); 2379 if (tagName.equals("key-set")) { 2380 if (currentKeySet != null) { 2381 outError[0] = "Improperly nested 'key-set' tag at " 2382 + parser.getPositionDescription(); 2383 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2384 return false; 2385 } 2386 final TypedArray sa = res.obtainAttributes(parser, 2387 com.android.internal.R.styleable.AndroidManifestKeySet); 2388 final String keysetName = sa.getNonResourceString( 2389 com.android.internal.R.styleable.AndroidManifestKeySet_name); 2390 definedKeySets.put(keysetName, new ArraySet<String>()); 2391 currentKeySet = keysetName; 2392 currentKeySetDepth = parser.getDepth(); 2393 sa.recycle(); 2394 } else if (tagName.equals("public-key")) { 2395 if (currentKeySet == null) { 2396 outError[0] = "Improperly nested 'key-set' tag at " 2397 + parser.getPositionDescription(); 2398 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2399 return false; 2400 } 2401 final TypedArray sa = res.obtainAttributes(parser, 2402 com.android.internal.R.styleable.AndroidManifestPublicKey); 2403 final String publicKeyName = sa.getNonResourceString( 2404 com.android.internal.R.styleable.AndroidManifestPublicKey_name); 2405 final String encodedKey = sa.getNonResourceString( 2406 com.android.internal.R.styleable.AndroidManifestPublicKey_value); 2407 if (encodedKey == null && publicKeys.get(publicKeyName) == null) { 2408 outError[0] = "'public-key' " + publicKeyName + " must define a public-key value" 2409 + " on first use at " + parser.getPositionDescription(); 2410 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2411 sa.recycle(); 2412 return false; 2413 } else if (encodedKey != null) { 2414 PublicKey currentKey = parsePublicKey(encodedKey); 2415 if (currentKey == null) { 2416 Slog.w(TAG, "No recognized valid key in 'public-key' tag at " 2417 + parser.getPositionDescription() + " key-set " + currentKeySet 2418 + " will not be added to the package's defined key-sets."); 2419 sa.recycle(); 2420 improperKeySets.add(currentKeySet); 2421 XmlUtils.skipCurrentTag(parser); 2422 continue; 2423 } 2424 if (publicKeys.get(publicKeyName) == null 2425 || publicKeys.get(publicKeyName).equals(currentKey)) { 2426 2427 /* public-key first definition, or matches old definition */ 2428 publicKeys.put(publicKeyName, currentKey); 2429 } else { 2430 outError[0] = "Value of 'public-key' " + publicKeyName 2431 + " conflicts with previously defined value at " 2432 + parser.getPositionDescription(); 2433 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2434 sa.recycle(); 2435 return false; 2436 } 2437 } 2438 definedKeySets.get(currentKeySet).add(publicKeyName); 2439 sa.recycle(); 2440 XmlUtils.skipCurrentTag(parser); 2441 } else if (tagName.equals("upgrade-key-set")) { 2442 final TypedArray sa = res.obtainAttributes(parser, 2443 com.android.internal.R.styleable.AndroidManifestUpgradeKeySet); 2444 String name = sa.getNonResourceString( 2445 com.android.internal.R.styleable.AndroidManifestUpgradeKeySet_name); 2446 upgradeKeySets.add(name); 2447 sa.recycle(); 2448 XmlUtils.skipCurrentTag(parser); 2449 } else if (RIGID_PARSER) { 2450 outError[0] = "Bad element under <key-sets>: " + parser.getName() 2451 + " at " + mArchiveSourcePath + " " 2452 + parser.getPositionDescription(); 2453 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2454 return false; 2455 } else { 2456 Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName() 2457 + " at " + mArchiveSourcePath + " " 2458 + parser.getPositionDescription()); 2459 XmlUtils.skipCurrentTag(parser); 2460 continue; 2461 } 2462 } 2463 Set<String> publicKeyNames = publicKeys.keySet(); 2464 if (publicKeyNames.removeAll(definedKeySets.keySet())) { 2465 outError[0] = "Package" + owner.packageName + " AndroidManifext.xml " 2466 + "'key-set' and 'public-key' names must be distinct."; 2467 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2468 return false; 2469 } 2470 owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>(); 2471 for (ArrayMap.Entry<String, ArraySet<String>> e: definedKeySets.entrySet()) { 2472 final String keySetName = e.getKey(); 2473 if (e.getValue().size() == 0) { 2474 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml " 2475 + "'key-set' " + keySetName + " has no valid associated 'public-key'." 2476 + " Not including in package's defined key-sets."); 2477 continue; 2478 } else if (improperKeySets.contains(keySetName)) { 2479 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml " 2480 + "'key-set' " + keySetName + " contained improper 'public-key'" 2481 + " tags. Not including in package's defined key-sets."); 2482 continue; 2483 } 2484 owner.mKeySetMapping.put(keySetName, new ArraySet<PublicKey>()); 2485 for (String s : e.getValue()) { 2486 owner.mKeySetMapping.get(keySetName).add(publicKeys.get(s)); 2487 } 2488 } 2489 if (owner.mKeySetMapping.keySet().containsAll(upgradeKeySets)) { 2490 owner.mUpgradeKeySets = upgradeKeySets; 2491 } else { 2492 outError[0] ="Package" + owner.packageName + " AndroidManifext.xml " 2493 + "does not define all 'upgrade-key-set's ."; 2494 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2495 return false; 2496 } 2497 return true; 2498 } 2499 2500 private PermissionGroup parsePermissionGroup(Package owner, int flags, Resources res, 2501 XmlResourceParser parser, String[] outError) 2502 throws XmlPullParserException, IOException { 2503 PermissionGroup perm = new PermissionGroup(owner); 2504 2505 TypedArray sa = res.obtainAttributes(parser, 2506 com.android.internal.R.styleable.AndroidManifestPermissionGroup); 2507 if (!parsePackageItemInfo(owner, perm.info, outError, 2508 "<permission-group>", sa, true /*nameRequired*/, 2509 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name, 2510 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label, 2511 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon, 2512 com.android.internal.R.styleable.AndroidManifestPermissionGroup_roundIcon, 2513 com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo, 2514 com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) { 2515 sa.recycle(); 2516 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2517 return null; 2518 } 2519 2520 perm.info.descriptionRes = sa.getResourceId( 2521 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description, 2522 0); 2523 perm.info.flags = sa.getInt( 2524 com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0); 2525 perm.info.priority = sa.getInt( 2526 com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0); 2527 if (perm.info.priority > 0 && (flags&PARSE_IS_SYSTEM) == 0) { 2528 perm.info.priority = 0; 2529 } 2530 2531 sa.recycle(); 2532 2533 if (!parseAllMetaData(res, parser, "<permission-group>", perm, 2534 outError)) { 2535 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2536 return null; 2537 } 2538 2539 owner.permissionGroups.add(perm); 2540 2541 return perm; 2542 } 2543 2544 private Permission parsePermission(Package owner, Resources res, 2545 XmlResourceParser parser, String[] outError) 2546 throws XmlPullParserException, IOException { 2547 Permission perm = new Permission(owner); 2548 2549 TypedArray sa = res.obtainAttributes(parser, 2550 com.android.internal.R.styleable.AndroidManifestPermission); 2551 2552 if (!parsePackageItemInfo(owner, perm.info, outError, 2553 "<permission>", sa, true /*nameRequired*/, 2554 com.android.internal.R.styleable.AndroidManifestPermission_name, 2555 com.android.internal.R.styleable.AndroidManifestPermission_label, 2556 com.android.internal.R.styleable.AndroidManifestPermission_icon, 2557 com.android.internal.R.styleable.AndroidManifestPermission_roundIcon, 2558 com.android.internal.R.styleable.AndroidManifestPermission_logo, 2559 com.android.internal.R.styleable.AndroidManifestPermission_banner)) { 2560 sa.recycle(); 2561 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2562 return null; 2563 } 2564 2565 // Note: don't allow this value to be a reference to a resource 2566 // that may change. 2567 perm.info.group = sa.getNonResourceString( 2568 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup); 2569 if (perm.info.group != null) { 2570 perm.info.group = perm.info.group.intern(); 2571 } 2572 2573 perm.info.descriptionRes = sa.getResourceId( 2574 com.android.internal.R.styleable.AndroidManifestPermission_description, 2575 0); 2576 2577 perm.info.protectionLevel = sa.getInt( 2578 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel, 2579 PermissionInfo.PROTECTION_NORMAL); 2580 2581 perm.info.flags = sa.getInt( 2582 com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0); 2583 2584 sa.recycle(); 2585 2586 if (perm.info.protectionLevel == -1) { 2587 outError[0] = "<permission> does not specify protectionLevel"; 2588 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2589 return null; 2590 } 2591 2592 perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel); 2593 2594 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) { 2595 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) != 2596 PermissionInfo.PROTECTION_SIGNATURE) { 2597 outError[0] = "<permission> protectionLevel specifies a flag but is " 2598 + "not based on signature type"; 2599 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2600 return null; 2601 } 2602 } 2603 2604 if (!parseAllMetaData(res, parser, "<permission>", perm, outError)) { 2605 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2606 return null; 2607 } 2608 2609 owner.permissions.add(perm); 2610 2611 return perm; 2612 } 2613 2614 private Permission parsePermissionTree(Package owner, Resources res, 2615 XmlResourceParser parser, String[] outError) 2616 throws XmlPullParserException, IOException { 2617 Permission perm = new Permission(owner); 2618 2619 TypedArray sa = res.obtainAttributes(parser, 2620 com.android.internal.R.styleable.AndroidManifestPermissionTree); 2621 2622 if (!parsePackageItemInfo(owner, perm.info, outError, 2623 "<permission-tree>", sa, true /*nameRequired*/, 2624 com.android.internal.R.styleable.AndroidManifestPermissionTree_name, 2625 com.android.internal.R.styleable.AndroidManifestPermissionTree_label, 2626 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon, 2627 com.android.internal.R.styleable.AndroidManifestPermissionTree_roundIcon, 2628 com.android.internal.R.styleable.AndroidManifestPermissionTree_logo, 2629 com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) { 2630 sa.recycle(); 2631 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2632 return null; 2633 } 2634 2635 sa.recycle(); 2636 2637 int index = perm.info.name.indexOf('.'); 2638 if (index > 0) { 2639 index = perm.info.name.indexOf('.', index+1); 2640 } 2641 if (index < 0) { 2642 outError[0] = "<permission-tree> name has less than three segments: " 2643 + perm.info.name; 2644 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2645 return null; 2646 } 2647 2648 perm.info.descriptionRes = 0; 2649 perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL; 2650 perm.tree = true; 2651 2652 if (!parseAllMetaData(res, parser, "<permission-tree>", perm, 2653 outError)) { 2654 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2655 return null; 2656 } 2657 2658 owner.permissions.add(perm); 2659 2660 return perm; 2661 } 2662 2663 private Instrumentation parseInstrumentation(Package owner, Resources res, 2664 XmlResourceParser parser, String[] outError) 2665 throws XmlPullParserException, IOException { 2666 TypedArray sa = res.obtainAttributes(parser, 2667 com.android.internal.R.styleable.AndroidManifestInstrumentation); 2668 2669 if (mParseInstrumentationArgs == null) { 2670 mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError, 2671 com.android.internal.R.styleable.AndroidManifestInstrumentation_name, 2672 com.android.internal.R.styleable.AndroidManifestInstrumentation_label, 2673 com.android.internal.R.styleable.AndroidManifestInstrumentation_icon, 2674 com.android.internal.R.styleable.AndroidManifestInstrumentation_roundIcon, 2675 com.android.internal.R.styleable.AndroidManifestInstrumentation_logo, 2676 com.android.internal.R.styleable.AndroidManifestInstrumentation_banner); 2677 mParseInstrumentationArgs.tag = "<instrumentation>"; 2678 } 2679 2680 mParseInstrumentationArgs.sa = sa; 2681 2682 Instrumentation a = new Instrumentation(mParseInstrumentationArgs, 2683 new InstrumentationInfo()); 2684 if (outError[0] != null) { 2685 sa.recycle(); 2686 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2687 return null; 2688 } 2689 2690 String str; 2691 // Note: don't allow this value to be a reference to a resource 2692 // that may change. 2693 str = sa.getNonResourceString( 2694 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage); 2695 a.info.targetPackage = str != null ? str.intern() : null; 2696 2697 a.info.handleProfiling = sa.getBoolean( 2698 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling, 2699 false); 2700 2701 a.info.functionalTest = sa.getBoolean( 2702 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest, 2703 false); 2704 2705 sa.recycle(); 2706 2707 if (a.info.targetPackage == null) { 2708 outError[0] = "<instrumentation> does not specify targetPackage"; 2709 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2710 return null; 2711 } 2712 2713 if (!parseAllMetaData(res, parser, "<instrumentation>", a, 2714 outError)) { 2715 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2716 return null; 2717 } 2718 2719 owner.instrumentation.add(a); 2720 2721 return a; 2722 } 2723 2724 /** 2725 * Parse the {@code application} XML tree at the current parse location in a 2726 * <em>base APK</em> manifest. 2727 * <p> 2728 * When adding new features, carefully consider if they should also be 2729 * supported by split APKs. 2730 */ 2731 private boolean parseBaseApplication(Package owner, Resources res, 2732 XmlResourceParser parser, int flags, String[] outError) 2733 throws XmlPullParserException, IOException { 2734 final ApplicationInfo ai = owner.applicationInfo; 2735 final String pkgName = owner.applicationInfo.packageName; 2736 2737 TypedArray sa = res.obtainAttributes(parser, 2738 com.android.internal.R.styleable.AndroidManifestApplication); 2739 2740 if (!parsePackageItemInfo(owner, ai, outError, 2741 "<application>", sa, false /*nameRequired*/, 2742 com.android.internal.R.styleable.AndroidManifestApplication_name, 2743 com.android.internal.R.styleable.AndroidManifestApplication_label, 2744 com.android.internal.R.styleable.AndroidManifestApplication_icon, 2745 com.android.internal.R.styleable.AndroidManifestApplication_roundIcon, 2746 com.android.internal.R.styleable.AndroidManifestApplication_logo, 2747 com.android.internal.R.styleable.AndroidManifestApplication_banner)) { 2748 sa.recycle(); 2749 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2750 return false; 2751 } 2752 2753 if (ai.name != null) { 2754 ai.className = ai.name; 2755 } 2756 2757 String manageSpaceActivity = sa.getNonConfigurationString( 2758 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity, 2759 Configuration.NATIVE_CONFIG_VERSION); 2760 if (manageSpaceActivity != null) { 2761 ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity, 2762 outError); 2763 } 2764 2765 boolean allowBackup = sa.getBoolean( 2766 com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true); 2767 if (allowBackup) { 2768 ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; 2769 2770 // backupAgent, killAfterRestore, fullBackupContent, backupInForeground, 2771 // and restoreAnyVersion are only relevant if backup is possible for the 2772 // given application. 2773 String backupAgent = sa.getNonConfigurationString( 2774 com.android.internal.R.styleable.AndroidManifestApplication_backupAgent, 2775 Configuration.NATIVE_CONFIG_VERSION); 2776 if (backupAgent != null) { 2777 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError); 2778 if (DEBUG_BACKUP) { 2779 Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName 2780 + " from " + pkgName + "+" + backupAgent); 2781 } 2782 2783 if (sa.getBoolean( 2784 com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore, 2785 true)) { 2786 ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE; 2787 } 2788 if (sa.getBoolean( 2789 com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion, 2790 false)) { 2791 ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION; 2792 } 2793 if (sa.getBoolean( 2794 com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly, 2795 false)) { 2796 ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY; 2797 } 2798 if (sa.getBoolean( 2799 com.android.internal.R.styleable.AndroidManifestApplication_backupInForeground, 2800 false)) { 2801 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; 2802 } 2803 } 2804 2805 TypedValue v = sa.peekValue( 2806 com.android.internal.R.styleable.AndroidManifestApplication_fullBackupContent); 2807 if (v != null && (ai.fullBackupContent = v.resourceId) == 0) { 2808 if (DEBUG_BACKUP) { 2809 Slog.v(TAG, "fullBackupContent specified as boolean=" + 2810 (v.data == 0 ? "false" : "true")); 2811 } 2812 // "false" => -1, "true" => 0 2813 ai.fullBackupContent = (v.data == 0 ? -1 : 0); 2814 } 2815 if (DEBUG_BACKUP) { 2816 Slog.v(TAG, "fullBackupContent=" + ai.fullBackupContent + " for " + pkgName); 2817 } 2818 } 2819 2820 ai.theme = sa.getResourceId( 2821 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); 2822 ai.descriptionRes = sa.getResourceId( 2823 com.android.internal.R.styleable.AndroidManifestApplication_description, 0); 2824 2825 if ((flags&PARSE_IS_SYSTEM) != 0) { 2826 if (sa.getBoolean( 2827 com.android.internal.R.styleable.AndroidManifestApplication_persistent, 2828 false)) { 2829 ai.flags |= ApplicationInfo.FLAG_PERSISTENT; 2830 } 2831 } 2832 2833 if (sa.getBoolean( 2834 com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers, 2835 false)) { 2836 owner.mRequiredForAllUsers = true; 2837 } 2838 2839 String restrictedAccountType = sa.getString(com.android.internal.R.styleable 2840 .AndroidManifestApplication_restrictedAccountType); 2841 if (restrictedAccountType != null && restrictedAccountType.length() > 0) { 2842 owner.mRestrictedAccountType = restrictedAccountType; 2843 } 2844 2845 String requiredAccountType = sa.getString(com.android.internal.R.styleable 2846 .AndroidManifestApplication_requiredAccountType); 2847 if (requiredAccountType != null && requiredAccountType.length() > 0) { 2848 owner.mRequiredAccountType = requiredAccountType; 2849 } 2850 2851 if (sa.getBoolean( 2852 com.android.internal.R.styleable.AndroidManifestApplication_debuggable, 2853 false)) { 2854 ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE; 2855 } 2856 2857 if (sa.getBoolean( 2858 com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode, 2859 false)) { 2860 ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE; 2861 } 2862 2863 owner.baseHardwareAccelerated = sa.getBoolean( 2864 com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated, 2865 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH); 2866 if (owner.baseHardwareAccelerated) { 2867 ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED; 2868 } 2869 2870 if (sa.getBoolean( 2871 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, 2872 true)) { 2873 ai.flags |= ApplicationInfo.FLAG_HAS_CODE; 2874 } 2875 2876 if (sa.getBoolean( 2877 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting, 2878 false)) { 2879 ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; 2880 } 2881 2882 if (sa.getBoolean( 2883 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData, 2884 true)) { 2885 ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; 2886 } 2887 2888 // The parent package controls installation, hence specify test only installs. 2889 if (owner.parentPackage == null) { 2890 if (sa.getBoolean( 2891 com.android.internal.R.styleable.AndroidManifestApplication_testOnly, 2892 false)) { 2893 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY; 2894 } 2895 } 2896 2897 if (sa.getBoolean( 2898 com.android.internal.R.styleable.AndroidManifestApplication_largeHeap, 2899 false)) { 2900 ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP; 2901 } 2902 2903 if (sa.getBoolean( 2904 com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic, 2905 true)) { 2906 ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC; 2907 } 2908 2909 if (sa.getBoolean( 2910 com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl, 2911 false /* default is no RTL support*/)) { 2912 ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL; 2913 } 2914 2915 if (sa.getBoolean( 2916 com.android.internal.R.styleable.AndroidManifestApplication_multiArch, 2917 false)) { 2918 ai.flags |= ApplicationInfo.FLAG_MULTIARCH; 2919 } 2920 2921 if (sa.getBoolean( 2922 com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs, 2923 true)) { 2924 ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS; 2925 } 2926 2927 if (sa.getBoolean( 2928 R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, 2929 false)) { 2930 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE; 2931 } 2932 if (sa.getBoolean( 2933 R.styleable.AndroidManifestApplication_directBootAware, 2934 false)) { 2935 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; 2936 } 2937 2938 if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity, 2939 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N)) { 2940 ai.privateFlags |= PRIVATE_FLAG_RESIZEABLE_ACTIVITIES; 2941 } 2942 2943 ai.networkSecurityConfigRes = sa.getResourceId( 2944 com.android.internal.R.styleable.AndroidManifestApplication_networkSecurityConfig, 2945 0); 2946 2947 String str; 2948 str = sa.getNonConfigurationString( 2949 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0); 2950 ai.permission = (str != null && str.length() > 0) ? str.intern() : null; 2951 2952 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 2953 str = sa.getNonConfigurationString( 2954 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, 2955 Configuration.NATIVE_CONFIG_VERSION); 2956 } else { 2957 // Some older apps have been seen to use a resource reference 2958 // here that on older builds was ignored (with a warning). We 2959 // need to continue to do this for them so they don't break. 2960 str = sa.getNonResourceString( 2961 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity); 2962 } 2963 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName, 2964 str, outError); 2965 2966 if (outError[0] == null) { 2967 CharSequence pname; 2968 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 2969 pname = sa.getNonConfigurationString( 2970 com.android.internal.R.styleable.AndroidManifestApplication_process, 2971 Configuration.NATIVE_CONFIG_VERSION); 2972 } else { 2973 // Some older apps have been seen to use a resource reference 2974 // here that on older builds was ignored (with a warning). We 2975 // need to continue to do this for them so they don't break. 2976 pname = sa.getNonResourceString( 2977 com.android.internal.R.styleable.AndroidManifestApplication_process); 2978 } 2979 ai.processName = buildProcessName(ai.packageName, null, pname, 2980 flags, mSeparateProcesses, outError); 2981 2982 ai.enabled = sa.getBoolean( 2983 com.android.internal.R.styleable.AndroidManifestApplication_enabled, true); 2984 2985 if (sa.getBoolean( 2986 com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) { 2987 ai.flags |= ApplicationInfo.FLAG_IS_GAME; 2988 } 2989 2990 if (false) { 2991 if (sa.getBoolean( 2992 com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState, 2993 false)) { 2994 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE; 2995 2996 // A heavy-weight application can not be in a custom process. 2997 // We can do direct compare because we intern all strings. 2998 if (ai.processName != null && ai.processName != ai.packageName) { 2999 outError[0] = "cantSaveState applications can not use custom processes"; 3000 } 3001 } 3002 } 3003 } 3004 3005 ai.uiOptions = sa.getInt( 3006 com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0); 3007 3008 sa.recycle(); 3009 3010 if (outError[0] != null) { 3011 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3012 return false; 3013 } 3014 3015 final int innerDepth = parser.getDepth(); 3016 int type; 3017 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 3018 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 3019 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3020 continue; 3021 } 3022 3023 String tagName = parser.getName(); 3024 if (tagName.equals("activity")) { 3025 Activity a = parseActivity(owner, res, parser, flags, outError, false, 3026 owner.baseHardwareAccelerated); 3027 if (a == null) { 3028 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3029 return false; 3030 } 3031 3032 owner.activities.add(a); 3033 3034 } else if (tagName.equals("receiver")) { 3035 Activity a = parseActivity(owner, res, parser, flags, outError, true, false); 3036 if (a == null) { 3037 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3038 return false; 3039 } 3040 3041 owner.receivers.add(a); 3042 3043 } else if (tagName.equals("service")) { 3044 Service s = parseService(owner, res, parser, flags, outError); 3045 if (s == null) { 3046 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3047 return false; 3048 } 3049 3050 owner.services.add(s); 3051 3052 } else if (tagName.equals("provider")) { 3053 Provider p = parseProvider(owner, res, parser, flags, outError); 3054 if (p == null) { 3055 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3056 return false; 3057 } 3058 3059 owner.providers.add(p); 3060 3061 } else if (tagName.equals("activity-alias")) { 3062 Activity a = parseActivityAlias(owner, res, parser, flags, outError); 3063 if (a == null) { 3064 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3065 return false; 3066 } 3067 3068 owner.activities.add(a); 3069 3070 } else if (parser.getName().equals("meta-data")) { 3071 // note: application meta-data is stored off to the side, so it can 3072 // remain null in the primary copy (we like to avoid extra copies because 3073 // it can be large) 3074 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData, 3075 outError)) == null) { 3076 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3077 return false; 3078 } 3079 3080 } else if (tagName.equals("library")) { 3081 sa = res.obtainAttributes(parser, 3082 com.android.internal.R.styleable.AndroidManifestLibrary); 3083 3084 // Note: don't allow this value to be a reference to a resource 3085 // that may change. 3086 String lname = sa.getNonResourceString( 3087 com.android.internal.R.styleable.AndroidManifestLibrary_name); 3088 3089 sa.recycle(); 3090 3091 if (lname != null) { 3092 lname = lname.intern(); 3093 if (!ArrayUtils.contains(owner.libraryNames, lname)) { 3094 owner.libraryNames = ArrayUtils.add(owner.libraryNames, lname); 3095 } 3096 } 3097 3098 XmlUtils.skipCurrentTag(parser); 3099 3100 } else if (tagName.equals("uses-library")) { 3101 sa = res.obtainAttributes(parser, 3102 com.android.internal.R.styleable.AndroidManifestUsesLibrary); 3103 3104 // Note: don't allow this value to be a reference to a resource 3105 // that may change. 3106 String lname = sa.getNonResourceString( 3107 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 3108 boolean req = sa.getBoolean( 3109 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, 3110 true); 3111 3112 sa.recycle(); 3113 3114 if (lname != null) { 3115 lname = lname.intern(); 3116 if (req) { 3117 owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname); 3118 } else { 3119 owner.usesOptionalLibraries = ArrayUtils.add( 3120 owner.usesOptionalLibraries, lname); 3121 } 3122 } 3123 3124 XmlUtils.skipCurrentTag(parser); 3125 3126 } else if (tagName.equals("uses-package")) { 3127 // Dependencies for app installers; we don't currently try to 3128 // enforce this. 3129 XmlUtils.skipCurrentTag(parser); 3130 3131 } else { 3132 if (!RIGID_PARSER) { 3133 Slog.w(TAG, "Unknown element under <application>: " + tagName 3134 + " at " + mArchiveSourcePath + " " 3135 + parser.getPositionDescription()); 3136 XmlUtils.skipCurrentTag(parser); 3137 continue; 3138 } else { 3139 outError[0] = "Bad element under <application>: " + tagName; 3140 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3141 return false; 3142 } 3143 } 3144 } 3145 3146 modifySharedLibrariesForBackwardCompatibility(owner); 3147 3148 if (hasDomainURLs(owner)) { 3149 owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS; 3150 } else { 3151 owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS; 3152 } 3153 3154 return true; 3155 } 3156 3157 private static void modifySharedLibrariesForBackwardCompatibility(Package owner) { 3158 // "org.apache.http.legacy" is now a part of the boot classpath so it doesn't need 3159 // to be an explicit dependency. 3160 // 3161 // A future change will remove this library from the boot classpath, at which point 3162 // all apps that target SDK 21 and earlier will have it automatically added to their 3163 // dependency lists. 3164 owner.usesLibraries = ArrayUtils.remove(owner.usesLibraries, "org.apache.http.legacy"); 3165 owner.usesOptionalLibraries = ArrayUtils.remove(owner.usesOptionalLibraries, 3166 "org.apache.http.legacy"); 3167 } 3168 3169 /** 3170 * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI 3171 */ 3172 private static boolean hasDomainURLs(Package pkg) { 3173 if (pkg == null || pkg.activities == null) return false; 3174 final ArrayList<Activity> activities = pkg.activities; 3175 final int countActivities = activities.size(); 3176 for (int n=0; n<countActivities; n++) { 3177 Activity activity = activities.get(n); 3178 ArrayList<ActivityIntentInfo> filters = activity.intents; 3179 if (filters == null) continue; 3180 final int countFilters = filters.size(); 3181 for (int m=0; m<countFilters; m++) { 3182 ActivityIntentInfo aii = filters.get(m); 3183 if (!aii.hasAction(Intent.ACTION_VIEW)) continue; 3184 if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue; 3185 if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) || 3186 aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) { 3187 return true; 3188 } 3189 } 3190 } 3191 return false; 3192 } 3193 3194 /** 3195 * Parse the {@code application} XML tree at the current parse location in a 3196 * <em>split APK</em> manifest. 3197 * <p> 3198 * Note that split APKs have many more restrictions on what they're capable 3199 * of doing, so many valid features of a base APK have been carefully 3200 * omitted here. 3201 */ 3202 private boolean parseSplitApplication(Package owner, Resources res, XmlResourceParser parser, 3203 int flags, int splitIndex, String[] outError) 3204 throws XmlPullParserException, IOException { 3205 TypedArray sa = res.obtainAttributes(parser, 3206 com.android.internal.R.styleable.AndroidManifestApplication); 3207 3208 if (sa.getBoolean( 3209 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, true)) { 3210 owner.splitFlags[splitIndex] |= ApplicationInfo.FLAG_HAS_CODE; 3211 } 3212 3213 final int innerDepth = parser.getDepth(); 3214 int type; 3215 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 3216 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 3217 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3218 continue; 3219 } 3220 3221 String tagName = parser.getName(); 3222 if (tagName.equals("activity")) { 3223 Activity a = parseActivity(owner, res, parser, flags, outError, false, 3224 owner.baseHardwareAccelerated); 3225 if (a == null) { 3226 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3227 return false; 3228 } 3229 3230 owner.activities.add(a); 3231 3232 } else if (tagName.equals("receiver")) { 3233 Activity a = parseActivity(owner, res, parser, flags, outError, true, false); 3234 if (a == null) { 3235 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3236 return false; 3237 } 3238 3239 owner.receivers.add(a); 3240 3241 } else if (tagName.equals("service")) { 3242 Service s = parseService(owner, res, parser, flags, outError); 3243 if (s == null) { 3244 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3245 return false; 3246 } 3247 3248 owner.services.add(s); 3249 3250 } else if (tagName.equals("provider")) { 3251 Provider p = parseProvider(owner, res, parser, flags, outError); 3252 if (p == null) { 3253 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3254 return false; 3255 } 3256 3257 owner.providers.add(p); 3258 3259 } else if (tagName.equals("activity-alias")) { 3260 Activity a = parseActivityAlias(owner, res, parser, flags, outError); 3261 if (a == null) { 3262 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3263 return false; 3264 } 3265 3266 owner.activities.add(a); 3267 3268 } else if (parser.getName().equals("meta-data")) { 3269 // note: application meta-data is stored off to the side, so it can 3270 // remain null in the primary copy (we like to avoid extra copies because 3271 // it can be large) 3272 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData, 3273 outError)) == null) { 3274 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3275 return false; 3276 } 3277 3278 } else if (tagName.equals("uses-library")) { 3279 sa = res.obtainAttributes(parser, 3280 com.android.internal.R.styleable.AndroidManifestUsesLibrary); 3281 3282 // Note: don't allow this value to be a reference to a resource 3283 // that may change. 3284 String lname = sa.getNonResourceString( 3285 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 3286 boolean req = sa.getBoolean( 3287 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, 3288 true); 3289 3290 sa.recycle(); 3291 3292 if (lname != null) { 3293 lname = lname.intern(); 3294 if (req) { 3295 // Upgrade to treat as stronger constraint 3296 owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname); 3297 owner.usesOptionalLibraries = ArrayUtils.remove( 3298 owner.usesOptionalLibraries, lname); 3299 } else { 3300 // Ignore if someone already defined as required 3301 if (!ArrayUtils.contains(owner.usesLibraries, lname)) { 3302 owner.usesOptionalLibraries = ArrayUtils.add( 3303 owner.usesOptionalLibraries, lname); 3304 } 3305 } 3306 } 3307 3308 XmlUtils.skipCurrentTag(parser); 3309 3310 } else if (tagName.equals("uses-package")) { 3311 // Dependencies for app installers; we don't currently try to 3312 // enforce this. 3313 XmlUtils.skipCurrentTag(parser); 3314 3315 } else { 3316 if (!RIGID_PARSER) { 3317 Slog.w(TAG, "Unknown element under <application>: " + tagName 3318 + " at " + mArchiveSourcePath + " " 3319 + parser.getPositionDescription()); 3320 XmlUtils.skipCurrentTag(parser); 3321 continue; 3322 } else { 3323 outError[0] = "Bad element under <application>: " + tagName; 3324 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3325 return false; 3326 } 3327 } 3328 } 3329 3330 return true; 3331 } 3332 3333 private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo, 3334 String[] outError, String tag, TypedArray sa, boolean nameRequired, 3335 int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) { 3336 String name = sa.getNonConfigurationString(nameRes, 0); 3337 if (name == null) { 3338 if (nameRequired) { 3339 outError[0] = tag + " does not specify android:name"; 3340 return false; 3341 } 3342 } else { 3343 outInfo.name 3344 = buildClassName(owner.applicationInfo.packageName, name, outError); 3345 if (outInfo.name == null) { 3346 return false; 3347 } 3348 } 3349 3350 final boolean useRoundIcon = 3351 Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon); 3352 int roundIconVal = useRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0; 3353 if (roundIconVal != 0) { 3354 outInfo.icon = roundIconVal; 3355 outInfo.nonLocalizedLabel = null; 3356 } else { 3357 int iconVal = sa.getResourceId(iconRes, 0); 3358 if (iconVal != 0) { 3359 outInfo.icon = iconVal; 3360 outInfo.nonLocalizedLabel = null; 3361 } 3362 } 3363 3364 int logoVal = sa.getResourceId(logoRes, 0); 3365 if (logoVal != 0) { 3366 outInfo.logo = logoVal; 3367 } 3368 3369 int bannerVal = sa.getResourceId(bannerRes, 0); 3370 if (bannerVal != 0) { 3371 outInfo.banner = bannerVal; 3372 } 3373 3374 TypedValue v = sa.peekValue(labelRes); 3375 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 3376 outInfo.nonLocalizedLabel = v.coerceToString(); 3377 } 3378 3379 outInfo.packageName = owner.packageName; 3380 3381 return true; 3382 } 3383 3384 private Activity parseActivity(Package owner, Resources res, 3385 XmlResourceParser parser, int flags, String[] outError, 3386 boolean receiver, boolean hardwareAccelerated) 3387 throws XmlPullParserException, IOException { 3388 TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity); 3389 3390 if (mParseActivityArgs == null) { 3391 mParseActivityArgs = new ParseComponentArgs(owner, outError, 3392 R.styleable.AndroidManifestActivity_name, 3393 R.styleable.AndroidManifestActivity_label, 3394 R.styleable.AndroidManifestActivity_icon, 3395 R.styleable.AndroidManifestActivity_roundIcon, 3396 R.styleable.AndroidManifestActivity_logo, 3397 R.styleable.AndroidManifestActivity_banner, 3398 mSeparateProcesses, 3399 R.styleable.AndroidManifestActivity_process, 3400 R.styleable.AndroidManifestActivity_description, 3401 R.styleable.AndroidManifestActivity_enabled); 3402 } 3403 3404 mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>"; 3405 mParseActivityArgs.sa = sa; 3406 mParseActivityArgs.flags = flags; 3407 3408 Activity a = new Activity(mParseActivityArgs, new ActivityInfo()); 3409 if (outError[0] != null) { 3410 sa.recycle(); 3411 return null; 3412 } 3413 3414 boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported); 3415 if (setExported) { 3416 a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false); 3417 } 3418 3419 a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0); 3420 3421 a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, 3422 a.info.applicationInfo.uiOptions); 3423 3424 String parentName = sa.getNonConfigurationString( 3425 R.styleable.AndroidManifestActivity_parentActivityName, 3426 Configuration.NATIVE_CONFIG_VERSION); 3427 if (parentName != null) { 3428 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 3429 if (outError[0] == null) { 3430 a.info.parentActivityName = parentClassName; 3431 } else { 3432 Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " + 3433 parentName); 3434 outError[0] = null; 3435 } 3436 } 3437 3438 String str; 3439 str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0); 3440 if (str == null) { 3441 a.info.permission = owner.applicationInfo.permission; 3442 } else { 3443 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 3444 } 3445 3446 str = sa.getNonConfigurationString( 3447 R.styleable.AndroidManifestActivity_taskAffinity, 3448 Configuration.NATIVE_CONFIG_VERSION); 3449 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName, 3450 owner.applicationInfo.taskAffinity, str, outError); 3451 3452 a.info.flags = 0; 3453 if (sa.getBoolean( 3454 R.styleable.AndroidManifestActivity_multiprocess, false)) { 3455 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS; 3456 } 3457 3458 if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) { 3459 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; 3460 } 3461 3462 if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) { 3463 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; 3464 } 3465 3466 if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) { 3467 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY; 3468 } 3469 3470 if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) { 3471 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; 3472 } 3473 3474 if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) { 3475 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; 3476 } 3477 3478 if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) { 3479 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; 3480 } 3481 3482 if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting, 3483 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) { 3484 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; 3485 } 3486 3487 if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) { 3488 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; 3489 } 3490 3491 if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false) 3492 || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) { 3493 a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; 3494 } 3495 3496 if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) { 3497 a.info.flags |= ActivityInfo.FLAG_IMMERSIVE; 3498 } 3499 3500 if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) { 3501 a.info.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY; 3502 } 3503 3504 if (!receiver) { 3505 if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated, 3506 hardwareAccelerated)) { 3507 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; 3508 } 3509 3510 a.info.launchMode = sa.getInt( 3511 R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE); 3512 a.info.documentLaunchMode = sa.getInt( 3513 R.styleable.AndroidManifestActivity_documentLaunchMode, 3514 ActivityInfo.DOCUMENT_LAUNCH_NONE); 3515 a.info.maxRecents = sa.getInt( 3516 R.styleable.AndroidManifestActivity_maxRecents, 3517 ActivityManager.getDefaultAppRecentsLimitStatic()); 3518 a.info.configChanges = sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0); 3519 a.info.softInputMode = sa.getInt( 3520 R.styleable.AndroidManifestActivity_windowSoftInputMode, 0); 3521 3522 a.info.persistableMode = sa.getInteger( 3523 R.styleable.AndroidManifestActivity_persistableMode, 3524 ActivityInfo.PERSIST_ROOT_ONLY); 3525 3526 if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) { 3527 a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED; 3528 } 3529 3530 if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) { 3531 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS; 3532 } 3533 3534 if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) { 3535 a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; 3536 } 3537 3538 if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) { 3539 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING; 3540 } 3541 3542 a.info.screenOrientation = sa.getInt( 3543 R.styleable.AndroidManifestActivity_screenOrientation, 3544 SCREEN_ORIENTATION_UNSPECIFIED); 3545 3546 a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; 3547 final boolean appDefault = (owner.applicationInfo.privateFlags 3548 & PRIVATE_FLAG_RESIZEABLE_ACTIVITIES) != 0; 3549 // This flag is used to workaround the issue with ignored resizeableActivity param when 3550 // either targetSdkVersion is not set at all or <uses-sdk> tag is below <application> 3551 // tag in AndroidManifest. If this param was explicitly set to 'false' we need to set 3552 // corresponding resizeMode regardless of targetSdkVersion value at this point in time. 3553 final boolean resizeableSetExplicitly 3554 = sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity); 3555 final boolean resizeable = sa.getBoolean( 3556 R.styleable.AndroidManifestActivity_resizeableActivity, appDefault); 3557 3558 if (resizeable) { 3559 if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, 3560 false)) { 3561 a.info.resizeMode = RESIZE_MODE_RESIZEABLE_AND_PIPABLE; 3562 } else { 3563 a.info.resizeMode = RESIZE_MODE_RESIZEABLE; 3564 } 3565 } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N 3566 || resizeableSetExplicitly) { 3567 a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; 3568 } else if (!a.info.isFixedOrientation() && (a.info.flags & FLAG_IMMERSIVE) == 0) { 3569 a.info.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; 3570 } 3571 3572 if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) { 3573 a.info.flags |= FLAG_ALWAYS_FOCUSABLE; 3574 } 3575 3576 a.info.lockTaskLaunchMode = 3577 sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0); 3578 3579 a.info.encryptionAware = a.info.directBootAware = sa.getBoolean( 3580 R.styleable.AndroidManifestActivity_directBootAware, 3581 false); 3582 3583 a.info.requestedVrComponent = 3584 sa.getString(R.styleable.AndroidManifestActivity_enableVrMode); 3585 } else { 3586 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; 3587 a.info.configChanges = 0; 3588 3589 if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) { 3590 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER; 3591 if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 3592 Slog.w(TAG, "Activity exported request ignored due to singleUser: " 3593 + a.className + " at " + mArchiveSourcePath + " " 3594 + parser.getPositionDescription()); 3595 a.info.exported = false; 3596 setExported = true; 3597 } 3598 } 3599 3600 a.info.encryptionAware = a.info.directBootAware = sa.getBoolean( 3601 R.styleable.AndroidManifestActivity_directBootAware, 3602 false); 3603 } 3604 3605 if (a.info.directBootAware) { 3606 owner.applicationInfo.privateFlags |= 3607 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; 3608 } 3609 3610 sa.recycle(); 3611 3612 if (receiver && (owner.applicationInfo.privateFlags 3613 &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { 3614 // A heavy-weight application can not have receives in its main process 3615 // We can do direct compare because we intern all strings. 3616 if (a.info.processName == owner.packageName) { 3617 outError[0] = "Heavy-weight applications can not have receivers in main process"; 3618 } 3619 } 3620 3621 if (outError[0] != null) { 3622 return null; 3623 } 3624 3625 int outerDepth = parser.getDepth(); 3626 int type; 3627 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3628 && (type != XmlPullParser.END_TAG 3629 || parser.getDepth() > outerDepth)) { 3630 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3631 continue; 3632 } 3633 3634 if (parser.getName().equals("intent-filter")) { 3635 ActivityIntentInfo intent = new ActivityIntentInfo(a); 3636 if (!parseIntent(res, parser, true, true, intent, outError)) { 3637 return null; 3638 } 3639 if (intent.countActions() == 0) { 3640 Slog.w(TAG, "No actions in intent filter at " 3641 + mArchiveSourcePath + " " 3642 + parser.getPositionDescription()); 3643 } else { 3644 a.intents.add(intent); 3645 } 3646 } else if (!receiver && parser.getName().equals("preferred")) { 3647 ActivityIntentInfo intent = new ActivityIntentInfo(a); 3648 if (!parseIntent(res, parser, false, false, intent, outError)) { 3649 return null; 3650 } 3651 if (intent.countActions() == 0) { 3652 Slog.w(TAG, "No actions in preferred at " 3653 + mArchiveSourcePath + " " 3654 + parser.getPositionDescription()); 3655 } else { 3656 if (owner.preferredActivityFilters == null) { 3657 owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>(); 3658 } 3659 owner.preferredActivityFilters.add(intent); 3660 } 3661 } else if (parser.getName().equals("meta-data")) { 3662 if ((a.metaData = parseMetaData(res, parser, a.metaData, 3663 outError)) == null) { 3664 return null; 3665 } 3666 } else if (!receiver && parser.getName().equals("layout")) { 3667 parseLayout(res, parser, a); 3668 } else { 3669 if (!RIGID_PARSER) { 3670 Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 3671 if (receiver) { 3672 Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName() 3673 + " at " + mArchiveSourcePath + " " 3674 + parser.getPositionDescription()); 3675 } else { 3676 Slog.w(TAG, "Unknown element under <activity>: " + parser.getName() 3677 + " at " + mArchiveSourcePath + " " 3678 + parser.getPositionDescription()); 3679 } 3680 XmlUtils.skipCurrentTag(parser); 3681 continue; 3682 } else { 3683 if (receiver) { 3684 outError[0] = "Bad element under <receiver>: " + parser.getName(); 3685 } else { 3686 outError[0] = "Bad element under <activity>: " + parser.getName(); 3687 } 3688 return null; 3689 } 3690 } 3691 } 3692 3693 if (!setExported) { 3694 a.info.exported = a.intents.size() > 0; 3695 } 3696 3697 return a; 3698 } 3699 3700 private void parseLayout(Resources res, AttributeSet attrs, Activity a) { 3701 TypedArray sw = res.obtainAttributes(attrs, 3702 com.android.internal.R.styleable.AndroidManifestLayout); 3703 int width = -1; 3704 float widthFraction = -1f; 3705 int height = -1; 3706 float heightFraction = -1f; 3707 final int widthType = sw.getType( 3708 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth); 3709 if (widthType == TypedValue.TYPE_FRACTION) { 3710 widthFraction = sw.getFraction( 3711 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth, 3712 1, 1, -1); 3713 } else if (widthType == TypedValue.TYPE_DIMENSION) { 3714 width = sw.getDimensionPixelSize( 3715 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth, 3716 -1); 3717 } 3718 final int heightType = sw.getType( 3719 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight); 3720 if (heightType == TypedValue.TYPE_FRACTION) { 3721 heightFraction = sw.getFraction( 3722 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight, 3723 1, 1, -1); 3724 } else if (heightType == TypedValue.TYPE_DIMENSION) { 3725 height = sw.getDimensionPixelSize( 3726 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight, 3727 -1); 3728 } 3729 int gravity = sw.getInt( 3730 com.android.internal.R.styleable.AndroidManifestLayout_gravity, 3731 Gravity.CENTER); 3732 int minWidth = sw.getDimensionPixelSize( 3733 com.android.internal.R.styleable.AndroidManifestLayout_minWidth, 3734 -1); 3735 int minHeight = sw.getDimensionPixelSize( 3736 com.android.internal.R.styleable.AndroidManifestLayout_minHeight, 3737 -1); 3738 sw.recycle(); 3739 a.info.windowLayout = new ActivityInfo.WindowLayout(width, widthFraction, 3740 height, heightFraction, gravity, minWidth, minHeight); 3741 } 3742 3743 private Activity parseActivityAlias(Package owner, Resources res, 3744 XmlResourceParser parser, int flags, String[] outError) 3745 throws XmlPullParserException, IOException { 3746 TypedArray sa = res.obtainAttributes(parser, 3747 com.android.internal.R.styleable.AndroidManifestActivityAlias); 3748 3749 String targetActivity = sa.getNonConfigurationString( 3750 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity, 3751 Configuration.NATIVE_CONFIG_VERSION); 3752 if (targetActivity == null) { 3753 outError[0] = "<activity-alias> does not specify android:targetActivity"; 3754 sa.recycle(); 3755 return null; 3756 } 3757 3758 targetActivity = buildClassName(owner.applicationInfo.packageName, 3759 targetActivity, outError); 3760 if (targetActivity == null) { 3761 sa.recycle(); 3762 return null; 3763 } 3764 3765 if (mParseActivityAliasArgs == null) { 3766 mParseActivityAliasArgs = new ParseComponentArgs(owner, outError, 3767 com.android.internal.R.styleable.AndroidManifestActivityAlias_name, 3768 com.android.internal.R.styleable.AndroidManifestActivityAlias_label, 3769 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, 3770 com.android.internal.R.styleable.AndroidManifestActivityAlias_roundIcon, 3771 com.android.internal.R.styleable.AndroidManifestActivityAlias_logo, 3772 com.android.internal.R.styleable.AndroidManifestActivityAlias_banner, 3773 mSeparateProcesses, 3774 0, 3775 com.android.internal.R.styleable.AndroidManifestActivityAlias_description, 3776 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled); 3777 mParseActivityAliasArgs.tag = "<activity-alias>"; 3778 } 3779 3780 mParseActivityAliasArgs.sa = sa; 3781 mParseActivityAliasArgs.flags = flags; 3782 3783 Activity target = null; 3784 3785 final int NA = owner.activities.size(); 3786 for (int i=0; i<NA; i++) { 3787 Activity t = owner.activities.get(i); 3788 if (targetActivity.equals(t.info.name)) { 3789 target = t; 3790 break; 3791 } 3792 } 3793 3794 if (target == null) { 3795 outError[0] = "<activity-alias> target activity " + targetActivity 3796 + " not found in manifest"; 3797 sa.recycle(); 3798 return null; 3799 } 3800 3801 ActivityInfo info = new ActivityInfo(); 3802 info.targetActivity = targetActivity; 3803 info.configChanges = target.info.configChanges; 3804 info.flags = target.info.flags; 3805 info.icon = target.info.icon; 3806 info.logo = target.info.logo; 3807 info.banner = target.info.banner; 3808 info.labelRes = target.info.labelRes; 3809 info.nonLocalizedLabel = target.info.nonLocalizedLabel; 3810 info.launchMode = target.info.launchMode; 3811 info.lockTaskLaunchMode = target.info.lockTaskLaunchMode; 3812 info.processName = target.info.processName; 3813 if (info.descriptionRes == 0) { 3814 info.descriptionRes = target.info.descriptionRes; 3815 } 3816 info.screenOrientation = target.info.screenOrientation; 3817 info.taskAffinity = target.info.taskAffinity; 3818 info.theme = target.info.theme; 3819 info.softInputMode = target.info.softInputMode; 3820 info.uiOptions = target.info.uiOptions; 3821 info.parentActivityName = target.info.parentActivityName; 3822 info.maxRecents = target.info.maxRecents; 3823 info.windowLayout = target.info.windowLayout; 3824 info.resizeMode = target.info.resizeMode; 3825 info.encryptionAware = info.directBootAware = target.info.directBootAware; 3826 3827 Activity a = new Activity(mParseActivityAliasArgs, info); 3828 if (outError[0] != null) { 3829 sa.recycle(); 3830 return null; 3831 } 3832 3833 final boolean setExported = sa.hasValue( 3834 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported); 3835 if (setExported) { 3836 a.info.exported = sa.getBoolean( 3837 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false); 3838 } 3839 3840 String str; 3841 str = sa.getNonConfigurationString( 3842 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0); 3843 if (str != null) { 3844 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 3845 } 3846 3847 String parentName = sa.getNonConfigurationString( 3848 com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName, 3849 Configuration.NATIVE_CONFIG_VERSION); 3850 if (parentName != null) { 3851 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 3852 if (outError[0] == null) { 3853 a.info.parentActivityName = parentClassName; 3854 } else { 3855 Log.e(TAG, "Activity alias " + a.info.name + 3856 " specified invalid parentActivityName " + parentName); 3857 outError[0] = null; 3858 } 3859 } 3860 3861 sa.recycle(); 3862 3863 if (outError[0] != null) { 3864 return null; 3865 } 3866 3867 int outerDepth = parser.getDepth(); 3868 int type; 3869 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3870 && (type != XmlPullParser.END_TAG 3871 || parser.getDepth() > outerDepth)) { 3872 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3873 continue; 3874 } 3875 3876 if (parser.getName().equals("intent-filter")) { 3877 ActivityIntentInfo intent = new ActivityIntentInfo(a); 3878 if (!parseIntent(res, parser, true, true, intent, outError)) { 3879 return null; 3880 } 3881 if (intent.countActions() == 0) { 3882 Slog.w(TAG, "No actions in intent filter at " 3883 + mArchiveSourcePath + " " 3884 + parser.getPositionDescription()); 3885 } else { 3886 a.intents.add(intent); 3887 } 3888 } else if (parser.getName().equals("meta-data")) { 3889 if ((a.metaData=parseMetaData(res, parser, a.metaData, 3890 outError)) == null) { 3891 return null; 3892 } 3893 } else { 3894 if (!RIGID_PARSER) { 3895 Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName() 3896 + " at " + mArchiveSourcePath + " " 3897 + parser.getPositionDescription()); 3898 XmlUtils.skipCurrentTag(parser); 3899 continue; 3900 } else { 3901 outError[0] = "Bad element under <activity-alias>: " + parser.getName(); 3902 return null; 3903 } 3904 } 3905 } 3906 3907 if (!setExported) { 3908 a.info.exported = a.intents.size() > 0; 3909 } 3910 3911 return a; 3912 } 3913 3914 private Provider parseProvider(Package owner, Resources res, 3915 XmlResourceParser parser, int flags, String[] outError) 3916 throws XmlPullParserException, IOException { 3917 TypedArray sa = res.obtainAttributes(parser, 3918 com.android.internal.R.styleable.AndroidManifestProvider); 3919 3920 if (mParseProviderArgs == null) { 3921 mParseProviderArgs = new ParseComponentArgs(owner, outError, 3922 com.android.internal.R.styleable.AndroidManifestProvider_name, 3923 com.android.internal.R.styleable.AndroidManifestProvider_label, 3924 com.android.internal.R.styleable.AndroidManifestProvider_icon, 3925 com.android.internal.R.styleable.AndroidManifestProvider_roundIcon, 3926 com.android.internal.R.styleable.AndroidManifestProvider_logo, 3927 com.android.internal.R.styleable.AndroidManifestProvider_banner, 3928 mSeparateProcesses, 3929 com.android.internal.R.styleable.AndroidManifestProvider_process, 3930 com.android.internal.R.styleable.AndroidManifestProvider_description, 3931 com.android.internal.R.styleable.AndroidManifestProvider_enabled); 3932 mParseProviderArgs.tag = "<provider>"; 3933 } 3934 3935 mParseProviderArgs.sa = sa; 3936 mParseProviderArgs.flags = flags; 3937 3938 Provider p = new Provider(mParseProviderArgs, new ProviderInfo()); 3939 if (outError[0] != null) { 3940 sa.recycle(); 3941 return null; 3942 } 3943 3944 boolean providerExportedDefault = false; 3945 3946 if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 3947 // For compatibility, applications targeting API level 16 or lower 3948 // should have their content providers exported by default, unless they 3949 // specify otherwise. 3950 providerExportedDefault = true; 3951 } 3952 3953 p.info.exported = sa.getBoolean( 3954 com.android.internal.R.styleable.AndroidManifestProvider_exported, 3955 providerExportedDefault); 3956 3957 String cpname = sa.getNonConfigurationString( 3958 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0); 3959 3960 p.info.isSyncable = sa.getBoolean( 3961 com.android.internal.R.styleable.AndroidManifestProvider_syncable, 3962 false); 3963 3964 String permission = sa.getNonConfigurationString( 3965 com.android.internal.R.styleable.AndroidManifestProvider_permission, 0); 3966 String str = sa.getNonConfigurationString( 3967 com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0); 3968 if (str == null) { 3969 str = permission; 3970 } 3971 if (str == null) { 3972 p.info.readPermission = owner.applicationInfo.permission; 3973 } else { 3974 p.info.readPermission = 3975 str.length() > 0 ? str.toString().intern() : null; 3976 } 3977 str = sa.getNonConfigurationString( 3978 com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0); 3979 if (str == null) { 3980 str = permission; 3981 } 3982 if (str == null) { 3983 p.info.writePermission = owner.applicationInfo.permission; 3984 } else { 3985 p.info.writePermission = 3986 str.length() > 0 ? str.toString().intern() : null; 3987 } 3988 3989 p.info.grantUriPermissions = sa.getBoolean( 3990 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions, 3991 false); 3992 3993 p.info.multiprocess = sa.getBoolean( 3994 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess, 3995 false); 3996 3997 p.info.initOrder = sa.getInt( 3998 com.android.internal.R.styleable.AndroidManifestProvider_initOrder, 3999 0); 4000 4001 p.info.flags = 0; 4002 4003 if (sa.getBoolean( 4004 com.android.internal.R.styleable.AndroidManifestProvider_singleUser, 4005 false)) { 4006 p.info.flags |= ProviderInfo.FLAG_SINGLE_USER; 4007 if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 4008 Slog.w(TAG, "Provider exported request ignored due to singleUser: " 4009 + p.className + " at " + mArchiveSourcePath + " " 4010 + parser.getPositionDescription()); 4011 p.info.exported = false; 4012 } 4013 } 4014 4015 p.info.encryptionAware = p.info.directBootAware = sa.getBoolean( 4016 R.styleable.AndroidManifestProvider_directBootAware, 4017 false); 4018 if (p.info.directBootAware) { 4019 owner.applicationInfo.privateFlags |= 4020 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; 4021 } 4022 4023 sa.recycle(); 4024 4025 if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) 4026 != 0) { 4027 // A heavy-weight application can not have providers in its main process 4028 // We can do direct compare because we intern all strings. 4029 if (p.info.processName == owner.packageName) { 4030 outError[0] = "Heavy-weight applications can not have providers in main process"; 4031 return null; 4032 } 4033 } 4034 4035 if (cpname == null) { 4036 outError[0] = "<provider> does not include authorities attribute"; 4037 return null; 4038 } 4039 if (cpname.length() <= 0) { 4040 outError[0] = "<provider> has empty authorities attribute"; 4041 return null; 4042 } 4043 p.info.authority = cpname.intern(); 4044 4045 if (!parseProviderTags(res, parser, p, outError)) { 4046 return null; 4047 } 4048 4049 return p; 4050 } 4051 4052 private boolean parseProviderTags(Resources res, 4053 XmlResourceParser parser, Provider outInfo, String[] outError) 4054 throws XmlPullParserException, IOException { 4055 int outerDepth = parser.getDepth(); 4056 int type; 4057 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 4058 && (type != XmlPullParser.END_TAG 4059 || parser.getDepth() > outerDepth)) { 4060 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4061 continue; 4062 } 4063 4064 if (parser.getName().equals("intent-filter")) { 4065 ProviderIntentInfo intent = new ProviderIntentInfo(outInfo); 4066 if (!parseIntent(res, parser, true, false, intent, outError)) { 4067 return false; 4068 } 4069 outInfo.intents.add(intent); 4070 4071 } else if (parser.getName().equals("meta-data")) { 4072 if ((outInfo.metaData=parseMetaData(res, parser, 4073 outInfo.metaData, outError)) == null) { 4074 return false; 4075 } 4076 4077 } else if (parser.getName().equals("grant-uri-permission")) { 4078 TypedArray sa = res.obtainAttributes(parser, 4079 com.android.internal.R.styleable.AndroidManifestGrantUriPermission); 4080 4081 PatternMatcher pa = null; 4082 4083 String str = sa.getNonConfigurationString( 4084 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0); 4085 if (str != null) { 4086 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); 4087 } 4088 4089 str = sa.getNonConfigurationString( 4090 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); 4091 if (str != null) { 4092 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); 4093 } 4094 4095 str = sa.getNonConfigurationString( 4096 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); 4097 if (str != null) { 4098 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 4099 } 4100 4101 sa.recycle(); 4102 4103 if (pa != null) { 4104 if (outInfo.info.uriPermissionPatterns == null) { 4105 outInfo.info.uriPermissionPatterns = new PatternMatcher[1]; 4106 outInfo.info.uriPermissionPatterns[0] = pa; 4107 } else { 4108 final int N = outInfo.info.uriPermissionPatterns.length; 4109 PatternMatcher[] newp = new PatternMatcher[N+1]; 4110 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N); 4111 newp[N] = pa; 4112 outInfo.info.uriPermissionPatterns = newp; 4113 } 4114 outInfo.info.grantUriPermissions = true; 4115 } else { 4116 if (!RIGID_PARSER) { 4117 Slog.w(TAG, "Unknown element under <path-permission>: " 4118 + parser.getName() + " at " + mArchiveSourcePath + " " 4119 + parser.getPositionDescription()); 4120 XmlUtils.skipCurrentTag(parser); 4121 continue; 4122 } else { 4123 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 4124 return false; 4125 } 4126 } 4127 XmlUtils.skipCurrentTag(parser); 4128 4129 } else if (parser.getName().equals("path-permission")) { 4130 TypedArray sa = res.obtainAttributes(parser, 4131 com.android.internal.R.styleable.AndroidManifestPathPermission); 4132 4133 PathPermission pa = null; 4134 4135 String permission = sa.getNonConfigurationString( 4136 com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0); 4137 String readPermission = sa.getNonConfigurationString( 4138 com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0); 4139 if (readPermission == null) { 4140 readPermission = permission; 4141 } 4142 String writePermission = sa.getNonConfigurationString( 4143 com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0); 4144 if (writePermission == null) { 4145 writePermission = permission; 4146 } 4147 4148 boolean havePerm = false; 4149 if (readPermission != null) { 4150 readPermission = readPermission.intern(); 4151 havePerm = true; 4152 } 4153 if (writePermission != null) { 4154 writePermission = writePermission.intern(); 4155 havePerm = true; 4156 } 4157 4158 if (!havePerm) { 4159 if (!RIGID_PARSER) { 4160 Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: " 4161 + parser.getName() + " at " + mArchiveSourcePath + " " 4162 + parser.getPositionDescription()); 4163 XmlUtils.skipCurrentTag(parser); 4164 continue; 4165 } else { 4166 outError[0] = "No readPermission or writePermssion for <path-permission>"; 4167 return false; 4168 } 4169 } 4170 4171 String path = sa.getNonConfigurationString( 4172 com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0); 4173 if (path != null) { 4174 pa = new PathPermission(path, 4175 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission); 4176 } 4177 4178 path = sa.getNonConfigurationString( 4179 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0); 4180 if (path != null) { 4181 pa = new PathPermission(path, 4182 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission); 4183 } 4184 4185 path = sa.getNonConfigurationString( 4186 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0); 4187 if (path != null) { 4188 pa = new PathPermission(path, 4189 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission); 4190 } 4191 4192 sa.recycle(); 4193 4194 if (pa != null) { 4195 if (outInfo.info.pathPermissions == null) { 4196 outInfo.info.pathPermissions = new PathPermission[1]; 4197 outInfo.info.pathPermissions[0] = pa; 4198 } else { 4199 final int N = outInfo.info.pathPermissions.length; 4200 PathPermission[] newp = new PathPermission[N+1]; 4201 System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N); 4202 newp[N] = pa; 4203 outInfo.info.pathPermissions = newp; 4204 } 4205 } else { 4206 if (!RIGID_PARSER) { 4207 Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: " 4208 + parser.getName() + " at " + mArchiveSourcePath + " " 4209 + parser.getPositionDescription()); 4210 XmlUtils.skipCurrentTag(parser); 4211 continue; 4212 } 4213 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 4214 return false; 4215 } 4216 XmlUtils.skipCurrentTag(parser); 4217 4218 } else { 4219 if (!RIGID_PARSER) { 4220 Slog.w(TAG, "Unknown element under <provider>: " 4221 + parser.getName() + " at " + mArchiveSourcePath + " " 4222 + parser.getPositionDescription()); 4223 XmlUtils.skipCurrentTag(parser); 4224 continue; 4225 } else { 4226 outError[0] = "Bad element under <provider>: " + parser.getName(); 4227 return false; 4228 } 4229 } 4230 } 4231 return true; 4232 } 4233 4234 private Service parseService(Package owner, Resources res, 4235 XmlResourceParser parser, int flags, String[] outError) 4236 throws XmlPullParserException, IOException { 4237 TypedArray sa = res.obtainAttributes(parser, 4238 com.android.internal.R.styleable.AndroidManifestService); 4239 4240 if (mParseServiceArgs == null) { 4241 mParseServiceArgs = new ParseComponentArgs(owner, outError, 4242 com.android.internal.R.styleable.AndroidManifestService_name, 4243 com.android.internal.R.styleable.AndroidManifestService_label, 4244 com.android.internal.R.styleable.AndroidManifestService_icon, 4245 com.android.internal.R.styleable.AndroidManifestService_roundIcon, 4246 com.android.internal.R.styleable.AndroidManifestService_logo, 4247 com.android.internal.R.styleable.AndroidManifestService_banner, 4248 mSeparateProcesses, 4249 com.android.internal.R.styleable.AndroidManifestService_process, 4250 com.android.internal.R.styleable.AndroidManifestService_description, 4251 com.android.internal.R.styleable.AndroidManifestService_enabled); 4252 mParseServiceArgs.tag = "<service>"; 4253 } 4254 4255 mParseServiceArgs.sa = sa; 4256 mParseServiceArgs.flags = flags; 4257 4258 Service s = new Service(mParseServiceArgs, new ServiceInfo()); 4259 if (outError[0] != null) { 4260 sa.recycle(); 4261 return null; 4262 } 4263 4264 boolean setExported = sa.hasValue( 4265 com.android.internal.R.styleable.AndroidManifestService_exported); 4266 if (setExported) { 4267 s.info.exported = sa.getBoolean( 4268 com.android.internal.R.styleable.AndroidManifestService_exported, false); 4269 } 4270 4271 String str = sa.getNonConfigurationString( 4272 com.android.internal.R.styleable.AndroidManifestService_permission, 0); 4273 if (str == null) { 4274 s.info.permission = owner.applicationInfo.permission; 4275 } else { 4276 s.info.permission = str.length() > 0 ? str.toString().intern() : null; 4277 } 4278 4279 s.info.flags = 0; 4280 if (sa.getBoolean( 4281 com.android.internal.R.styleable.AndroidManifestService_stopWithTask, 4282 false)) { 4283 s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK; 4284 } 4285 if (sa.getBoolean( 4286 com.android.internal.R.styleable.AndroidManifestService_isolatedProcess, 4287 false)) { 4288 s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS; 4289 } 4290 if (sa.getBoolean( 4291 com.android.internal.R.styleable.AndroidManifestService_externalService, 4292 false)) { 4293 s.info.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE; 4294 } 4295 if (sa.getBoolean( 4296 com.android.internal.R.styleable.AndroidManifestService_singleUser, 4297 false)) { 4298 s.info.flags |= ServiceInfo.FLAG_SINGLE_USER; 4299 if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 4300 Slog.w(TAG, "Service exported request ignored due to singleUser: " 4301 + s.className + " at " + mArchiveSourcePath + " " 4302 + parser.getPositionDescription()); 4303 s.info.exported = false; 4304 setExported = true; 4305 } 4306 } 4307 4308 s.info.encryptionAware = s.info.directBootAware = sa.getBoolean( 4309 R.styleable.AndroidManifestService_directBootAware, 4310 false); 4311 if (s.info.directBootAware) { 4312 owner.applicationInfo.privateFlags |= 4313 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; 4314 } 4315 4316 sa.recycle(); 4317 4318 if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) 4319 != 0) { 4320 // A heavy-weight application can not have services in its main process 4321 // We can do direct compare because we intern all strings. 4322 if (s.info.processName == owner.packageName) { 4323 outError[0] = "Heavy-weight applications can not have services in main process"; 4324 return null; 4325 } 4326 } 4327 4328 int outerDepth = parser.getDepth(); 4329 int type; 4330 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 4331 && (type != XmlPullParser.END_TAG 4332 || parser.getDepth() > outerDepth)) { 4333 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4334 continue; 4335 } 4336 4337 if (parser.getName().equals("intent-filter")) { 4338 ServiceIntentInfo intent = new ServiceIntentInfo(s); 4339 if (!parseIntent(res, parser, true, false, intent, outError)) { 4340 return null; 4341 } 4342 4343 s.intents.add(intent); 4344 } else if (parser.getName().equals("meta-data")) { 4345 if ((s.metaData=parseMetaData(res, parser, s.metaData, 4346 outError)) == null) { 4347 return null; 4348 } 4349 } else { 4350 if (!RIGID_PARSER) { 4351 Slog.w(TAG, "Unknown element under <service>: " 4352 + parser.getName() + " at " + mArchiveSourcePath + " " 4353 + parser.getPositionDescription()); 4354 XmlUtils.skipCurrentTag(parser); 4355 continue; 4356 } else { 4357 outError[0] = "Bad element under <service>: " + parser.getName(); 4358 return null; 4359 } 4360 } 4361 } 4362 4363 if (!setExported) { 4364 s.info.exported = s.intents.size() > 0; 4365 } 4366 4367 return s; 4368 } 4369 4370 private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag, 4371 Component<?> outInfo, String[] outError) throws XmlPullParserException, IOException { 4372 int outerDepth = parser.getDepth(); 4373 int type; 4374 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 4375 && (type != XmlPullParser.END_TAG 4376 || parser.getDepth() > outerDepth)) { 4377 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4378 continue; 4379 } 4380 4381 if (parser.getName().equals("meta-data")) { 4382 if ((outInfo.metaData=parseMetaData(res, parser, 4383 outInfo.metaData, outError)) == null) { 4384 return false; 4385 } 4386 } else { 4387 if (!RIGID_PARSER) { 4388 Slog.w(TAG, "Unknown element under " + tag + ": " 4389 + parser.getName() + " at " + mArchiveSourcePath + " " 4390 + parser.getPositionDescription()); 4391 XmlUtils.skipCurrentTag(parser); 4392 continue; 4393 } else { 4394 outError[0] = "Bad element under " + tag + ": " + parser.getName(); 4395 return false; 4396 } 4397 } 4398 } 4399 return true; 4400 } 4401 4402 private Bundle parseMetaData(Resources res, 4403 XmlResourceParser parser, Bundle data, String[] outError) 4404 throws XmlPullParserException, IOException { 4405 4406 TypedArray sa = res.obtainAttributes(parser, 4407 com.android.internal.R.styleable.AndroidManifestMetaData); 4408 4409 if (data == null) { 4410 data = new Bundle(); 4411 } 4412 4413 String name = sa.getNonConfigurationString( 4414 com.android.internal.R.styleable.AndroidManifestMetaData_name, 0); 4415 if (name == null) { 4416 outError[0] = "<meta-data> requires an android:name attribute"; 4417 sa.recycle(); 4418 return null; 4419 } 4420 4421 name = name.intern(); 4422 4423 TypedValue v = sa.peekValue( 4424 com.android.internal.R.styleable.AndroidManifestMetaData_resource); 4425 if (v != null && v.resourceId != 0) { 4426 //Slog.i(TAG, "Meta data ref " + name + ": " + v); 4427 data.putInt(name, v.resourceId); 4428 } else { 4429 v = sa.peekValue( 4430 com.android.internal.R.styleable.AndroidManifestMetaData_value); 4431 //Slog.i(TAG, "Meta data " + name + ": " + v); 4432 if (v != null) { 4433 if (v.type == TypedValue.TYPE_STRING) { 4434 CharSequence cs = v.coerceToString(); 4435 data.putString(name, cs != null ? cs.toString().intern() : null); 4436 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { 4437 data.putBoolean(name, v.data != 0); 4438 } else if (v.type >= TypedValue.TYPE_FIRST_INT 4439 && v.type <= TypedValue.TYPE_LAST_INT) { 4440 data.putInt(name, v.data); 4441 } else if (v.type == TypedValue.TYPE_FLOAT) { 4442 data.putFloat(name, v.getFloat()); 4443 } else { 4444 if (!RIGID_PARSER) { 4445 Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: " 4446 + parser.getName() + " at " + mArchiveSourcePath + " " 4447 + parser.getPositionDescription()); 4448 } else { 4449 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types"; 4450 data = null; 4451 } 4452 } 4453 } else { 4454 outError[0] = "<meta-data> requires an android:value or android:resource attribute"; 4455 data = null; 4456 } 4457 } 4458 4459 sa.recycle(); 4460 4461 XmlUtils.skipCurrentTag(parser); 4462 4463 return data; 4464 } 4465 4466 private static VerifierInfo parseVerifier(Resources res, XmlPullParser parser, 4467 AttributeSet attrs, int flags) { 4468 final TypedArray sa = res.obtainAttributes(attrs, 4469 com.android.internal.R.styleable.AndroidManifestPackageVerifier); 4470 4471 final String packageName = sa.getNonResourceString( 4472 com.android.internal.R.styleable.AndroidManifestPackageVerifier_name); 4473 4474 final String encodedPublicKey = sa.getNonResourceString( 4475 com.android.internal.R.styleable.AndroidManifestPackageVerifier_publicKey); 4476 4477 sa.recycle(); 4478 4479 if (packageName == null || packageName.length() == 0) { 4480 Slog.i(TAG, "verifier package name was null; skipping"); 4481 return null; 4482 } 4483 4484 final PublicKey publicKey = parsePublicKey(encodedPublicKey); 4485 if (publicKey == null) { 4486 Slog.i(TAG, "Unable to parse verifier public key for " + packageName); 4487 return null; 4488 } 4489 4490 return new VerifierInfo(packageName, publicKey); 4491 } 4492 4493 public static final PublicKey parsePublicKey(final String encodedPublicKey) { 4494 if (encodedPublicKey == null) { 4495 Slog.w(TAG, "Could not parse null public key"); 4496 return null; 4497 } 4498 4499 EncodedKeySpec keySpec; 4500 try { 4501 final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT); 4502 keySpec = new X509EncodedKeySpec(encoded); 4503 } catch (IllegalArgumentException e) { 4504 Slog.w(TAG, "Could not parse verifier public key; invalid Base64"); 4505 return null; 4506 } 4507 4508 /* First try the key as an RSA key. */ 4509 try { 4510 final KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 4511 return keyFactory.generatePublic(keySpec); 4512 } catch (NoSuchAlgorithmException e) { 4513 Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build"); 4514 } catch (InvalidKeySpecException e) { 4515 // Not a RSA public key. 4516 } 4517 4518 /* Now try it as a ECDSA key. */ 4519 try { 4520 final KeyFactory keyFactory = KeyFactory.getInstance("EC"); 4521 return keyFactory.generatePublic(keySpec); 4522 } catch (NoSuchAlgorithmException e) { 4523 Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build"); 4524 } catch (InvalidKeySpecException e) { 4525 // Not a ECDSA public key. 4526 } 4527 4528 /* Now try it as a DSA key. */ 4529 try { 4530 final KeyFactory keyFactory = KeyFactory.getInstance("DSA"); 4531 return keyFactory.generatePublic(keySpec); 4532 } catch (NoSuchAlgorithmException e) { 4533 Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build"); 4534 } catch (InvalidKeySpecException e) { 4535 // Not a DSA public key. 4536 } 4537 4538 /* Not a supported key type */ 4539 return null; 4540 } 4541 4542 private static final String ANDROID_RESOURCES 4543 = "http://schemas.android.com/apk/res/android"; 4544 4545 private boolean parseIntent(Resources res, XmlResourceParser parser, 4546 boolean allowGlobs, boolean allowAutoVerify, IntentInfo outInfo, String[] outError) 4547 throws XmlPullParserException, IOException { 4548 4549 TypedArray sa = res.obtainAttributes(parser, 4550 com.android.internal.R.styleable.AndroidManifestIntentFilter); 4551 4552 int priority = sa.getInt( 4553 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0); 4554 outInfo.setPriority(priority); 4555 4556 TypedValue v = sa.peekValue( 4557 com.android.internal.R.styleable.AndroidManifestIntentFilter_label); 4558 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 4559 outInfo.nonLocalizedLabel = v.coerceToString(); 4560 } 4561 4562 final boolean useRoundIcon = 4563 Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon); 4564 int roundIconVal = useRoundIcon ? sa.getResourceId( 4565 com.android.internal.R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0; 4566 if (roundIconVal != 0) { 4567 outInfo.icon = roundIconVal; 4568 } else { 4569 outInfo.icon = sa.getResourceId( 4570 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0); 4571 } 4572 4573 outInfo.logo = sa.getResourceId( 4574 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0); 4575 4576 outInfo.banner = sa.getResourceId( 4577 com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0); 4578 4579 if (allowAutoVerify) { 4580 outInfo.setAutoVerify(sa.getBoolean( 4581 com.android.internal.R.styleable.AndroidManifestIntentFilter_autoVerify, 4582 false)); 4583 } 4584 4585 sa.recycle(); 4586 4587 int outerDepth = parser.getDepth(); 4588 int type; 4589 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 4590 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 4591 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4592 continue; 4593 } 4594 4595 String nodeName = parser.getName(); 4596 if (nodeName.equals("action")) { 4597 String value = parser.getAttributeValue( 4598 ANDROID_RESOURCES, "name"); 4599 if (value == null || value == "") { 4600 outError[0] = "No value supplied for <android:name>"; 4601 return false; 4602 } 4603 XmlUtils.skipCurrentTag(parser); 4604 4605 outInfo.addAction(value); 4606 } else if (nodeName.equals("category")) { 4607 String value = parser.getAttributeValue( 4608 ANDROID_RESOURCES, "name"); 4609 if (value == null || value == "") { 4610 outError[0] = "No value supplied for <android:name>"; 4611 return false; 4612 } 4613 XmlUtils.skipCurrentTag(parser); 4614 4615 outInfo.addCategory(value); 4616 4617 } else if (nodeName.equals("data")) { 4618 sa = res.obtainAttributes(parser, 4619 com.android.internal.R.styleable.AndroidManifestData); 4620 4621 String str = sa.getNonConfigurationString( 4622 com.android.internal.R.styleable.AndroidManifestData_mimeType, 0); 4623 if (str != null) { 4624 try { 4625 outInfo.addDataType(str); 4626 } catch (IntentFilter.MalformedMimeTypeException e) { 4627 outError[0] = e.toString(); 4628 sa.recycle(); 4629 return false; 4630 } 4631 } 4632 4633 str = sa.getNonConfigurationString( 4634 com.android.internal.R.styleable.AndroidManifestData_scheme, 0); 4635 if (str != null) { 4636 outInfo.addDataScheme(str); 4637 } 4638 4639 str = sa.getNonConfigurationString( 4640 com.android.internal.R.styleable.AndroidManifestData_ssp, 0); 4641 if (str != null) { 4642 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL); 4643 } 4644 4645 str = sa.getNonConfigurationString( 4646 com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0); 4647 if (str != null) { 4648 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX); 4649 } 4650 4651 str = sa.getNonConfigurationString( 4652 com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0); 4653 if (str != null) { 4654 if (!allowGlobs) { 4655 outError[0] = "sspPattern not allowed here; ssp must be literal"; 4656 return false; 4657 } 4658 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 4659 } 4660 4661 String host = sa.getNonConfigurationString( 4662 com.android.internal.R.styleable.AndroidManifestData_host, 0); 4663 String port = sa.getNonConfigurationString( 4664 com.android.internal.R.styleable.AndroidManifestData_port, 0); 4665 if (host != null) { 4666 outInfo.addDataAuthority(host, port); 4667 } 4668 4669 str = sa.getNonConfigurationString( 4670 com.android.internal.R.styleable.AndroidManifestData_path, 0); 4671 if (str != null) { 4672 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); 4673 } 4674 4675 str = sa.getNonConfigurationString( 4676 com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0); 4677 if (str != null) { 4678 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); 4679 } 4680 4681 str = sa.getNonConfigurationString( 4682 com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0); 4683 if (str != null) { 4684 if (!allowGlobs) { 4685 outError[0] = "pathPattern not allowed here; path must be literal"; 4686 return false; 4687 } 4688 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 4689 } 4690 4691 sa.recycle(); 4692 XmlUtils.skipCurrentTag(parser); 4693 } else if (!RIGID_PARSER) { 4694 Slog.w(TAG, "Unknown element under <intent-filter>: " 4695 + parser.getName() + " at " + mArchiveSourcePath + " " 4696 + parser.getPositionDescription()); 4697 XmlUtils.skipCurrentTag(parser); 4698 } else { 4699 outError[0] = "Bad element under <intent-filter>: " + parser.getName(); 4700 return false; 4701 } 4702 } 4703 4704 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT); 4705 4706 if (DEBUG_PARSER) { 4707 final StringBuilder cats = new StringBuilder("Intent d="); 4708 cats.append(outInfo.hasDefault); 4709 cats.append(", cat="); 4710 4711 final Iterator<String> it = outInfo.categoriesIterator(); 4712 if (it != null) { 4713 while (it.hasNext()) { 4714 cats.append(' '); 4715 cats.append(it.next()); 4716 } 4717 } 4718 Slog.d(TAG, cats.toString()); 4719 } 4720 4721 return true; 4722 } 4723 4724 /** 4725 * Representation of a full package parsed from APK files on disk. A package 4726 * consists of a single base APK, and zero or more split APKs. 4727 */ 4728 public final static class Package { 4729 4730 public String packageName; 4731 4732 /** Names of any split APKs, ordered by parsed splitName */ 4733 public String[] splitNames; 4734 4735 // TODO: work towards making these paths invariant 4736 4737 public String volumeUuid; 4738 4739 /** 4740 * Path where this package was found on disk. For monolithic packages 4741 * this is path to single base APK file; for cluster packages this is 4742 * path to the cluster directory. 4743 */ 4744 public String codePath; 4745 4746 /** Path of base APK */ 4747 public String baseCodePath; 4748 /** Paths of any split APKs, ordered by parsed splitName */ 4749 public String[] splitCodePaths; 4750 4751 /** Revision code of base APK */ 4752 public int baseRevisionCode; 4753 /** Revision codes of any split APKs, ordered by parsed splitName */ 4754 public int[] splitRevisionCodes; 4755 4756 /** Flags of any split APKs; ordered by parsed splitName */ 4757 public int[] splitFlags; 4758 4759 /** 4760 * Private flags of any split APKs; ordered by parsed splitName. 4761 * 4762 * {@hide} 4763 */ 4764 public int[] splitPrivateFlags; 4765 4766 public boolean baseHardwareAccelerated; 4767 4768 // For now we only support one application per package. 4769 public final ApplicationInfo applicationInfo = new ApplicationInfo(); 4770 4771 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0); 4772 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0); 4773 public final ArrayList<Activity> activities = new ArrayList<Activity>(0); 4774 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0); 4775 public final ArrayList<Provider> providers = new ArrayList<Provider>(0); 4776 public final ArrayList<Service> services = new ArrayList<Service>(0); 4777 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0); 4778 4779 public final ArrayList<String> requestedPermissions = new ArrayList<String>(); 4780 4781 public ArrayList<String> protectedBroadcasts; 4782 4783 public Package parentPackage; 4784 public ArrayList<Package> childPackages; 4785 4786 public ArrayList<String> libraryNames = null; 4787 public ArrayList<String> usesLibraries = null; 4788 public ArrayList<String> usesOptionalLibraries = null; 4789 public String[] usesLibraryFiles = null; 4790 4791 public ArrayList<ActivityIntentInfo> preferredActivityFilters = null; 4792 4793 public ArrayList<String> mOriginalPackages = null; 4794 public String mRealPackage = null; 4795 public ArrayList<String> mAdoptPermissions = null; 4796 4797 // We store the application meta-data independently to avoid multiple unwanted references 4798 public Bundle mAppMetaData = null; 4799 4800 // The version code declared for this package. 4801 public int mVersionCode; 4802 4803 // The version name declared for this package. 4804 public String mVersionName; 4805 4806 // The shared user id that this package wants to use. 4807 public String mSharedUserId; 4808 4809 // The shared user label that this package wants to use. 4810 public int mSharedUserLabel; 4811 4812 // Signatures that were read from the package. 4813 public Signature[] mSignatures; 4814 public Certificate[][] mCertificates; 4815 4816 // For use by package manager service for quick lookup of 4817 // preferred up order. 4818 public int mPreferredOrder = 0; 4819 4820 // For use by package manager to keep track of when a package was last used. 4821 public long[] mLastPackageUsageTimeInMills = 4822 new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT]; 4823 4824 // // User set enabled state. 4825 // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; 4826 // 4827 // // Whether the package has been stopped. 4828 // public boolean mSetStopped = false; 4829 4830 // Additional data supplied by callers. 4831 public Object mExtras; 4832 4833 // Applications hardware preferences 4834 public ArrayList<ConfigurationInfo> configPreferences = null; 4835 4836 // Applications requested features 4837 public ArrayList<FeatureInfo> reqFeatures = null; 4838 4839 // Applications requested feature groups 4840 public ArrayList<FeatureGroupInfo> featureGroups = null; 4841 4842 public int installLocation; 4843 4844 public boolean coreApp; 4845 4846 /* An app that's required for all users and cannot be uninstalled for a user */ 4847 public boolean mRequiredForAllUsers; 4848 4849 /* The restricted account authenticator type that is used by this application */ 4850 public String mRestrictedAccountType; 4851 4852 /* The required account type without which this application will not function */ 4853 public String mRequiredAccountType; 4854 4855 public String mOverlayTarget; 4856 public int mOverlayPriority; 4857 public boolean mTrustedOverlay; 4858 4859 /** 4860 * Data used to feed the KeySetManagerService 4861 */ 4862 public ArraySet<PublicKey> mSigningKeys; 4863 public ArraySet<String> mUpgradeKeySets; 4864 public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping; 4865 4866 /** 4867 * The install time abi override for this package, if any. 4868 * 4869 * TODO: This seems like a horrible place to put the abiOverride because 4870 * this isn't something the packageParser parsers. However, this fits in with 4871 * the rest of the PackageManager where package scanning randomly pushes 4872 * and prods fields out of {@code this.applicationInfo}. 4873 */ 4874 public String cpuAbiOverride; 4875 /** 4876 * The install time abi override to choose 32bit abi's when multiple abi's 4877 * are present. This is only meaningfull for multiarch applications. 4878 * The use32bitAbi attribute is ignored if cpuAbiOverride is also set. 4879 */ 4880 public boolean use32bitAbi; 4881 4882 public byte[] restrictUpdateHash; 4883 4884 public Package(String packageName) { 4885 this.packageName = packageName; 4886 applicationInfo.packageName = packageName; 4887 applicationInfo.uid = -1; 4888 } 4889 4890 public void setApplicationVolumeUuid(String volumeUuid) { 4891 this.applicationInfo.volumeUuid = volumeUuid; 4892 if (childPackages != null) { 4893 final int packageCount = childPackages.size(); 4894 for (int i = 0; i < packageCount; i++) { 4895 childPackages.get(i).applicationInfo.volumeUuid = volumeUuid; 4896 } 4897 } 4898 } 4899 4900 public void setApplicationInfoCodePath(String codePath) { 4901 this.applicationInfo.setCodePath(codePath); 4902 if (childPackages != null) { 4903 final int packageCount = childPackages.size(); 4904 for (int i = 0; i < packageCount; i++) { 4905 childPackages.get(i).applicationInfo.setCodePath(codePath); 4906 } 4907 } 4908 } 4909 4910 public void setApplicationInfoResourcePath(String resourcePath) { 4911 this.applicationInfo.setResourcePath(resourcePath); 4912 if (childPackages != null) { 4913 final int packageCount = childPackages.size(); 4914 for (int i = 0; i < packageCount; i++) { 4915 childPackages.get(i).applicationInfo.setResourcePath(resourcePath); 4916 } 4917 } 4918 } 4919 4920 public void setApplicationInfoBaseResourcePath(String resourcePath) { 4921 this.applicationInfo.setBaseResourcePath(resourcePath); 4922 if (childPackages != null) { 4923 final int packageCount = childPackages.size(); 4924 for (int i = 0; i < packageCount; i++) { 4925 childPackages.get(i).applicationInfo.setBaseResourcePath(resourcePath); 4926 } 4927 } 4928 } 4929 4930 public void setApplicationInfoBaseCodePath(String baseCodePath) { 4931 this.applicationInfo.setBaseCodePath(baseCodePath); 4932 if (childPackages != null) { 4933 final int packageCount = childPackages.size(); 4934 for (int i = 0; i < packageCount; i++) { 4935 childPackages.get(i).applicationInfo.setBaseCodePath(baseCodePath); 4936 } 4937 } 4938 } 4939 4940 public boolean hasChildPackage(String packageName) { 4941 final int childCount = (childPackages != null) ? childPackages.size() : 0; 4942 for (int i = 0; i < childCount; i++) { 4943 if (childPackages.get(i).packageName.equals(packageName)) { 4944 return true; 4945 } 4946 } 4947 return false; 4948 } 4949 4950 public void setApplicationInfoSplitCodePaths(String[] splitCodePaths) { 4951 this.applicationInfo.setSplitCodePaths(splitCodePaths); 4952 // Children have no splits 4953 } 4954 4955 public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) { 4956 this.applicationInfo.setSplitResourcePaths(resroucePaths); 4957 // Children have no splits 4958 } 4959 4960 public void setSplitCodePaths(String[] codePaths) { 4961 this.splitCodePaths = codePaths; 4962 } 4963 4964 public void setCodePath(String codePath) { 4965 this.codePath = codePath; 4966 if (childPackages != null) { 4967 final int packageCount = childPackages.size(); 4968 for (int i = 0; i < packageCount; i++) { 4969 childPackages.get(i).codePath = codePath; 4970 } 4971 } 4972 } 4973 4974 public void setBaseCodePath(String baseCodePath) { 4975 this.baseCodePath = baseCodePath; 4976 if (childPackages != null) { 4977 final int packageCount = childPackages.size(); 4978 for (int i = 0; i < packageCount; i++) { 4979 childPackages.get(i).baseCodePath = baseCodePath; 4980 } 4981 } 4982 } 4983 4984 public void setSignatures(Signature[] signatures) { 4985 this.mSignatures = signatures; 4986 if (childPackages != null) { 4987 final int packageCount = childPackages.size(); 4988 for (int i = 0; i < packageCount; i++) { 4989 childPackages.get(i).mSignatures = signatures; 4990 } 4991 } 4992 } 4993 4994 public void setVolumeUuid(String volumeUuid) { 4995 this.volumeUuid = volumeUuid; 4996 if (childPackages != null) { 4997 final int packageCount = childPackages.size(); 4998 for (int i = 0; i < packageCount; i++) { 4999 childPackages.get(i).volumeUuid = volumeUuid; 5000 } 5001 } 5002 } 5003 5004 public void setApplicationInfoFlags(int mask, int flags) { 5005 applicationInfo.flags = (applicationInfo.flags & ~mask) | (mask & flags); 5006 if (childPackages != null) { 5007 final int packageCount = childPackages.size(); 5008 for (int i = 0; i < packageCount; i++) { 5009 childPackages.get(i).applicationInfo.flags = 5010 (applicationInfo.flags & ~mask) | (mask & flags); 5011 } 5012 } 5013 } 5014 5015 public void setUse32bitAbi(boolean use32bitAbi) { 5016 this.use32bitAbi = use32bitAbi; 5017 if (childPackages != null) { 5018 final int packageCount = childPackages.size(); 5019 for (int i = 0; i < packageCount; i++) { 5020 childPackages.get(i).use32bitAbi = use32bitAbi; 5021 } 5022 } 5023 } 5024 5025 public List<String> getAllCodePaths() { 5026 ArrayList<String> paths = new ArrayList<>(); 5027 paths.add(baseCodePath); 5028 if (!ArrayUtils.isEmpty(splitCodePaths)) { 5029 Collections.addAll(paths, splitCodePaths); 5030 } 5031 return paths; 5032 } 5033 5034 /** 5035 * Filtered set of {@link #getAllCodePaths()} that excludes 5036 * resource-only APKs. 5037 */ 5038 public List<String> getAllCodePathsExcludingResourceOnly() { 5039 ArrayList<String> paths = new ArrayList<>(); 5040 if ((applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { 5041 paths.add(baseCodePath); 5042 } 5043 if (!ArrayUtils.isEmpty(splitCodePaths)) { 5044 for (int i = 0; i < splitCodePaths.length; i++) { 5045 if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { 5046 paths.add(splitCodePaths[i]); 5047 } 5048 } 5049 } 5050 return paths; 5051 } 5052 5053 public void setPackageName(String newName) { 5054 packageName = newName; 5055 applicationInfo.packageName = newName; 5056 for (int i=permissions.size()-1; i>=0; i--) { 5057 permissions.get(i).setPackageName(newName); 5058 } 5059 for (int i=permissionGroups.size()-1; i>=0; i--) { 5060 permissionGroups.get(i).setPackageName(newName); 5061 } 5062 for (int i=activities.size()-1; i>=0; i--) { 5063 activities.get(i).setPackageName(newName); 5064 } 5065 for (int i=receivers.size()-1; i>=0; i--) { 5066 receivers.get(i).setPackageName(newName); 5067 } 5068 for (int i=providers.size()-1; i>=0; i--) { 5069 providers.get(i).setPackageName(newName); 5070 } 5071 for (int i=services.size()-1; i>=0; i--) { 5072 services.get(i).setPackageName(newName); 5073 } 5074 for (int i=instrumentation.size()-1; i>=0; i--) { 5075 instrumentation.get(i).setPackageName(newName); 5076 } 5077 } 5078 5079 public boolean hasComponentClassName(String name) { 5080 for (int i=activities.size()-1; i>=0; i--) { 5081 if (name.equals(activities.get(i).className)) { 5082 return true; 5083 } 5084 } 5085 for (int i=receivers.size()-1; i>=0; i--) { 5086 if (name.equals(receivers.get(i).className)) { 5087 return true; 5088 } 5089 } 5090 for (int i=providers.size()-1; i>=0; i--) { 5091 if (name.equals(providers.get(i).className)) { 5092 return true; 5093 } 5094 } 5095 for (int i=services.size()-1; i>=0; i--) { 5096 if (name.equals(services.get(i).className)) { 5097 return true; 5098 } 5099 } 5100 for (int i=instrumentation.size()-1; i>=0; i--) { 5101 if (name.equals(instrumentation.get(i).className)) { 5102 return true; 5103 } 5104 } 5105 return false; 5106 } 5107 5108 /** 5109 * @hide 5110 */ 5111 public boolean isForwardLocked() { 5112 return applicationInfo.isForwardLocked(); 5113 } 5114 5115 /** 5116 * @hide 5117 */ 5118 public boolean isSystemApp() { 5119 return applicationInfo.isSystemApp(); 5120 } 5121 5122 /** 5123 * @hide 5124 */ 5125 public boolean isPrivilegedApp() { 5126 return applicationInfo.isPrivilegedApp(); 5127 } 5128 5129 /** 5130 * @hide 5131 */ 5132 public boolean isUpdatedSystemApp() { 5133 return applicationInfo.isUpdatedSystemApp(); 5134 } 5135 5136 /** 5137 * @hide 5138 */ 5139 public boolean canHaveOatDir() { 5140 // The following app types CANNOT have oat directory 5141 // - non-updated system apps 5142 // - forward-locked apps or apps installed in ASEC containers 5143 return (!isSystemApp() || isUpdatedSystemApp()) 5144 && !isForwardLocked() && !applicationInfo.isExternalAsec(); 5145 } 5146 5147 public boolean isMatch(int flags) { 5148 if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { 5149 return isSystemApp(); 5150 } 5151 return true; 5152 } 5153 5154 public long getLatestPackageUseTimeInMills() { 5155 long latestUse = 0L; 5156 for (long use : mLastPackageUsageTimeInMills) { 5157 latestUse = Math.max(latestUse, use); 5158 } 5159 return latestUse; 5160 } 5161 5162 public long getLatestForegroundPackageUseTimeInMills() { 5163 int[] foregroundReasons = { 5164 PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY, 5165 PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE 5166 }; 5167 5168 long latestUse = 0L; 5169 for (int reason : foregroundReasons) { 5170 latestUse = Math.max(latestUse, mLastPackageUsageTimeInMills[reason]); 5171 } 5172 return latestUse; 5173 } 5174 5175 public String toString() { 5176 return "Package{" 5177 + Integer.toHexString(System.identityHashCode(this)) 5178 + " " + packageName + "}"; 5179 } 5180 } 5181 5182 public static class Component<II extends IntentInfo> { 5183 public final Package owner; 5184 public final ArrayList<II> intents; 5185 public final String className; 5186 public Bundle metaData; 5187 5188 ComponentName componentName; 5189 String componentShortName; 5190 5191 public Component(Package _owner) { 5192 owner = _owner; 5193 intents = null; 5194 className = null; 5195 } 5196 5197 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) { 5198 owner = args.owner; 5199 intents = new ArrayList<II>(0); 5200 if (parsePackageItemInfo(args.owner, outInfo, args.outError, args.tag, args.sa, 5201 true /*nameRequired*/, args.nameRes, args.labelRes, args.iconRes, 5202 args.roundIconRes, args.logoRes, args.bannerRes)) { 5203 className = outInfo.name; 5204 } else { 5205 className = null; 5206 } 5207 } 5208 5209 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) { 5210 this(args, (PackageItemInfo)outInfo); 5211 if (args.outError[0] != null) { 5212 return; 5213 } 5214 5215 if (args.processRes != 0) { 5216 CharSequence pname; 5217 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 5218 pname = args.sa.getNonConfigurationString(args.processRes, 5219 Configuration.NATIVE_CONFIG_VERSION); 5220 } else { 5221 // Some older apps have been seen to use a resource reference 5222 // here that on older builds was ignored (with a warning). We 5223 // need to continue to do this for them so they don't break. 5224 pname = args.sa.getNonResourceString(args.processRes); 5225 } 5226 outInfo.processName = buildProcessName(owner.applicationInfo.packageName, 5227 owner.applicationInfo.processName, pname, 5228 args.flags, args.sepProcesses, args.outError); 5229 } 5230 5231 if (args.descriptionRes != 0) { 5232 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0); 5233 } 5234 5235 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true); 5236 } 5237 5238 public Component(Component<II> clone) { 5239 owner = clone.owner; 5240 intents = clone.intents; 5241 className = clone.className; 5242 componentName = clone.componentName; 5243 componentShortName = clone.componentShortName; 5244 } 5245 5246 public ComponentName getComponentName() { 5247 if (componentName != null) { 5248 return componentName; 5249 } 5250 if (className != null) { 5251 componentName = new ComponentName(owner.applicationInfo.packageName, 5252 className); 5253 } 5254 return componentName; 5255 } 5256 5257 public void appendComponentShortName(StringBuilder sb) { 5258 ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className); 5259 } 5260 5261 public void printComponentShortName(PrintWriter pw) { 5262 ComponentName.printShortString(pw, owner.applicationInfo.packageName, className); 5263 } 5264 5265 public void setPackageName(String packageName) { 5266 componentName = null; 5267 componentShortName = null; 5268 } 5269 } 5270 5271 public final static class Permission extends Component<IntentInfo> { 5272 public final PermissionInfo info; 5273 public boolean tree; 5274 public PermissionGroup group; 5275 5276 public Permission(Package _owner) { 5277 super(_owner); 5278 info = new PermissionInfo(); 5279 } 5280 5281 public Permission(Package _owner, PermissionInfo _info) { 5282 super(_owner); 5283 info = _info; 5284 } 5285 5286 public void setPackageName(String packageName) { 5287 super.setPackageName(packageName); 5288 info.packageName = packageName; 5289 } 5290 5291 public String toString() { 5292 return "Permission{" 5293 + Integer.toHexString(System.identityHashCode(this)) 5294 + " " + info.name + "}"; 5295 } 5296 } 5297 5298 public final static class PermissionGroup extends Component<IntentInfo> { 5299 public final PermissionGroupInfo info; 5300 5301 public PermissionGroup(Package _owner) { 5302 super(_owner); 5303 info = new PermissionGroupInfo(); 5304 } 5305 5306 public PermissionGroup(Package _owner, PermissionGroupInfo _info) { 5307 super(_owner); 5308 info = _info; 5309 } 5310 5311 public void setPackageName(String packageName) { 5312 super.setPackageName(packageName); 5313 info.packageName = packageName; 5314 } 5315 5316 public String toString() { 5317 return "PermissionGroup{" 5318 + Integer.toHexString(System.identityHashCode(this)) 5319 + " " + info.name + "}"; 5320 } 5321 } 5322 5323 private static boolean copyNeeded(int flags, Package p, 5324 PackageUserState state, Bundle metaData, int userId) { 5325 if (userId != UserHandle.USER_SYSTEM) { 5326 // We always need to copy for other users, since we need 5327 // to fix up the uid. 5328 return true; 5329 } 5330 if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 5331 boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 5332 if (p.applicationInfo.enabled != enabled) { 5333 return true; 5334 } 5335 } 5336 boolean suspended = (p.applicationInfo.flags & FLAG_SUSPENDED) != 0; 5337 if (state.suspended != suspended) { 5338 return true; 5339 } 5340 if (!state.installed || state.hidden) { 5341 return true; 5342 } 5343 if (state.stopped) { 5344 return true; 5345 } 5346 if ((flags & PackageManager.GET_META_DATA) != 0 5347 && (metaData != null || p.mAppMetaData != null)) { 5348 return true; 5349 } 5350 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 5351 && p.usesLibraryFiles != null) { 5352 return true; 5353 } 5354 return false; 5355 } 5356 5357 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 5358 PackageUserState state) { 5359 return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId()); 5360 } 5361 5362 private static void updateApplicationInfo(ApplicationInfo ai, int flags, 5363 PackageUserState state) { 5364 // CompatibilityMode is global state. 5365 if (!sCompatibilityModeEnabled) { 5366 ai.disableCompatibilityMode(); 5367 } 5368 if (state.installed) { 5369 ai.flags |= ApplicationInfo.FLAG_INSTALLED; 5370 } else { 5371 ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; 5372 } 5373 if (state.suspended) { 5374 ai.flags |= ApplicationInfo.FLAG_SUSPENDED; 5375 } else { 5376 ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED; 5377 } 5378 if (state.hidden) { 5379 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN; 5380 } else { 5381 ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN; 5382 } 5383 if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 5384 ai.enabled = true; 5385 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { 5386 ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0; 5387 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED 5388 || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { 5389 ai.enabled = false; 5390 } 5391 ai.enabledSetting = state.enabled; 5392 } 5393 5394 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 5395 PackageUserState state, int userId) { 5396 if (p == null) return null; 5397 if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) { 5398 return null; 5399 } 5400 if (!copyNeeded(flags, p, state, null, userId) 5401 && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0 5402 || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { 5403 // In this case it is safe to directly modify the internal ApplicationInfo state: 5404 // - CompatibilityMode is global state, so will be the same for every call. 5405 // - We only come in to here if the app should reported as installed; this is the 5406 // default state, and we will do a copy otherwise. 5407 // - The enable state will always be reported the same for the application across 5408 // calls; the only exception is for the UNTIL_USED mode, and in that case we will 5409 // be doing a copy. 5410 updateApplicationInfo(p.applicationInfo, flags, state); 5411 return p.applicationInfo; 5412 } 5413 5414 // Make shallow copy so we can store the metadata/libraries safely 5415 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo); 5416 ai.initForUser(userId); 5417 if ((flags & PackageManager.GET_META_DATA) != 0) { 5418 ai.metaData = p.mAppMetaData; 5419 } 5420 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { 5421 ai.sharedLibraryFiles = p.usesLibraryFiles; 5422 } 5423 if (state.stopped) { 5424 ai.flags |= ApplicationInfo.FLAG_STOPPED; 5425 } else { 5426 ai.flags &= ~ApplicationInfo.FLAG_STOPPED; 5427 } 5428 updateApplicationInfo(ai, flags, state); 5429 return ai; 5430 } 5431 5432 public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags, 5433 PackageUserState state, int userId) { 5434 if (ai == null) return null; 5435 if (!checkUseInstalledOrHidden(flags, state)) { 5436 return null; 5437 } 5438 // This is only used to return the ResolverActivity; we will just always 5439 // make a copy. 5440 ai = new ApplicationInfo(ai); 5441 ai.initForUser(userId); 5442 if (state.stopped) { 5443 ai.flags |= ApplicationInfo.FLAG_STOPPED; 5444 } else { 5445 ai.flags &= ~ApplicationInfo.FLAG_STOPPED; 5446 } 5447 updateApplicationInfo(ai, flags, state); 5448 return ai; 5449 } 5450 5451 public static final PermissionInfo generatePermissionInfo( 5452 Permission p, int flags) { 5453 if (p == null) return null; 5454 if ((flags&PackageManager.GET_META_DATA) == 0) { 5455 return p.info; 5456 } 5457 PermissionInfo pi = new PermissionInfo(p.info); 5458 pi.metaData = p.metaData; 5459 return pi; 5460 } 5461 5462 public static final PermissionGroupInfo generatePermissionGroupInfo( 5463 PermissionGroup pg, int flags) { 5464 if (pg == null) return null; 5465 if ((flags&PackageManager.GET_META_DATA) == 0) { 5466 return pg.info; 5467 } 5468 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info); 5469 pgi.metaData = pg.metaData; 5470 return pgi; 5471 } 5472 5473 public final static class Activity extends Component<ActivityIntentInfo> { 5474 public final ActivityInfo info; 5475 5476 public Activity(final ParseComponentArgs args, final ActivityInfo _info) { 5477 super(args, _info); 5478 info = _info; 5479 info.applicationInfo = args.owner.applicationInfo; 5480 } 5481 5482 public void setPackageName(String packageName) { 5483 super.setPackageName(packageName); 5484 info.packageName = packageName; 5485 } 5486 5487 public String toString() { 5488 StringBuilder sb = new StringBuilder(128); 5489 sb.append("Activity{"); 5490 sb.append(Integer.toHexString(System.identityHashCode(this))); 5491 sb.append(' '); 5492 appendComponentShortName(sb); 5493 sb.append('}'); 5494 return sb.toString(); 5495 } 5496 } 5497 5498 public static final ActivityInfo generateActivityInfo(Activity a, int flags, 5499 PackageUserState state, int userId) { 5500 if (a == null) return null; 5501 if (!checkUseInstalledOrHidden(flags, state)) { 5502 return null; 5503 } 5504 if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) { 5505 return a.info; 5506 } 5507 // Make shallow copies so we can store the metadata safely 5508 ActivityInfo ai = new ActivityInfo(a.info); 5509 ai.metaData = a.metaData; 5510 ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId); 5511 return ai; 5512 } 5513 5514 public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags, 5515 PackageUserState state, int userId) { 5516 if (ai == null) return null; 5517 if (!checkUseInstalledOrHidden(flags, state)) { 5518 return null; 5519 } 5520 // This is only used to return the ResolverActivity; we will just always 5521 // make a copy. 5522 ai = new ActivityInfo(ai); 5523 ai.applicationInfo = generateApplicationInfo(ai.applicationInfo, flags, state, userId); 5524 return ai; 5525 } 5526 5527 public final static class Service extends Component<ServiceIntentInfo> { 5528 public final ServiceInfo info; 5529 5530 public Service(final ParseComponentArgs args, final ServiceInfo _info) { 5531 super(args, _info); 5532 info = _info; 5533 info.applicationInfo = args.owner.applicationInfo; 5534 } 5535 5536 public void setPackageName(String packageName) { 5537 super.setPackageName(packageName); 5538 info.packageName = packageName; 5539 } 5540 5541 public String toString() { 5542 StringBuilder sb = new StringBuilder(128); 5543 sb.append("Service{"); 5544 sb.append(Integer.toHexString(System.identityHashCode(this))); 5545 sb.append(' '); 5546 appendComponentShortName(sb); 5547 sb.append('}'); 5548 return sb.toString(); 5549 } 5550 } 5551 5552 public static final ServiceInfo generateServiceInfo(Service s, int flags, 5553 PackageUserState state, int userId) { 5554 if (s == null) return null; 5555 if (!checkUseInstalledOrHidden(flags, state)) { 5556 return null; 5557 } 5558 if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) { 5559 return s.info; 5560 } 5561 // Make shallow copies so we can store the metadata safely 5562 ServiceInfo si = new ServiceInfo(s.info); 5563 si.metaData = s.metaData; 5564 si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId); 5565 return si; 5566 } 5567 5568 public final static class Provider extends Component<ProviderIntentInfo> { 5569 public final ProviderInfo info; 5570 public boolean syncable; 5571 5572 public Provider(final ParseComponentArgs args, final ProviderInfo _info) { 5573 super(args, _info); 5574 info = _info; 5575 info.applicationInfo = args.owner.applicationInfo; 5576 syncable = false; 5577 } 5578 5579 public Provider(Provider existingProvider) { 5580 super(existingProvider); 5581 this.info = existingProvider.info; 5582 this.syncable = existingProvider.syncable; 5583 } 5584 5585 public void setPackageName(String packageName) { 5586 super.setPackageName(packageName); 5587 info.packageName = packageName; 5588 } 5589 5590 public String toString() { 5591 StringBuilder sb = new StringBuilder(128); 5592 sb.append("Provider{"); 5593 sb.append(Integer.toHexString(System.identityHashCode(this))); 5594 sb.append(' '); 5595 appendComponentShortName(sb); 5596 sb.append('}'); 5597 return sb.toString(); 5598 } 5599 } 5600 5601 public static final ProviderInfo generateProviderInfo(Provider p, int flags, 5602 PackageUserState state, int userId) { 5603 if (p == null) return null; 5604 if (!checkUseInstalledOrHidden(flags, state)) { 5605 return null; 5606 } 5607 if (!copyNeeded(flags, p.owner, state, p.metaData, userId) 5608 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 5609 || p.info.uriPermissionPatterns == null)) { 5610 return p.info; 5611 } 5612 // Make shallow copies so we can store the metadata safely 5613 ProviderInfo pi = new ProviderInfo(p.info); 5614 pi.metaData = p.metaData; 5615 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { 5616 pi.uriPermissionPatterns = null; 5617 } 5618 pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId); 5619 return pi; 5620 } 5621 5622 public final static class Instrumentation extends Component<IntentInfo> { 5623 public final InstrumentationInfo info; 5624 5625 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) { 5626 super(args, _info); 5627 info = _info; 5628 } 5629 5630 public void setPackageName(String packageName) { 5631 super.setPackageName(packageName); 5632 info.packageName = packageName; 5633 } 5634 5635 public String toString() { 5636 StringBuilder sb = new StringBuilder(128); 5637 sb.append("Instrumentation{"); 5638 sb.append(Integer.toHexString(System.identityHashCode(this))); 5639 sb.append(' '); 5640 appendComponentShortName(sb); 5641 sb.append('}'); 5642 return sb.toString(); 5643 } 5644 } 5645 5646 public static final InstrumentationInfo generateInstrumentationInfo( 5647 Instrumentation i, int flags) { 5648 if (i == null) return null; 5649 if ((flags&PackageManager.GET_META_DATA) == 0) { 5650 return i.info; 5651 } 5652 InstrumentationInfo ii = new InstrumentationInfo(i.info); 5653 ii.metaData = i.metaData; 5654 return ii; 5655 } 5656 5657 public static class IntentInfo extends IntentFilter { 5658 public boolean hasDefault; 5659 public int labelRes; 5660 public CharSequence nonLocalizedLabel; 5661 public int icon; 5662 public int logo; 5663 public int banner; 5664 public int preferred; 5665 } 5666 5667 public final static class ActivityIntentInfo extends IntentInfo { 5668 public final Activity activity; 5669 5670 public ActivityIntentInfo(Activity _activity) { 5671 activity = _activity; 5672 } 5673 5674 public String toString() { 5675 StringBuilder sb = new StringBuilder(128); 5676 sb.append("ActivityIntentInfo{"); 5677 sb.append(Integer.toHexString(System.identityHashCode(this))); 5678 sb.append(' '); 5679 activity.appendComponentShortName(sb); 5680 sb.append('}'); 5681 return sb.toString(); 5682 } 5683 } 5684 5685 public final static class ServiceIntentInfo extends IntentInfo { 5686 public final Service service; 5687 5688 public ServiceIntentInfo(Service _service) { 5689 service = _service; 5690 } 5691 5692 public String toString() { 5693 StringBuilder sb = new StringBuilder(128); 5694 sb.append("ServiceIntentInfo{"); 5695 sb.append(Integer.toHexString(System.identityHashCode(this))); 5696 sb.append(' '); 5697 service.appendComponentShortName(sb); 5698 sb.append('}'); 5699 return sb.toString(); 5700 } 5701 } 5702 5703 public static final class ProviderIntentInfo extends IntentInfo { 5704 public final Provider provider; 5705 5706 public ProviderIntentInfo(Provider provider) { 5707 this.provider = provider; 5708 } 5709 5710 public String toString() { 5711 StringBuilder sb = new StringBuilder(128); 5712 sb.append("ProviderIntentInfo{"); 5713 sb.append(Integer.toHexString(System.identityHashCode(this))); 5714 sb.append(' '); 5715 provider.appendComponentShortName(sb); 5716 sb.append('}'); 5717 return sb.toString(); 5718 } 5719 } 5720 5721 /** 5722 * @hide 5723 */ 5724 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { 5725 sCompatibilityModeEnabled = compatibilityModeEnabled; 5726 } 5727 5728 private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>(); 5729 5730 public static long readFullyIgnoringContents(InputStream in) throws IOException { 5731 byte[] buffer = sBuffer.getAndSet(null); 5732 if (buffer == null) { 5733 buffer = new byte[4096]; 5734 } 5735 5736 int n = 0; 5737 int count = 0; 5738 while ((n = in.read(buffer, 0, buffer.length)) != -1) { 5739 count += n; 5740 } 5741 5742 sBuffer.set(buffer); 5743 return count; 5744 } 5745 5746 public static void closeQuietly(StrictJarFile jarFile) { 5747 if (jarFile != null) { 5748 try { 5749 jarFile.close(); 5750 } catch (Exception ignored) { 5751 } 5752 } 5753 } 5754 5755 public static class PackageParserException extends Exception { 5756 public final int error; 5757 5758 public PackageParserException(int error, String detailMessage) { 5759 super(detailMessage); 5760 this.error = error; 5761 } 5762 5763 public PackageParserException(int error, String detailMessage, Throwable throwable) { 5764 super(detailMessage, throwable); 5765 this.error = error; 5766 } 5767 } 5768 } 5769