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