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