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