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