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