PackageParser.java revision 589a1bc0b00e570db079b4b157f60229ad8ef8f9
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 if (sa.getBoolean( 2309 com.android.internal.R.styleable.AndroidManifestApplication_multiArch, 2310 false)) { 2311 ai.flags |= ApplicationInfo.FLAG_MULTIARCH; 2312 } 2313 2314 String str; 2315 str = sa.getNonConfigurationString( 2316 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0); 2317 ai.permission = (str != null && str.length() > 0) ? str.intern() : null; 2318 2319 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 2320 str = sa.getNonConfigurationString( 2321 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, 2322 Configuration.NATIVE_CONFIG_VERSION); 2323 } else { 2324 // Some older apps have been seen to use a resource reference 2325 // here that on older builds was ignored (with a warning). We 2326 // need to continue to do this for them so they don't break. 2327 str = sa.getNonResourceString( 2328 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity); 2329 } 2330 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName, 2331 str, outError); 2332 2333 if (outError[0] == null) { 2334 CharSequence pname; 2335 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 2336 pname = sa.getNonConfigurationString( 2337 com.android.internal.R.styleable.AndroidManifestApplication_process, 2338 Configuration.NATIVE_CONFIG_VERSION); 2339 } else { 2340 // Some older apps have been seen to use a resource reference 2341 // here that on older builds was ignored (with a warning). We 2342 // need to continue to do this for them so they don't break. 2343 pname = sa.getNonResourceString( 2344 com.android.internal.R.styleable.AndroidManifestApplication_process); 2345 } 2346 ai.processName = buildProcessName(ai.packageName, null, pname, 2347 flags, mSeparateProcesses, outError); 2348 2349 ai.enabled = sa.getBoolean( 2350 com.android.internal.R.styleable.AndroidManifestApplication_enabled, true); 2351 2352 if (sa.getBoolean( 2353 com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) { 2354 ai.flags |= ApplicationInfo.FLAG_IS_GAME; 2355 } 2356 2357 if (false) { 2358 if (sa.getBoolean( 2359 com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState, 2360 false)) { 2361 ai.flags |= ApplicationInfo.FLAG_CANT_SAVE_STATE; 2362 2363 // A heavy-weight application can not be in a custom process. 2364 // We can do direct compare because we intern all strings. 2365 if (ai.processName != null && ai.processName != ai.packageName) { 2366 outError[0] = "cantSaveState applications can not use custom processes"; 2367 } 2368 } 2369 } 2370 } 2371 2372 ai.uiOptions = sa.getInt( 2373 com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0); 2374 2375 sa.recycle(); 2376 2377 if (outError[0] != null) { 2378 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2379 return false; 2380 } 2381 2382 final int innerDepth = parser.getDepth(); 2383 int type; 2384 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 2385 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 2386 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2387 continue; 2388 } 2389 2390 String tagName = parser.getName(); 2391 if (tagName.equals("activity")) { 2392 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false, 2393 hardwareAccelerated); 2394 if (a == null) { 2395 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2396 return false; 2397 } 2398 2399 owner.activities.add(a); 2400 2401 } else if (tagName.equals("receiver")) { 2402 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false); 2403 if (a == null) { 2404 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2405 return false; 2406 } 2407 2408 owner.receivers.add(a); 2409 2410 } else if (tagName.equals("service")) { 2411 Service s = parseService(owner, res, parser, attrs, flags, outError); 2412 if (s == null) { 2413 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2414 return false; 2415 } 2416 2417 owner.services.add(s); 2418 2419 } else if (tagName.equals("provider")) { 2420 Provider p = parseProvider(owner, res, parser, attrs, flags, outError); 2421 if (p == null) { 2422 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2423 return false; 2424 } 2425 2426 owner.providers.add(p); 2427 2428 } else if (tagName.equals("activity-alias")) { 2429 Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError); 2430 if (a == null) { 2431 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2432 return false; 2433 } 2434 2435 owner.activities.add(a); 2436 2437 } else if (parser.getName().equals("meta-data")) { 2438 // note: application meta-data is stored off to the side, so it can 2439 // remain null in the primary copy (we like to avoid extra copies because 2440 // it can be large) 2441 if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData, 2442 outError)) == null) { 2443 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2444 return false; 2445 } 2446 2447 } else if (tagName.equals("library")) { 2448 sa = res.obtainAttributes(attrs, 2449 com.android.internal.R.styleable.AndroidManifestLibrary); 2450 2451 // Note: don't allow this value to be a reference to a resource 2452 // that may change. 2453 String lname = sa.getNonResourceString( 2454 com.android.internal.R.styleable.AndroidManifestLibrary_name); 2455 2456 sa.recycle(); 2457 2458 if (lname != null) { 2459 if (owner.libraryNames == null) { 2460 owner.libraryNames = new ArrayList<String>(); 2461 } 2462 if (!owner.libraryNames.contains(lname)) { 2463 owner.libraryNames.add(lname.intern()); 2464 } 2465 } 2466 2467 XmlUtils.skipCurrentTag(parser); 2468 2469 } else if (tagName.equals("uses-library")) { 2470 sa = res.obtainAttributes(attrs, 2471 com.android.internal.R.styleable.AndroidManifestUsesLibrary); 2472 2473 // Note: don't allow this value to be a reference to a resource 2474 // that may change. 2475 String lname = sa.getNonResourceString( 2476 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 2477 boolean req = sa.getBoolean( 2478 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, 2479 true); 2480 2481 sa.recycle(); 2482 2483 if (lname != null) { 2484 if (req) { 2485 if (owner.usesLibraries == null) { 2486 owner.usesLibraries = new ArrayList<String>(); 2487 } 2488 if (!owner.usesLibraries.contains(lname)) { 2489 owner.usesLibraries.add(lname.intern()); 2490 } 2491 } else { 2492 if (owner.usesOptionalLibraries == null) { 2493 owner.usesOptionalLibraries = new ArrayList<String>(); 2494 } 2495 if (!owner.usesOptionalLibraries.contains(lname)) { 2496 owner.usesOptionalLibraries.add(lname.intern()); 2497 } 2498 } 2499 } 2500 2501 XmlUtils.skipCurrentTag(parser); 2502 2503 } else if (tagName.equals("uses-package")) { 2504 // Dependencies for app installers; we don't currently try to 2505 // enforce this. 2506 XmlUtils.skipCurrentTag(parser); 2507 2508 } else { 2509 if (!RIGID_PARSER) { 2510 Slog.w(TAG, "Unknown element under <application>: " + tagName 2511 + " at " + mArchiveSourcePath + " " 2512 + parser.getPositionDescription()); 2513 XmlUtils.skipCurrentTag(parser); 2514 continue; 2515 } else { 2516 outError[0] = "Bad element under <application>: " + tagName; 2517 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2518 return false; 2519 } 2520 } 2521 } 2522 2523 return true; 2524 } 2525 2526 private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo, 2527 String[] outError, String tag, TypedArray sa, 2528 int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) { 2529 String name = sa.getNonConfigurationString(nameRes, 0); 2530 if (name == null) { 2531 outError[0] = tag + " does not specify android:name"; 2532 return false; 2533 } 2534 2535 outInfo.name 2536 = buildClassName(owner.applicationInfo.packageName, name, outError); 2537 if (outInfo.name == null) { 2538 return false; 2539 } 2540 2541 int iconVal = sa.getResourceId(iconRes, 0); 2542 if (iconVal != 0) { 2543 outInfo.icon = iconVal; 2544 outInfo.nonLocalizedLabel = null; 2545 } 2546 2547 int logoVal = sa.getResourceId(logoRes, 0); 2548 if (logoVal != 0) { 2549 outInfo.logo = logoVal; 2550 } 2551 2552 int bannerVal = sa.getResourceId(bannerRes, 0); 2553 if (bannerVal != 0) { 2554 outInfo.banner = bannerVal; 2555 } 2556 2557 TypedValue v = sa.peekValue(labelRes); 2558 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 2559 outInfo.nonLocalizedLabel = v.coerceToString(); 2560 } 2561 2562 outInfo.packageName = owner.packageName; 2563 2564 return true; 2565 } 2566 2567 private Activity parseActivity(Package owner, Resources res, 2568 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError, 2569 boolean receiver, boolean hardwareAccelerated) 2570 throws XmlPullParserException, IOException { 2571 TypedArray sa = res.obtainAttributes(attrs, 2572 com.android.internal.R.styleable.AndroidManifestActivity); 2573 2574 if (mParseActivityArgs == null) { 2575 mParseActivityArgs = new ParseComponentArgs(owner, outError, 2576 com.android.internal.R.styleable.AndroidManifestActivity_name, 2577 com.android.internal.R.styleable.AndroidManifestActivity_label, 2578 com.android.internal.R.styleable.AndroidManifestActivity_icon, 2579 com.android.internal.R.styleable.AndroidManifestActivity_logo, 2580 com.android.internal.R.styleable.AndroidManifestActivity_banner, 2581 mSeparateProcesses, 2582 com.android.internal.R.styleable.AndroidManifestActivity_process, 2583 com.android.internal.R.styleable.AndroidManifestActivity_description, 2584 com.android.internal.R.styleable.AndroidManifestActivity_enabled); 2585 } 2586 2587 mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>"; 2588 mParseActivityArgs.sa = sa; 2589 mParseActivityArgs.flags = flags; 2590 2591 Activity a = new Activity(mParseActivityArgs, new ActivityInfo()); 2592 if (outError[0] != null) { 2593 sa.recycle(); 2594 return null; 2595 } 2596 2597 boolean setExported = sa.hasValue( 2598 com.android.internal.R.styleable.AndroidManifestActivity_exported); 2599 if (setExported) { 2600 a.info.exported = sa.getBoolean( 2601 com.android.internal.R.styleable.AndroidManifestActivity_exported, false); 2602 } 2603 2604 a.info.theme = sa.getResourceId( 2605 com.android.internal.R.styleable.AndroidManifestActivity_theme, 0); 2606 2607 a.info.uiOptions = sa.getInt( 2608 com.android.internal.R.styleable.AndroidManifestActivity_uiOptions, 2609 a.info.applicationInfo.uiOptions); 2610 2611 String parentName = sa.getNonConfigurationString( 2612 com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName, 2613 Configuration.NATIVE_CONFIG_VERSION); 2614 if (parentName != null) { 2615 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 2616 if (outError[0] == null) { 2617 a.info.parentActivityName = parentClassName; 2618 } else { 2619 Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " + 2620 parentName); 2621 outError[0] = null; 2622 } 2623 } 2624 2625 String str; 2626 str = sa.getNonConfigurationString( 2627 com.android.internal.R.styleable.AndroidManifestActivity_permission, 0); 2628 if (str == null) { 2629 a.info.permission = owner.applicationInfo.permission; 2630 } else { 2631 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 2632 } 2633 2634 str = sa.getNonConfigurationString( 2635 com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity, 2636 Configuration.NATIVE_CONFIG_VERSION); 2637 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName, 2638 owner.applicationInfo.taskAffinity, str, outError); 2639 2640 a.info.flags = 0; 2641 if (sa.getBoolean( 2642 com.android.internal.R.styleable.AndroidManifestActivity_multiprocess, 2643 false)) { 2644 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS; 2645 } 2646 2647 if (sa.getBoolean( 2648 com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch, 2649 false)) { 2650 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; 2651 } 2652 2653 if (sa.getBoolean( 2654 com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch, 2655 false)) { 2656 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; 2657 } 2658 2659 if (sa.getBoolean( 2660 com.android.internal.R.styleable.AndroidManifestActivity_noHistory, 2661 false)) { 2662 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY; 2663 } 2664 2665 if (sa.getBoolean( 2666 com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState, 2667 false)) { 2668 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; 2669 } 2670 2671 if (sa.getBoolean( 2672 com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded, 2673 false)) { 2674 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; 2675 } 2676 2677 if (sa.getBoolean( 2678 com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents, 2679 false)) { 2680 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; 2681 } 2682 2683 if (sa.getBoolean( 2684 com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting, 2685 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) { 2686 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; 2687 } 2688 2689 if (sa.getBoolean( 2690 com.android.internal.R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, 2691 false)) { 2692 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; 2693 } 2694 2695 if (sa.getBoolean( 2696 com.android.internal.R.styleable.AndroidManifestActivity_showOnLockScreen, 2697 false)) { 2698 a.info.flags |= ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN; 2699 } 2700 2701 if (sa.getBoolean( 2702 com.android.internal.R.styleable.AndroidManifestActivity_immersive, 2703 false)) { 2704 a.info.flags |= ActivityInfo.FLAG_IMMERSIVE; 2705 } 2706 2707 if (!receiver) { 2708 if (sa.getBoolean( 2709 com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated, 2710 hardwareAccelerated)) { 2711 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; 2712 } 2713 2714 a.info.launchMode = sa.getInt( 2715 com.android.internal.R.styleable.AndroidManifestActivity_launchMode, 2716 ActivityInfo.LAUNCH_MULTIPLE); 2717 a.info.documentLaunchMode = sa.getInt( 2718 com.android.internal.R.styleable.AndroidManifestActivity_documentLaunchMode, 2719 ActivityInfo.DOCUMENT_LAUNCH_NONE); 2720 a.info.maxRecents = sa.getInt( 2721 com.android.internal.R.styleable.AndroidManifestActivity_maxRecents, 2722 15); 2723 a.info.screenOrientation = sa.getInt( 2724 com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation, 2725 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 2726 a.info.configChanges = sa.getInt( 2727 com.android.internal.R.styleable.AndroidManifestActivity_configChanges, 2728 0); 2729 a.info.softInputMode = sa.getInt( 2730 com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode, 2731 0); 2732 2733 a.info.persistableMode = sa.getInteger( 2734 com.android.internal.R.styleable.AndroidManifestActivity_persistableMode, 2735 ActivityInfo.PERSIST_ROOT_ONLY); 2736 2737 if (sa.getBoolean( 2738 com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded, 2739 false)) { 2740 a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED; 2741 } 2742 2743 if (sa.getBoolean( 2744 com.android.internal.R.styleable.AndroidManifestActivity_autoRemoveFromRecents, 2745 false)) { 2746 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS; 2747 } 2748 2749 if (sa.getBoolean( 2750 com.android.internal.R.styleable.AndroidManifestActivity_relinquishTaskIdentity, 2751 false)) { 2752 a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; 2753 } 2754 } else { 2755 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; 2756 a.info.configChanges = 0; 2757 } 2758 2759 if (receiver) { 2760 if (sa.getBoolean( 2761 com.android.internal.R.styleable.AndroidManifestActivity_singleUser, 2762 false)) { 2763 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER; 2764 if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 2765 Slog.w(TAG, "Activity exported request ignored due to singleUser: " 2766 + a.className + " at " + mArchiveSourcePath + " " 2767 + parser.getPositionDescription()); 2768 a.info.exported = false; 2769 setExported = true; 2770 } 2771 } 2772 if (sa.getBoolean( 2773 com.android.internal.R.styleable.AndroidManifestActivity_primaryUserOnly, 2774 false)) { 2775 a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY; 2776 } 2777 } 2778 2779 sa.recycle(); 2780 2781 if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { 2782 // A heavy-weight application can not have receives in its main process 2783 // We can do direct compare because we intern all strings. 2784 if (a.info.processName == owner.packageName) { 2785 outError[0] = "Heavy-weight applications can not have receivers in main process"; 2786 } 2787 } 2788 2789 if (outError[0] != null) { 2790 return null; 2791 } 2792 2793 int outerDepth = parser.getDepth(); 2794 int type; 2795 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2796 && (type != XmlPullParser.END_TAG 2797 || parser.getDepth() > outerDepth)) { 2798 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2799 continue; 2800 } 2801 2802 if (parser.getName().equals("intent-filter")) { 2803 ActivityIntentInfo intent = new ActivityIntentInfo(a); 2804 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 2805 return null; 2806 } 2807 if (intent.countActions() == 0) { 2808 Slog.w(TAG, "No actions in intent filter at " 2809 + mArchiveSourcePath + " " 2810 + parser.getPositionDescription()); 2811 } else { 2812 a.intents.add(intent); 2813 } 2814 } else if (!receiver && parser.getName().equals("preferred")) { 2815 ActivityIntentInfo intent = new ActivityIntentInfo(a); 2816 if (!parseIntent(res, parser, attrs, false, intent, outError)) { 2817 return null; 2818 } 2819 if (intent.countActions() == 0) { 2820 Slog.w(TAG, "No actions in preferred at " 2821 + mArchiveSourcePath + " " 2822 + parser.getPositionDescription()); 2823 } else { 2824 if (owner.preferredActivityFilters == null) { 2825 owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>(); 2826 } 2827 owner.preferredActivityFilters.add(intent); 2828 } 2829 } else if (parser.getName().equals("meta-data")) { 2830 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData, 2831 outError)) == null) { 2832 return null; 2833 } 2834 } else { 2835 if (!RIGID_PARSER) { 2836 Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 2837 if (receiver) { 2838 Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName() 2839 + " at " + mArchiveSourcePath + " " 2840 + parser.getPositionDescription()); 2841 } else { 2842 Slog.w(TAG, "Unknown element under <activity>: " + parser.getName() 2843 + " at " + mArchiveSourcePath + " " 2844 + parser.getPositionDescription()); 2845 } 2846 XmlUtils.skipCurrentTag(parser); 2847 continue; 2848 } else { 2849 if (receiver) { 2850 outError[0] = "Bad element under <receiver>: " + parser.getName(); 2851 } else { 2852 outError[0] = "Bad element under <activity>: " + parser.getName(); 2853 } 2854 return null; 2855 } 2856 } 2857 } 2858 2859 if (!setExported) { 2860 a.info.exported = a.intents.size() > 0; 2861 } 2862 2863 return a; 2864 } 2865 2866 private Activity parseActivityAlias(Package owner, Resources res, 2867 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 2868 throws XmlPullParserException, IOException { 2869 TypedArray sa = res.obtainAttributes(attrs, 2870 com.android.internal.R.styleable.AndroidManifestActivityAlias); 2871 2872 String targetActivity = sa.getNonConfigurationString( 2873 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity, 2874 Configuration.NATIVE_CONFIG_VERSION); 2875 if (targetActivity == null) { 2876 outError[0] = "<activity-alias> does not specify android:targetActivity"; 2877 sa.recycle(); 2878 return null; 2879 } 2880 2881 targetActivity = buildClassName(owner.applicationInfo.packageName, 2882 targetActivity, outError); 2883 if (targetActivity == null) { 2884 sa.recycle(); 2885 return null; 2886 } 2887 2888 if (mParseActivityAliasArgs == null) { 2889 mParseActivityAliasArgs = new ParseComponentArgs(owner, outError, 2890 com.android.internal.R.styleable.AndroidManifestActivityAlias_name, 2891 com.android.internal.R.styleable.AndroidManifestActivityAlias_label, 2892 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, 2893 com.android.internal.R.styleable.AndroidManifestActivityAlias_logo, 2894 com.android.internal.R.styleable.AndroidManifestActivityAlias_banner, 2895 mSeparateProcesses, 2896 0, 2897 com.android.internal.R.styleable.AndroidManifestActivityAlias_description, 2898 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled); 2899 mParseActivityAliasArgs.tag = "<activity-alias>"; 2900 } 2901 2902 mParseActivityAliasArgs.sa = sa; 2903 mParseActivityAliasArgs.flags = flags; 2904 2905 Activity target = null; 2906 2907 final int NA = owner.activities.size(); 2908 for (int i=0; i<NA; i++) { 2909 Activity t = owner.activities.get(i); 2910 if (targetActivity.equals(t.info.name)) { 2911 target = t; 2912 break; 2913 } 2914 } 2915 2916 if (target == null) { 2917 outError[0] = "<activity-alias> target activity " + targetActivity 2918 + " not found in manifest"; 2919 sa.recycle(); 2920 return null; 2921 } 2922 2923 ActivityInfo info = new ActivityInfo(); 2924 info.targetActivity = targetActivity; 2925 info.configChanges = target.info.configChanges; 2926 info.flags = target.info.flags; 2927 info.icon = target.info.icon; 2928 info.logo = target.info.logo; 2929 info.banner = target.info.banner; 2930 info.labelRes = target.info.labelRes; 2931 info.nonLocalizedLabel = target.info.nonLocalizedLabel; 2932 info.launchMode = target.info.launchMode; 2933 info.processName = target.info.processName; 2934 if (info.descriptionRes == 0) { 2935 info.descriptionRes = target.info.descriptionRes; 2936 } 2937 info.screenOrientation = target.info.screenOrientation; 2938 info.taskAffinity = target.info.taskAffinity; 2939 info.theme = target.info.theme; 2940 info.softInputMode = target.info.softInputMode; 2941 info.uiOptions = target.info.uiOptions; 2942 info.parentActivityName = target.info.parentActivityName; 2943 2944 Activity a = new Activity(mParseActivityAliasArgs, info); 2945 if (outError[0] != null) { 2946 sa.recycle(); 2947 return null; 2948 } 2949 2950 final boolean setExported = sa.hasValue( 2951 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported); 2952 if (setExported) { 2953 a.info.exported = sa.getBoolean( 2954 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false); 2955 } 2956 2957 String str; 2958 str = sa.getNonConfigurationString( 2959 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0); 2960 if (str != null) { 2961 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 2962 } 2963 2964 String parentName = sa.getNonConfigurationString( 2965 com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName, 2966 Configuration.NATIVE_CONFIG_VERSION); 2967 if (parentName != null) { 2968 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 2969 if (outError[0] == null) { 2970 a.info.parentActivityName = parentClassName; 2971 } else { 2972 Log.e(TAG, "Activity alias " + a.info.name + 2973 " specified invalid parentActivityName " + parentName); 2974 outError[0] = null; 2975 } 2976 } 2977 2978 sa.recycle(); 2979 2980 if (outError[0] != null) { 2981 return null; 2982 } 2983 2984 int outerDepth = parser.getDepth(); 2985 int type; 2986 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2987 && (type != XmlPullParser.END_TAG 2988 || parser.getDepth() > outerDepth)) { 2989 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2990 continue; 2991 } 2992 2993 if (parser.getName().equals("intent-filter")) { 2994 ActivityIntentInfo intent = new ActivityIntentInfo(a); 2995 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 2996 return null; 2997 } 2998 if (intent.countActions() == 0) { 2999 Slog.w(TAG, "No actions in intent filter at " 3000 + mArchiveSourcePath + " " 3001 + parser.getPositionDescription()); 3002 } else { 3003 a.intents.add(intent); 3004 } 3005 } else if (parser.getName().equals("meta-data")) { 3006 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData, 3007 outError)) == null) { 3008 return null; 3009 } 3010 } else { 3011 if (!RIGID_PARSER) { 3012 Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName() 3013 + " at " + mArchiveSourcePath + " " 3014 + parser.getPositionDescription()); 3015 XmlUtils.skipCurrentTag(parser); 3016 continue; 3017 } else { 3018 outError[0] = "Bad element under <activity-alias>: " + parser.getName(); 3019 return null; 3020 } 3021 } 3022 } 3023 3024 if (!setExported) { 3025 a.info.exported = a.intents.size() > 0; 3026 } 3027 3028 return a; 3029 } 3030 3031 private Provider parseProvider(Package owner, Resources res, 3032 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 3033 throws XmlPullParserException, IOException { 3034 TypedArray sa = res.obtainAttributes(attrs, 3035 com.android.internal.R.styleable.AndroidManifestProvider); 3036 3037 if (mParseProviderArgs == null) { 3038 mParseProviderArgs = new ParseComponentArgs(owner, outError, 3039 com.android.internal.R.styleable.AndroidManifestProvider_name, 3040 com.android.internal.R.styleable.AndroidManifestProvider_label, 3041 com.android.internal.R.styleable.AndroidManifestProvider_icon, 3042 com.android.internal.R.styleable.AndroidManifestProvider_logo, 3043 com.android.internal.R.styleable.AndroidManifestProvider_banner, 3044 mSeparateProcesses, 3045 com.android.internal.R.styleable.AndroidManifestProvider_process, 3046 com.android.internal.R.styleable.AndroidManifestProvider_description, 3047 com.android.internal.R.styleable.AndroidManifestProvider_enabled); 3048 mParseProviderArgs.tag = "<provider>"; 3049 } 3050 3051 mParseProviderArgs.sa = sa; 3052 mParseProviderArgs.flags = flags; 3053 3054 Provider p = new Provider(mParseProviderArgs, new ProviderInfo()); 3055 if (outError[0] != null) { 3056 sa.recycle(); 3057 return null; 3058 } 3059 3060 boolean providerExportedDefault = false; 3061 3062 if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 3063 // For compatibility, applications targeting API level 16 or lower 3064 // should have their content providers exported by default, unless they 3065 // specify otherwise. 3066 providerExportedDefault = true; 3067 } 3068 3069 p.info.exported = sa.getBoolean( 3070 com.android.internal.R.styleable.AndroidManifestProvider_exported, 3071 providerExportedDefault); 3072 3073 String cpname = sa.getNonConfigurationString( 3074 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0); 3075 3076 p.info.isSyncable = sa.getBoolean( 3077 com.android.internal.R.styleable.AndroidManifestProvider_syncable, 3078 false); 3079 3080 String permission = sa.getNonConfigurationString( 3081 com.android.internal.R.styleable.AndroidManifestProvider_permission, 0); 3082 String str = sa.getNonConfigurationString( 3083 com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0); 3084 if (str == null) { 3085 str = permission; 3086 } 3087 if (str == null) { 3088 p.info.readPermission = owner.applicationInfo.permission; 3089 } else { 3090 p.info.readPermission = 3091 str.length() > 0 ? str.toString().intern() : null; 3092 } 3093 str = sa.getNonConfigurationString( 3094 com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0); 3095 if (str == null) { 3096 str = permission; 3097 } 3098 if (str == null) { 3099 p.info.writePermission = owner.applicationInfo.permission; 3100 } else { 3101 p.info.writePermission = 3102 str.length() > 0 ? str.toString().intern() : null; 3103 } 3104 3105 p.info.grantUriPermissions = sa.getBoolean( 3106 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions, 3107 false); 3108 3109 p.info.multiprocess = sa.getBoolean( 3110 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess, 3111 false); 3112 3113 p.info.initOrder = sa.getInt( 3114 com.android.internal.R.styleable.AndroidManifestProvider_initOrder, 3115 0); 3116 3117 p.info.flags = 0; 3118 3119 if (sa.getBoolean( 3120 com.android.internal.R.styleable.AndroidManifestProvider_singleUser, 3121 false)) { 3122 p.info.flags |= ProviderInfo.FLAG_SINGLE_USER; 3123 if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 3124 Slog.w(TAG, "Provider exported request ignored due to singleUser: " 3125 + p.className + " at " + mArchiveSourcePath + " " 3126 + parser.getPositionDescription()); 3127 p.info.exported = false; 3128 } 3129 } 3130 3131 sa.recycle(); 3132 3133 if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { 3134 // A heavy-weight application can not have providers in its main process 3135 // We can do direct compare because we intern all strings. 3136 if (p.info.processName == owner.packageName) { 3137 outError[0] = "Heavy-weight applications can not have providers in main process"; 3138 return null; 3139 } 3140 } 3141 3142 if (cpname == null) { 3143 outError[0] = "<provider> does not include authorities attribute"; 3144 return null; 3145 } 3146 p.info.authority = cpname.intern(); 3147 3148 if (!parseProviderTags(res, parser, attrs, p, outError)) { 3149 return null; 3150 } 3151 3152 return p; 3153 } 3154 3155 private boolean parseProviderTags(Resources res, 3156 XmlPullParser parser, AttributeSet attrs, 3157 Provider outInfo, String[] outError) 3158 throws XmlPullParserException, IOException { 3159 int outerDepth = parser.getDepth(); 3160 int type; 3161 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3162 && (type != XmlPullParser.END_TAG 3163 || parser.getDepth() > outerDepth)) { 3164 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3165 continue; 3166 } 3167 3168 if (parser.getName().equals("intent-filter")) { 3169 ProviderIntentInfo intent = new ProviderIntentInfo(outInfo); 3170 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 3171 return false; 3172 } 3173 outInfo.intents.add(intent); 3174 3175 } else if (parser.getName().equals("meta-data")) { 3176 if ((outInfo.metaData=parseMetaData(res, parser, attrs, 3177 outInfo.metaData, outError)) == null) { 3178 return false; 3179 } 3180 3181 } else if (parser.getName().equals("grant-uri-permission")) { 3182 TypedArray sa = res.obtainAttributes(attrs, 3183 com.android.internal.R.styleable.AndroidManifestGrantUriPermission); 3184 3185 PatternMatcher pa = null; 3186 3187 String str = sa.getNonConfigurationString( 3188 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0); 3189 if (str != null) { 3190 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); 3191 } 3192 3193 str = sa.getNonConfigurationString( 3194 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); 3195 if (str != null) { 3196 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); 3197 } 3198 3199 str = sa.getNonConfigurationString( 3200 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); 3201 if (str != null) { 3202 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 3203 } 3204 3205 sa.recycle(); 3206 3207 if (pa != null) { 3208 if (outInfo.info.uriPermissionPatterns == null) { 3209 outInfo.info.uriPermissionPatterns = new PatternMatcher[1]; 3210 outInfo.info.uriPermissionPatterns[0] = pa; 3211 } else { 3212 final int N = outInfo.info.uriPermissionPatterns.length; 3213 PatternMatcher[] newp = new PatternMatcher[N+1]; 3214 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N); 3215 newp[N] = pa; 3216 outInfo.info.uriPermissionPatterns = newp; 3217 } 3218 outInfo.info.grantUriPermissions = true; 3219 } else { 3220 if (!RIGID_PARSER) { 3221 Slog.w(TAG, "Unknown element under <path-permission>: " 3222 + parser.getName() + " at " + mArchiveSourcePath + " " 3223 + parser.getPositionDescription()); 3224 XmlUtils.skipCurrentTag(parser); 3225 continue; 3226 } else { 3227 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 3228 return false; 3229 } 3230 } 3231 XmlUtils.skipCurrentTag(parser); 3232 3233 } else if (parser.getName().equals("path-permission")) { 3234 TypedArray sa = res.obtainAttributes(attrs, 3235 com.android.internal.R.styleable.AndroidManifestPathPermission); 3236 3237 PathPermission pa = null; 3238 3239 String permission = sa.getNonConfigurationString( 3240 com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0); 3241 String readPermission = sa.getNonConfigurationString( 3242 com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0); 3243 if (readPermission == null) { 3244 readPermission = permission; 3245 } 3246 String writePermission = sa.getNonConfigurationString( 3247 com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0); 3248 if (writePermission == null) { 3249 writePermission = permission; 3250 } 3251 3252 boolean havePerm = false; 3253 if (readPermission != null) { 3254 readPermission = readPermission.intern(); 3255 havePerm = true; 3256 } 3257 if (writePermission != null) { 3258 writePermission = writePermission.intern(); 3259 havePerm = true; 3260 } 3261 3262 if (!havePerm) { 3263 if (!RIGID_PARSER) { 3264 Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: " 3265 + parser.getName() + " at " + mArchiveSourcePath + " " 3266 + parser.getPositionDescription()); 3267 XmlUtils.skipCurrentTag(parser); 3268 continue; 3269 } else { 3270 outError[0] = "No readPermission or writePermssion for <path-permission>"; 3271 return false; 3272 } 3273 } 3274 3275 String path = sa.getNonConfigurationString( 3276 com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0); 3277 if (path != null) { 3278 pa = new PathPermission(path, 3279 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission); 3280 } 3281 3282 path = sa.getNonConfigurationString( 3283 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0); 3284 if (path != null) { 3285 pa = new PathPermission(path, 3286 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission); 3287 } 3288 3289 path = sa.getNonConfigurationString( 3290 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0); 3291 if (path != null) { 3292 pa = new PathPermission(path, 3293 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission); 3294 } 3295 3296 sa.recycle(); 3297 3298 if (pa != null) { 3299 if (outInfo.info.pathPermissions == null) { 3300 outInfo.info.pathPermissions = new PathPermission[1]; 3301 outInfo.info.pathPermissions[0] = pa; 3302 } else { 3303 final int N = outInfo.info.pathPermissions.length; 3304 PathPermission[] newp = new PathPermission[N+1]; 3305 System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N); 3306 newp[N] = pa; 3307 outInfo.info.pathPermissions = newp; 3308 } 3309 } else { 3310 if (!RIGID_PARSER) { 3311 Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: " 3312 + parser.getName() + " at " + mArchiveSourcePath + " " 3313 + parser.getPositionDescription()); 3314 XmlUtils.skipCurrentTag(parser); 3315 continue; 3316 } 3317 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 3318 return false; 3319 } 3320 XmlUtils.skipCurrentTag(parser); 3321 3322 } else { 3323 if (!RIGID_PARSER) { 3324 Slog.w(TAG, "Unknown element under <provider>: " 3325 + parser.getName() + " at " + mArchiveSourcePath + " " 3326 + parser.getPositionDescription()); 3327 XmlUtils.skipCurrentTag(parser); 3328 continue; 3329 } else { 3330 outError[0] = "Bad element under <provider>: " + parser.getName(); 3331 return false; 3332 } 3333 } 3334 } 3335 return true; 3336 } 3337 3338 private Service parseService(Package owner, Resources res, 3339 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 3340 throws XmlPullParserException, IOException { 3341 TypedArray sa = res.obtainAttributes(attrs, 3342 com.android.internal.R.styleable.AndroidManifestService); 3343 3344 if (mParseServiceArgs == null) { 3345 mParseServiceArgs = new ParseComponentArgs(owner, outError, 3346 com.android.internal.R.styleable.AndroidManifestService_name, 3347 com.android.internal.R.styleable.AndroidManifestService_label, 3348 com.android.internal.R.styleable.AndroidManifestService_icon, 3349 com.android.internal.R.styleable.AndroidManifestService_logo, 3350 com.android.internal.R.styleable.AndroidManifestService_banner, 3351 mSeparateProcesses, 3352 com.android.internal.R.styleable.AndroidManifestService_process, 3353 com.android.internal.R.styleable.AndroidManifestService_description, 3354 com.android.internal.R.styleable.AndroidManifestService_enabled); 3355 mParseServiceArgs.tag = "<service>"; 3356 } 3357 3358 mParseServiceArgs.sa = sa; 3359 mParseServiceArgs.flags = flags; 3360 3361 Service s = new Service(mParseServiceArgs, new ServiceInfo()); 3362 if (outError[0] != null) { 3363 sa.recycle(); 3364 return null; 3365 } 3366 3367 boolean setExported = sa.hasValue( 3368 com.android.internal.R.styleable.AndroidManifestService_exported); 3369 if (setExported) { 3370 s.info.exported = sa.getBoolean( 3371 com.android.internal.R.styleable.AndroidManifestService_exported, false); 3372 } 3373 3374 String str = sa.getNonConfigurationString( 3375 com.android.internal.R.styleable.AndroidManifestService_permission, 0); 3376 if (str == null) { 3377 s.info.permission = owner.applicationInfo.permission; 3378 } else { 3379 s.info.permission = str.length() > 0 ? str.toString().intern() : null; 3380 } 3381 3382 s.info.flags = 0; 3383 if (sa.getBoolean( 3384 com.android.internal.R.styleable.AndroidManifestService_stopWithTask, 3385 false)) { 3386 s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK; 3387 } 3388 if (sa.getBoolean( 3389 com.android.internal.R.styleable.AndroidManifestService_isolatedProcess, 3390 false)) { 3391 s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS; 3392 } 3393 if (sa.getBoolean( 3394 com.android.internal.R.styleable.AndroidManifestService_singleUser, 3395 false)) { 3396 s.info.flags |= ServiceInfo.FLAG_SINGLE_USER; 3397 if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 3398 Slog.w(TAG, "Service exported request ignored due to singleUser: " 3399 + s.className + " at " + mArchiveSourcePath + " " 3400 + parser.getPositionDescription()); 3401 s.info.exported = false; 3402 setExported = true; 3403 } 3404 } 3405 3406 sa.recycle(); 3407 3408 if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { 3409 // A heavy-weight application can not have services in its main process 3410 // We can do direct compare because we intern all strings. 3411 if (s.info.processName == owner.packageName) { 3412 outError[0] = "Heavy-weight applications can not have services in main process"; 3413 return null; 3414 } 3415 } 3416 3417 int outerDepth = parser.getDepth(); 3418 int type; 3419 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3420 && (type != XmlPullParser.END_TAG 3421 || parser.getDepth() > outerDepth)) { 3422 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3423 continue; 3424 } 3425 3426 if (parser.getName().equals("intent-filter")) { 3427 ServiceIntentInfo intent = new ServiceIntentInfo(s); 3428 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 3429 return null; 3430 } 3431 3432 s.intents.add(intent); 3433 } else if (parser.getName().equals("meta-data")) { 3434 if ((s.metaData=parseMetaData(res, parser, attrs, s.metaData, 3435 outError)) == null) { 3436 return null; 3437 } 3438 } else { 3439 if (!RIGID_PARSER) { 3440 Slog.w(TAG, "Unknown element under <service>: " 3441 + parser.getName() + " at " + mArchiveSourcePath + " " 3442 + parser.getPositionDescription()); 3443 XmlUtils.skipCurrentTag(parser); 3444 continue; 3445 } else { 3446 outError[0] = "Bad element under <service>: " + parser.getName(); 3447 return null; 3448 } 3449 } 3450 } 3451 3452 if (!setExported) { 3453 s.info.exported = s.intents.size() > 0; 3454 } 3455 3456 return s; 3457 } 3458 3459 private boolean parseAllMetaData(Resources res, 3460 XmlPullParser parser, AttributeSet attrs, String tag, 3461 Component outInfo, String[] outError) 3462 throws XmlPullParserException, IOException { 3463 int outerDepth = parser.getDepth(); 3464 int type; 3465 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3466 && (type != XmlPullParser.END_TAG 3467 || parser.getDepth() > outerDepth)) { 3468 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3469 continue; 3470 } 3471 3472 if (parser.getName().equals("meta-data")) { 3473 if ((outInfo.metaData=parseMetaData(res, parser, attrs, 3474 outInfo.metaData, outError)) == null) { 3475 return false; 3476 } 3477 } else { 3478 if (!RIGID_PARSER) { 3479 Slog.w(TAG, "Unknown element under " + tag + ": " 3480 + parser.getName() + " at " + mArchiveSourcePath + " " 3481 + parser.getPositionDescription()); 3482 XmlUtils.skipCurrentTag(parser); 3483 continue; 3484 } else { 3485 outError[0] = "Bad element under " + tag + ": " + parser.getName(); 3486 return false; 3487 } 3488 } 3489 } 3490 return true; 3491 } 3492 3493 private Bundle parseMetaData(Resources res, 3494 XmlPullParser parser, AttributeSet attrs, 3495 Bundle data, String[] outError) 3496 throws XmlPullParserException, IOException { 3497 3498 TypedArray sa = res.obtainAttributes(attrs, 3499 com.android.internal.R.styleable.AndroidManifestMetaData); 3500 3501 if (data == null) { 3502 data = new Bundle(); 3503 } 3504 3505 String name = sa.getNonConfigurationString( 3506 com.android.internal.R.styleable.AndroidManifestMetaData_name, 0); 3507 if (name == null) { 3508 outError[0] = "<meta-data> requires an android:name attribute"; 3509 sa.recycle(); 3510 return null; 3511 } 3512 3513 name = name.intern(); 3514 3515 TypedValue v = sa.peekValue( 3516 com.android.internal.R.styleable.AndroidManifestMetaData_resource); 3517 if (v != null && v.resourceId != 0) { 3518 //Slog.i(TAG, "Meta data ref " + name + ": " + v); 3519 data.putInt(name, v.resourceId); 3520 } else { 3521 v = sa.peekValue( 3522 com.android.internal.R.styleable.AndroidManifestMetaData_value); 3523 //Slog.i(TAG, "Meta data " + name + ": " + v); 3524 if (v != null) { 3525 if (v.type == TypedValue.TYPE_STRING) { 3526 CharSequence cs = v.coerceToString(); 3527 data.putString(name, cs != null ? cs.toString().intern() : null); 3528 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { 3529 data.putBoolean(name, v.data != 0); 3530 } else if (v.type >= TypedValue.TYPE_FIRST_INT 3531 && v.type <= TypedValue.TYPE_LAST_INT) { 3532 data.putInt(name, v.data); 3533 } else if (v.type == TypedValue.TYPE_FLOAT) { 3534 data.putFloat(name, v.getFloat()); 3535 } else { 3536 if (!RIGID_PARSER) { 3537 Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: " 3538 + parser.getName() + " at " + mArchiveSourcePath + " " 3539 + parser.getPositionDescription()); 3540 } else { 3541 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types"; 3542 data = null; 3543 } 3544 } 3545 } else { 3546 outError[0] = "<meta-data> requires an android:value or android:resource attribute"; 3547 data = null; 3548 } 3549 } 3550 3551 sa.recycle(); 3552 3553 XmlUtils.skipCurrentTag(parser); 3554 3555 return data; 3556 } 3557 3558 private static VerifierInfo parseVerifier(Resources res, XmlPullParser parser, 3559 AttributeSet attrs, int flags) { 3560 final TypedArray sa = res.obtainAttributes(attrs, 3561 com.android.internal.R.styleable.AndroidManifestPackageVerifier); 3562 3563 final String packageName = sa.getNonResourceString( 3564 com.android.internal.R.styleable.AndroidManifestPackageVerifier_name); 3565 3566 final String encodedPublicKey = sa.getNonResourceString( 3567 com.android.internal.R.styleable.AndroidManifestPackageVerifier_publicKey); 3568 3569 sa.recycle(); 3570 3571 if (packageName == null || packageName.length() == 0) { 3572 Slog.i(TAG, "verifier package name was null; skipping"); 3573 return null; 3574 } 3575 3576 final PublicKey publicKey = parsePublicKey(encodedPublicKey); 3577 if (publicKey == null) { 3578 Slog.i(TAG, "Unable to parse verifier public key for " + packageName); 3579 return null; 3580 } 3581 3582 return new VerifierInfo(packageName, publicKey); 3583 } 3584 3585 public static final PublicKey parsePublicKey(final String encodedPublicKey) { 3586 if (encodedPublicKey == null) { 3587 Slog.i(TAG, "Could not parse null public key"); 3588 return null; 3589 } 3590 3591 EncodedKeySpec keySpec; 3592 try { 3593 final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT); 3594 keySpec = new X509EncodedKeySpec(encoded); 3595 } catch (IllegalArgumentException e) { 3596 Slog.i(TAG, "Could not parse verifier public key; invalid Base64"); 3597 return null; 3598 } 3599 3600 /* First try the key as an RSA key. */ 3601 try { 3602 final KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 3603 return keyFactory.generatePublic(keySpec); 3604 } catch (NoSuchAlgorithmException e) { 3605 Log.wtf(TAG, "Could not parse public key because RSA isn't included in build"); 3606 return null; 3607 } catch (InvalidKeySpecException e) { 3608 // Not a RSA public key. 3609 } 3610 3611 /* Now try it as a DSA key. */ 3612 try { 3613 final KeyFactory keyFactory = KeyFactory.getInstance("DSA"); 3614 return keyFactory.generatePublic(keySpec); 3615 } catch (NoSuchAlgorithmException e) { 3616 Log.wtf(TAG, "Could not parse public key because DSA isn't included in build"); 3617 return null; 3618 } catch (InvalidKeySpecException e) { 3619 // Not a DSA public key. 3620 } 3621 3622 return null; 3623 } 3624 3625 private static final String ANDROID_RESOURCES 3626 = "http://schemas.android.com/apk/res/android"; 3627 3628 private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs, 3629 boolean allowGlobs, IntentInfo outInfo, String[] outError) 3630 throws XmlPullParserException, IOException { 3631 3632 TypedArray sa = res.obtainAttributes(attrs, 3633 com.android.internal.R.styleable.AndroidManifestIntentFilter); 3634 3635 int priority = sa.getInt( 3636 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0); 3637 outInfo.setPriority(priority); 3638 3639 TypedValue v = sa.peekValue( 3640 com.android.internal.R.styleable.AndroidManifestIntentFilter_label); 3641 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 3642 outInfo.nonLocalizedLabel = v.coerceToString(); 3643 } 3644 3645 outInfo.icon = sa.getResourceId( 3646 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0); 3647 3648 outInfo.logo = sa.getResourceId( 3649 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0); 3650 3651 outInfo.banner = sa.getResourceId( 3652 com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0); 3653 3654 sa.recycle(); 3655 3656 int outerDepth = parser.getDepth(); 3657 int type; 3658 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 3659 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 3660 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3661 continue; 3662 } 3663 3664 String nodeName = parser.getName(); 3665 if (nodeName.equals("action")) { 3666 String value = attrs.getAttributeValue( 3667 ANDROID_RESOURCES, "name"); 3668 if (value == null || value == "") { 3669 outError[0] = "No value supplied for <android:name>"; 3670 return false; 3671 } 3672 XmlUtils.skipCurrentTag(parser); 3673 3674 outInfo.addAction(value); 3675 } else if (nodeName.equals("category")) { 3676 String value = attrs.getAttributeValue( 3677 ANDROID_RESOURCES, "name"); 3678 if (value == null || value == "") { 3679 outError[0] = "No value supplied for <android:name>"; 3680 return false; 3681 } 3682 XmlUtils.skipCurrentTag(parser); 3683 3684 outInfo.addCategory(value); 3685 3686 } else if (nodeName.equals("data")) { 3687 sa = res.obtainAttributes(attrs, 3688 com.android.internal.R.styleable.AndroidManifestData); 3689 3690 String str = sa.getNonConfigurationString( 3691 com.android.internal.R.styleable.AndroidManifestData_mimeType, 0); 3692 if (str != null) { 3693 try { 3694 outInfo.addDataType(str); 3695 } catch (IntentFilter.MalformedMimeTypeException e) { 3696 outError[0] = e.toString(); 3697 sa.recycle(); 3698 return false; 3699 } 3700 } 3701 3702 str = sa.getNonConfigurationString( 3703 com.android.internal.R.styleable.AndroidManifestData_scheme, 0); 3704 if (str != null) { 3705 outInfo.addDataScheme(str); 3706 } 3707 3708 str = sa.getNonConfigurationString( 3709 com.android.internal.R.styleable.AndroidManifestData_ssp, 0); 3710 if (str != null) { 3711 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL); 3712 } 3713 3714 str = sa.getNonConfigurationString( 3715 com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0); 3716 if (str != null) { 3717 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX); 3718 } 3719 3720 str = sa.getNonConfigurationString( 3721 com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0); 3722 if (str != null) { 3723 if (!allowGlobs) { 3724 outError[0] = "sspPattern not allowed here; ssp must be literal"; 3725 return false; 3726 } 3727 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 3728 } 3729 3730 String host = sa.getNonConfigurationString( 3731 com.android.internal.R.styleable.AndroidManifestData_host, 0); 3732 String port = sa.getNonConfigurationString( 3733 com.android.internal.R.styleable.AndroidManifestData_port, 0); 3734 if (host != null) { 3735 outInfo.addDataAuthority(host, port); 3736 } 3737 3738 str = sa.getNonConfigurationString( 3739 com.android.internal.R.styleable.AndroidManifestData_path, 0); 3740 if (str != null) { 3741 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); 3742 } 3743 3744 str = sa.getNonConfigurationString( 3745 com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0); 3746 if (str != null) { 3747 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); 3748 } 3749 3750 str = sa.getNonConfigurationString( 3751 com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0); 3752 if (str != null) { 3753 if (!allowGlobs) { 3754 outError[0] = "pathPattern not allowed here; path must be literal"; 3755 return false; 3756 } 3757 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 3758 } 3759 3760 sa.recycle(); 3761 XmlUtils.skipCurrentTag(parser); 3762 } else if (!RIGID_PARSER) { 3763 Slog.w(TAG, "Unknown element under <intent-filter>: " 3764 + parser.getName() + " at " + mArchiveSourcePath + " " 3765 + parser.getPositionDescription()); 3766 XmlUtils.skipCurrentTag(parser); 3767 } else { 3768 outError[0] = "Bad element under <intent-filter>: " + parser.getName(); 3769 return false; 3770 } 3771 } 3772 3773 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT); 3774 3775 if (DEBUG_PARSER) { 3776 final StringBuilder cats = new StringBuilder("Intent d="); 3777 cats.append(outInfo.hasDefault); 3778 cats.append(", cat="); 3779 3780 final Iterator<String> it = outInfo.categoriesIterator(); 3781 if (it != null) { 3782 while (it.hasNext()) { 3783 cats.append(' '); 3784 cats.append(it.next()); 3785 } 3786 } 3787 Slog.d(TAG, cats.toString()); 3788 } 3789 3790 return true; 3791 } 3792 3793 /** 3794 * Representation of a full package parsed from APK files on disk. A package 3795 * consists of a single base APK, and zero or more split APKs. 3796 */ 3797 public final static class Package { 3798 3799 public String packageName; 3800 /** Names of any split APKs, ordered by parsed splitName */ 3801 public String[] splitNames; 3802 3803 // TODO: work towards making these paths invariant 3804 3805 /** 3806 * Path where this package was found on disk. For monolithic packages 3807 * this is path to single base APK file; for cluster packages this is 3808 * path to the cluster directory. 3809 */ 3810 public String codePath; 3811 3812 /** Path of base APK */ 3813 public String baseCodePath; 3814 /** Paths of any split APKs, ordered by parsed splitName */ 3815 public String[] splitCodePaths; 3816 3817 // For now we only support one application per package. 3818 public final ApplicationInfo applicationInfo = new ApplicationInfo(); 3819 3820 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0); 3821 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0); 3822 public final ArrayList<Activity> activities = new ArrayList<Activity>(0); 3823 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0); 3824 public final ArrayList<Provider> providers = new ArrayList<Provider>(0); 3825 public final ArrayList<Service> services = new ArrayList<Service>(0); 3826 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0); 3827 3828 public final ArrayList<String> requestedPermissions = new ArrayList<String>(); 3829 public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>(); 3830 3831 public ArrayList<String> protectedBroadcasts; 3832 3833 public ArrayList<String> libraryNames = null; 3834 public ArrayList<String> usesLibraries = null; 3835 public ArrayList<String> usesOptionalLibraries = null; 3836 public String[] usesLibraryFiles = null; 3837 3838 public ArrayList<ActivityIntentInfo> preferredActivityFilters = null; 3839 3840 public ArrayList<String> mOriginalPackages = null; 3841 public String mRealPackage = null; 3842 public ArrayList<String> mAdoptPermissions = null; 3843 3844 // We store the application meta-data independently to avoid multiple unwanted references 3845 public Bundle mAppMetaData = null; 3846 3847 // The version code declared for this package. 3848 public int mVersionCode; 3849 3850 // The version name declared for this package. 3851 public String mVersionName; 3852 3853 // The shared user id that this package wants to use. 3854 public String mSharedUserId; 3855 3856 // The shared user label that this package wants to use. 3857 public int mSharedUserLabel; 3858 3859 // Signatures that were read from the package. 3860 public Signature[] mSignatures; 3861 public Certificate[][] mCertificates; 3862 3863 // For use by package manager service for quick lookup of 3864 // preferred up order. 3865 public int mPreferredOrder = 0; 3866 3867 // For use by package manager to keep track of where it needs to do dexopt. 3868 public boolean mDexOptNeeded = true; 3869 3870 // For use by package manager to keep track of when a package was last used. 3871 public long mLastPackageUsageTimeInMills; 3872 3873 // // User set enabled state. 3874 // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; 3875 // 3876 // // Whether the package has been stopped. 3877 // public boolean mSetStopped = false; 3878 3879 // Additional data supplied by callers. 3880 public Object mExtras; 3881 3882 // Whether an operation is currently pending on this package 3883 public boolean mOperationPending; 3884 3885 /* 3886 * Applications hardware preferences 3887 */ 3888 public final ArrayList<ConfigurationInfo> configPreferences = 3889 new ArrayList<ConfigurationInfo>(); 3890 3891 /* 3892 * Applications requested features 3893 */ 3894 public ArrayList<FeatureInfo> reqFeatures = null; 3895 3896 public int installLocation; 3897 3898 /* An app that's required for all users and cannot be uninstalled for a user */ 3899 public boolean mRequiredForAllUsers; 3900 3901 /* For which types of profile this app is required */ 3902 public int mRequiredForProfile; 3903 3904 /* The restricted account authenticator type that is used by this application */ 3905 public String mRestrictedAccountType; 3906 3907 /* The required account type without which this application will not function */ 3908 public String mRequiredAccountType; 3909 3910 /** 3911 * Digest suitable for comparing whether this package's manifest is the 3912 * same as another. 3913 */ 3914 public ManifestDigest manifestDigest; 3915 3916 public String mOverlayTarget; 3917 public int mOverlayPriority; 3918 public boolean mTrustedOverlay; 3919 3920 /** 3921 * Data used to feed the KeySetManager 3922 */ 3923 public Set<PublicKey> mSigningKeys; 3924 public Set<String> mUpgradeKeySets; 3925 public Map<String, Set<PublicKey>> mKeySetMapping; 3926 3927 public Package(String packageName) { 3928 this.packageName = packageName; 3929 applicationInfo.packageName = packageName; 3930 applicationInfo.uid = -1; 3931 } 3932 3933 public List<String> getAllCodePaths() { 3934 ArrayList<String> paths = new ArrayList<>(); 3935 paths.add(baseCodePath); 3936 if (!ArrayUtils.isEmpty(splitCodePaths)) { 3937 Collections.addAll(paths, splitCodePaths); 3938 } 3939 return paths; 3940 } 3941 3942 public void setPackageName(String newName) { 3943 packageName = newName; 3944 applicationInfo.packageName = newName; 3945 for (int i=permissions.size()-1; i>=0; i--) { 3946 permissions.get(i).setPackageName(newName); 3947 } 3948 for (int i=permissionGroups.size()-1; i>=0; i--) { 3949 permissionGroups.get(i).setPackageName(newName); 3950 } 3951 for (int i=activities.size()-1; i>=0; i--) { 3952 activities.get(i).setPackageName(newName); 3953 } 3954 for (int i=receivers.size()-1; i>=0; i--) { 3955 receivers.get(i).setPackageName(newName); 3956 } 3957 for (int i=providers.size()-1; i>=0; i--) { 3958 providers.get(i).setPackageName(newName); 3959 } 3960 for (int i=services.size()-1; i>=0; i--) { 3961 services.get(i).setPackageName(newName); 3962 } 3963 for (int i=instrumentation.size()-1; i>=0; i--) { 3964 instrumentation.get(i).setPackageName(newName); 3965 } 3966 } 3967 3968 public boolean hasComponentClassName(String name) { 3969 for (int i=activities.size()-1; i>=0; i--) { 3970 if (name.equals(activities.get(i).className)) { 3971 return true; 3972 } 3973 } 3974 for (int i=receivers.size()-1; i>=0; i--) { 3975 if (name.equals(receivers.get(i).className)) { 3976 return true; 3977 } 3978 } 3979 for (int i=providers.size()-1; i>=0; i--) { 3980 if (name.equals(providers.get(i).className)) { 3981 return true; 3982 } 3983 } 3984 for (int i=services.size()-1; i>=0; i--) { 3985 if (name.equals(services.get(i).className)) { 3986 return true; 3987 } 3988 } 3989 for (int i=instrumentation.size()-1; i>=0; i--) { 3990 if (name.equals(instrumentation.get(i).className)) { 3991 return true; 3992 } 3993 } 3994 return false; 3995 } 3996 3997 public String toString() { 3998 return "Package{" 3999 + Integer.toHexString(System.identityHashCode(this)) 4000 + " " + packageName + "}"; 4001 } 4002 } 4003 4004 public static class Component<II extends IntentInfo> { 4005 public final Package owner; 4006 public final ArrayList<II> intents; 4007 public final String className; 4008 public Bundle metaData; 4009 4010 ComponentName componentName; 4011 String componentShortName; 4012 4013 public Component(Package _owner) { 4014 owner = _owner; 4015 intents = null; 4016 className = null; 4017 } 4018 4019 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) { 4020 owner = args.owner; 4021 intents = new ArrayList<II>(0); 4022 String name = args.sa.getNonConfigurationString(args.nameRes, 0); 4023 if (name == null) { 4024 className = null; 4025 args.outError[0] = args.tag + " does not specify android:name"; 4026 return; 4027 } 4028 4029 outInfo.name 4030 = buildClassName(owner.applicationInfo.packageName, name, args.outError); 4031 if (outInfo.name == null) { 4032 className = null; 4033 args.outError[0] = args.tag + " does not have valid android:name"; 4034 return; 4035 } 4036 4037 className = outInfo.name; 4038 4039 int iconVal = args.sa.getResourceId(args.iconRes, 0); 4040 if (iconVal != 0) { 4041 outInfo.icon = iconVal; 4042 outInfo.nonLocalizedLabel = null; 4043 } 4044 4045 int logoVal = args.sa.getResourceId(args.logoRes, 0); 4046 if (logoVal != 0) { 4047 outInfo.logo = logoVal; 4048 } 4049 4050 int bannerVal = args.sa.getResourceId(args.bannerRes, 0); 4051 if (bannerVal != 0) { 4052 outInfo.banner = bannerVal; 4053 } 4054 4055 TypedValue v = args.sa.peekValue(args.labelRes); 4056 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 4057 outInfo.nonLocalizedLabel = v.coerceToString(); 4058 } 4059 4060 outInfo.packageName = owner.packageName; 4061 } 4062 4063 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) { 4064 this(args, (PackageItemInfo)outInfo); 4065 if (args.outError[0] != null) { 4066 return; 4067 } 4068 4069 if (args.processRes != 0) { 4070 CharSequence pname; 4071 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 4072 pname = args.sa.getNonConfigurationString(args.processRes, 4073 Configuration.NATIVE_CONFIG_VERSION); 4074 } else { 4075 // Some older apps have been seen to use a resource reference 4076 // here that on older builds was ignored (with a warning). We 4077 // need to continue to do this for them so they don't break. 4078 pname = args.sa.getNonResourceString(args.processRes); 4079 } 4080 outInfo.processName = buildProcessName(owner.applicationInfo.packageName, 4081 owner.applicationInfo.processName, pname, 4082 args.flags, args.sepProcesses, args.outError); 4083 } 4084 4085 if (args.descriptionRes != 0) { 4086 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0); 4087 } 4088 4089 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true); 4090 } 4091 4092 public Component(Component<II> clone) { 4093 owner = clone.owner; 4094 intents = clone.intents; 4095 className = clone.className; 4096 componentName = clone.componentName; 4097 componentShortName = clone.componentShortName; 4098 } 4099 4100 public ComponentName getComponentName() { 4101 if (componentName != null) { 4102 return componentName; 4103 } 4104 if (className != null) { 4105 componentName = new ComponentName(owner.applicationInfo.packageName, 4106 className); 4107 } 4108 return componentName; 4109 } 4110 4111 public void appendComponentShortName(StringBuilder sb) { 4112 ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className); 4113 } 4114 4115 public void printComponentShortName(PrintWriter pw) { 4116 ComponentName.printShortString(pw, owner.applicationInfo.packageName, className); 4117 } 4118 4119 public void setPackageName(String packageName) { 4120 componentName = null; 4121 componentShortName = null; 4122 } 4123 } 4124 4125 public final static class Permission extends Component<IntentInfo> { 4126 public final PermissionInfo info; 4127 public boolean tree; 4128 public PermissionGroup group; 4129 4130 public Permission(Package _owner) { 4131 super(_owner); 4132 info = new PermissionInfo(); 4133 } 4134 4135 public Permission(Package _owner, PermissionInfo _info) { 4136 super(_owner); 4137 info = _info; 4138 } 4139 4140 public void setPackageName(String packageName) { 4141 super.setPackageName(packageName); 4142 info.packageName = packageName; 4143 } 4144 4145 public String toString() { 4146 return "Permission{" 4147 + Integer.toHexString(System.identityHashCode(this)) 4148 + " " + info.name + "}"; 4149 } 4150 } 4151 4152 public final static class PermissionGroup extends Component<IntentInfo> { 4153 public final PermissionGroupInfo info; 4154 4155 public PermissionGroup(Package _owner) { 4156 super(_owner); 4157 info = new PermissionGroupInfo(); 4158 } 4159 4160 public PermissionGroup(Package _owner, PermissionGroupInfo _info) { 4161 super(_owner); 4162 info = _info; 4163 } 4164 4165 public void setPackageName(String packageName) { 4166 super.setPackageName(packageName); 4167 info.packageName = packageName; 4168 } 4169 4170 public String toString() { 4171 return "PermissionGroup{" 4172 + Integer.toHexString(System.identityHashCode(this)) 4173 + " " + info.name + "}"; 4174 } 4175 } 4176 4177 private static boolean copyNeeded(int flags, Package p, 4178 PackageUserState state, Bundle metaData, int userId) { 4179 if (userId != 0) { 4180 // We always need to copy for other users, since we need 4181 // to fix up the uid. 4182 return true; 4183 } 4184 if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 4185 boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 4186 if (p.applicationInfo.enabled != enabled) { 4187 return true; 4188 } 4189 } 4190 if (!state.installed || state.blocked) { 4191 return true; 4192 } 4193 if (state.stopped) { 4194 return true; 4195 } 4196 if ((flags & PackageManager.GET_META_DATA) != 0 4197 && (metaData != null || p.mAppMetaData != null)) { 4198 return true; 4199 } 4200 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 4201 && p.usesLibraryFiles != null) { 4202 return true; 4203 } 4204 return false; 4205 } 4206 4207 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 4208 PackageUserState state) { 4209 return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId()); 4210 } 4211 4212 private static void updateApplicationInfo(ApplicationInfo ai, int flags, 4213 PackageUserState state) { 4214 // CompatibilityMode is global state. 4215 if (!sCompatibilityModeEnabled) { 4216 ai.disableCompatibilityMode(); 4217 } 4218 if (state.installed) { 4219 ai.flags |= ApplicationInfo.FLAG_INSTALLED; 4220 } else { 4221 ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; 4222 } 4223 if (state.blocked) { 4224 ai.flags |= ApplicationInfo.FLAG_BLOCKED; 4225 } else { 4226 ai.flags &= ~ApplicationInfo.FLAG_BLOCKED; 4227 } 4228 if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 4229 ai.enabled = true; 4230 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { 4231 ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0; 4232 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED 4233 || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { 4234 ai.enabled = false; 4235 } 4236 ai.enabledSetting = state.enabled; 4237 } 4238 4239 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 4240 PackageUserState state, int userId) { 4241 if (p == null) return null; 4242 if (!checkUseInstalledOrBlocked(flags, state)) { 4243 return null; 4244 } 4245 if (!copyNeeded(flags, p, state, null, userId) 4246 && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0 4247 || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { 4248 // In this case it is safe to directly modify the internal ApplicationInfo state: 4249 // - CompatibilityMode is global state, so will be the same for every call. 4250 // - We only come in to here if the app should reported as installed; this is the 4251 // default state, and we will do a copy otherwise. 4252 // - The enable state will always be reported the same for the application across 4253 // calls; the only exception is for the UNTIL_USED mode, and in that case we will 4254 // be doing a copy. 4255 updateApplicationInfo(p.applicationInfo, flags, state); 4256 return p.applicationInfo; 4257 } 4258 4259 // Make shallow copy so we can store the metadata/libraries safely 4260 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo); 4261 if (userId != 0) { 4262 ai.uid = UserHandle.getUid(userId, ai.uid); 4263 ai.dataDir = PackageManager.getDataDirForUser(userId, ai.packageName); 4264 } 4265 if ((flags & PackageManager.GET_META_DATA) != 0) { 4266 ai.metaData = p.mAppMetaData; 4267 } 4268 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { 4269 ai.sharedLibraryFiles = p.usesLibraryFiles; 4270 } 4271 if (state.stopped) { 4272 ai.flags |= ApplicationInfo.FLAG_STOPPED; 4273 } else { 4274 ai.flags &= ~ApplicationInfo.FLAG_STOPPED; 4275 } 4276 updateApplicationInfo(ai, flags, state); 4277 return ai; 4278 } 4279 4280 public static final PermissionInfo generatePermissionInfo( 4281 Permission p, int flags) { 4282 if (p == null) return null; 4283 if ((flags&PackageManager.GET_META_DATA) == 0) { 4284 return p.info; 4285 } 4286 PermissionInfo pi = new PermissionInfo(p.info); 4287 pi.metaData = p.metaData; 4288 return pi; 4289 } 4290 4291 public static final PermissionGroupInfo generatePermissionGroupInfo( 4292 PermissionGroup pg, int flags) { 4293 if (pg == null) return null; 4294 if ((flags&PackageManager.GET_META_DATA) == 0) { 4295 return pg.info; 4296 } 4297 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info); 4298 pgi.metaData = pg.metaData; 4299 return pgi; 4300 } 4301 4302 public final static class Activity extends Component<ActivityIntentInfo> { 4303 public final ActivityInfo info; 4304 4305 public Activity(final ParseComponentArgs args, final ActivityInfo _info) { 4306 super(args, _info); 4307 info = _info; 4308 info.applicationInfo = args.owner.applicationInfo; 4309 } 4310 4311 public void setPackageName(String packageName) { 4312 super.setPackageName(packageName); 4313 info.packageName = packageName; 4314 } 4315 4316 public String toString() { 4317 StringBuilder sb = new StringBuilder(128); 4318 sb.append("Activity{"); 4319 sb.append(Integer.toHexString(System.identityHashCode(this))); 4320 sb.append(' '); 4321 appendComponentShortName(sb); 4322 sb.append('}'); 4323 return sb.toString(); 4324 } 4325 } 4326 4327 public static final ActivityInfo generateActivityInfo(Activity a, int flags, 4328 PackageUserState state, int userId) { 4329 if (a == null) return null; 4330 if (!checkUseInstalledOrBlocked(flags, state)) { 4331 return null; 4332 } 4333 if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) { 4334 return a.info; 4335 } 4336 // Make shallow copies so we can store the metadata safely 4337 ActivityInfo ai = new ActivityInfo(a.info); 4338 ai.metaData = a.metaData; 4339 ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId); 4340 return ai; 4341 } 4342 4343 public final static class Service extends Component<ServiceIntentInfo> { 4344 public final ServiceInfo info; 4345 4346 public Service(final ParseComponentArgs args, final ServiceInfo _info) { 4347 super(args, _info); 4348 info = _info; 4349 info.applicationInfo = args.owner.applicationInfo; 4350 } 4351 4352 public void setPackageName(String packageName) { 4353 super.setPackageName(packageName); 4354 info.packageName = packageName; 4355 } 4356 4357 public String toString() { 4358 StringBuilder sb = new StringBuilder(128); 4359 sb.append("Service{"); 4360 sb.append(Integer.toHexString(System.identityHashCode(this))); 4361 sb.append(' '); 4362 appendComponentShortName(sb); 4363 sb.append('}'); 4364 return sb.toString(); 4365 } 4366 } 4367 4368 public static final ServiceInfo generateServiceInfo(Service s, int flags, 4369 PackageUserState state, int userId) { 4370 if (s == null) return null; 4371 if (!checkUseInstalledOrBlocked(flags, state)) { 4372 return null; 4373 } 4374 if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) { 4375 return s.info; 4376 } 4377 // Make shallow copies so we can store the metadata safely 4378 ServiceInfo si = new ServiceInfo(s.info); 4379 si.metaData = s.metaData; 4380 si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId); 4381 return si; 4382 } 4383 4384 public final static class Provider extends Component<ProviderIntentInfo> { 4385 public final ProviderInfo info; 4386 public boolean syncable; 4387 4388 public Provider(final ParseComponentArgs args, final ProviderInfo _info) { 4389 super(args, _info); 4390 info = _info; 4391 info.applicationInfo = args.owner.applicationInfo; 4392 syncable = false; 4393 } 4394 4395 public Provider(Provider existingProvider) { 4396 super(existingProvider); 4397 this.info = existingProvider.info; 4398 this.syncable = existingProvider.syncable; 4399 } 4400 4401 public void setPackageName(String packageName) { 4402 super.setPackageName(packageName); 4403 info.packageName = packageName; 4404 } 4405 4406 public String toString() { 4407 StringBuilder sb = new StringBuilder(128); 4408 sb.append("Provider{"); 4409 sb.append(Integer.toHexString(System.identityHashCode(this))); 4410 sb.append(' '); 4411 appendComponentShortName(sb); 4412 sb.append('}'); 4413 return sb.toString(); 4414 } 4415 } 4416 4417 public static final ProviderInfo generateProviderInfo(Provider p, int flags, 4418 PackageUserState state, int userId) { 4419 if (p == null) return null; 4420 if (!checkUseInstalledOrBlocked(flags, state)) { 4421 return null; 4422 } 4423 if (!copyNeeded(flags, p.owner, state, p.metaData, userId) 4424 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 4425 || p.info.uriPermissionPatterns == null)) { 4426 return p.info; 4427 } 4428 // Make shallow copies so we can store the metadata safely 4429 ProviderInfo pi = new ProviderInfo(p.info); 4430 pi.metaData = p.metaData; 4431 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { 4432 pi.uriPermissionPatterns = null; 4433 } 4434 pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId); 4435 return pi; 4436 } 4437 4438 public final static class Instrumentation extends Component { 4439 public final InstrumentationInfo info; 4440 4441 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) { 4442 super(args, _info); 4443 info = _info; 4444 } 4445 4446 public void setPackageName(String packageName) { 4447 super.setPackageName(packageName); 4448 info.packageName = packageName; 4449 } 4450 4451 public String toString() { 4452 StringBuilder sb = new StringBuilder(128); 4453 sb.append("Instrumentation{"); 4454 sb.append(Integer.toHexString(System.identityHashCode(this))); 4455 sb.append(' '); 4456 appendComponentShortName(sb); 4457 sb.append('}'); 4458 return sb.toString(); 4459 } 4460 } 4461 4462 public static final InstrumentationInfo generateInstrumentationInfo( 4463 Instrumentation i, int flags) { 4464 if (i == null) return null; 4465 if ((flags&PackageManager.GET_META_DATA) == 0) { 4466 return i.info; 4467 } 4468 InstrumentationInfo ii = new InstrumentationInfo(i.info); 4469 ii.metaData = i.metaData; 4470 return ii; 4471 } 4472 4473 public static class IntentInfo extends IntentFilter { 4474 public boolean hasDefault; 4475 public int labelRes; 4476 public CharSequence nonLocalizedLabel; 4477 public int icon; 4478 public int logo; 4479 public int banner; 4480 public int preferred; 4481 } 4482 4483 public final static class ActivityIntentInfo extends IntentInfo { 4484 public final Activity activity; 4485 4486 public ActivityIntentInfo(Activity _activity) { 4487 activity = _activity; 4488 } 4489 4490 public String toString() { 4491 StringBuilder sb = new StringBuilder(128); 4492 sb.append("ActivityIntentInfo{"); 4493 sb.append(Integer.toHexString(System.identityHashCode(this))); 4494 sb.append(' '); 4495 activity.appendComponentShortName(sb); 4496 sb.append('}'); 4497 return sb.toString(); 4498 } 4499 } 4500 4501 public final static class ServiceIntentInfo extends IntentInfo { 4502 public final Service service; 4503 4504 public ServiceIntentInfo(Service _service) { 4505 service = _service; 4506 } 4507 4508 public String toString() { 4509 StringBuilder sb = new StringBuilder(128); 4510 sb.append("ServiceIntentInfo{"); 4511 sb.append(Integer.toHexString(System.identityHashCode(this))); 4512 sb.append(' '); 4513 service.appendComponentShortName(sb); 4514 sb.append('}'); 4515 return sb.toString(); 4516 } 4517 } 4518 4519 public static final class ProviderIntentInfo extends IntentInfo { 4520 public final Provider provider; 4521 4522 public ProviderIntentInfo(Provider provider) { 4523 this.provider = provider; 4524 } 4525 4526 public String toString() { 4527 StringBuilder sb = new StringBuilder(128); 4528 sb.append("ProviderIntentInfo{"); 4529 sb.append(Integer.toHexString(System.identityHashCode(this))); 4530 sb.append(' '); 4531 provider.appendComponentShortName(sb); 4532 sb.append('}'); 4533 return sb.toString(); 4534 } 4535 } 4536 4537 /** 4538 * @hide 4539 */ 4540 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { 4541 sCompatibilityModeEnabled = compatibilityModeEnabled; 4542 } 4543 4544 private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>(); 4545 4546 public static long readFullyIgnoringContents(InputStream in) throws IOException { 4547 byte[] buffer = sBuffer.getAndSet(null); 4548 if (buffer == null) { 4549 buffer = new byte[4096]; 4550 } 4551 4552 int n = 0; 4553 int count = 0; 4554 while ((n = in.read(buffer, 0, buffer.length)) != -1) { 4555 count += n; 4556 } 4557 4558 sBuffer.set(buffer); 4559 return count; 4560 } 4561 4562 public static void closeQuietly(StrictJarFile jarFile) { 4563 if (jarFile != null) { 4564 try { 4565 jarFile.close(); 4566 } catch (Exception ignored) { 4567 } 4568 } 4569 } 4570 4571 public static class PackageParserException extends Exception { 4572 public final int error; 4573 4574 public PackageParserException(int error, String detailMessage) { 4575 super(detailMessage); 4576 this.error = error; 4577 } 4578 4579 public PackageParserException(int error, String detailMessage, Throwable throwable) { 4580 super(detailMessage, throwable); 4581 this.error = error; 4582 } 4583 } 4584} 4585