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