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