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