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