PackageParser.java revision 032f2b246bd01653c592f2b148d6a0debfe164b2
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<>(); 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("uses-permission")) { 1226 if (!parseUsesPermission(pkg, res, parser, attrs, outError)) { 1227 return null; 1228 } 1229 } else if (tagName.equals("uses-configuration")) { 1230 ConfigurationInfo cPref = new ConfigurationInfo(); 1231 sa = res.obtainAttributes(attrs, 1232 com.android.internal.R.styleable.AndroidManifestUsesConfiguration); 1233 cPref.reqTouchScreen = sa.getInt( 1234 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, 1235 Configuration.TOUCHSCREEN_UNDEFINED); 1236 cPref.reqKeyboardType = sa.getInt( 1237 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, 1238 Configuration.KEYBOARD_UNDEFINED); 1239 if (sa.getBoolean( 1240 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, 1241 false)) { 1242 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; 1243 } 1244 cPref.reqNavigation = sa.getInt( 1245 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation, 1246 Configuration.NAVIGATION_UNDEFINED); 1247 if (sa.getBoolean( 1248 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, 1249 false)) { 1250 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; 1251 } 1252 sa.recycle(); 1253 pkg.configPreferences.add(cPref); 1254 1255 XmlUtils.skipCurrentTag(parser); 1256 1257 } else if (tagName.equals("uses-feature")) { 1258 FeatureInfo fi = new FeatureInfo(); 1259 sa = res.obtainAttributes(attrs, 1260 com.android.internal.R.styleable.AndroidManifestUsesFeature); 1261 // Note: don't allow this value to be a reference to a resource 1262 // that may change. 1263 fi.name = sa.getNonResourceString( 1264 com.android.internal.R.styleable.AndroidManifestUsesFeature_name); 1265 if (fi.name == null) { 1266 fi.reqGlEsVersion = sa.getInt( 1267 com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion, 1268 FeatureInfo.GL_ES_VERSION_UNDEFINED); 1269 } 1270 if (sa.getBoolean( 1271 com.android.internal.R.styleable.AndroidManifestUsesFeature_required, 1272 true)) { 1273 fi.flags |= FeatureInfo.FLAG_REQUIRED; 1274 } 1275 sa.recycle(); 1276 if (pkg.reqFeatures == null) { 1277 pkg.reqFeatures = new ArrayList<FeatureInfo>(); 1278 } 1279 pkg.reqFeatures.add(fi); 1280 1281 if (fi.name == null) { 1282 ConfigurationInfo cPref = new ConfigurationInfo(); 1283 cPref.reqGlEsVersion = fi.reqGlEsVersion; 1284 pkg.configPreferences.add(cPref); 1285 } 1286 1287 XmlUtils.skipCurrentTag(parser); 1288 1289 } else if (tagName.equals("uses-sdk")) { 1290 if (SDK_VERSION > 0) { 1291 sa = res.obtainAttributes(attrs, 1292 com.android.internal.R.styleable.AndroidManifestUsesSdk); 1293 1294 int minVers = 0; 1295 String minCode = null; 1296 int targetVers = 0; 1297 String targetCode = null; 1298 1299 TypedValue val = sa.peekValue( 1300 com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); 1301 if (val != null) { 1302 if (val.type == TypedValue.TYPE_STRING && val.string != null) { 1303 targetCode = minCode = val.string.toString(); 1304 } else { 1305 // If it's not a string, it's an integer. 1306 targetVers = minVers = val.data; 1307 } 1308 } 1309 1310 val = sa.peekValue( 1311 com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); 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 = val.data; 1318 } 1319 } 1320 1321 sa.recycle(); 1322 1323 if (minCode != null) { 1324 boolean allowedCodename = false; 1325 for (String codename : SDK_CODENAMES) { 1326 if (minCode.equals(codename)) { 1327 allowedCodename = true; 1328 break; 1329 } 1330 } 1331 if (!allowedCodename) { 1332 if (SDK_CODENAMES.length > 0) { 1333 outError[0] = "Requires development platform " + minCode 1334 + " (current platform is any of " 1335 + Arrays.toString(SDK_CODENAMES) + ")"; 1336 } else { 1337 outError[0] = "Requires development platform " + minCode 1338 + " but this is a release platform."; 1339 } 1340 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1341 return null; 1342 } 1343 } else if (minVers > SDK_VERSION) { 1344 outError[0] = "Requires newer sdk version #" + minVers 1345 + " (current version is #" + SDK_VERSION + ")"; 1346 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1347 return null; 1348 } 1349 1350 if (targetCode != null) { 1351 boolean allowedCodename = false; 1352 for (String codename : SDK_CODENAMES) { 1353 if (targetCode.equals(codename)) { 1354 allowedCodename = true; 1355 break; 1356 } 1357 } 1358 if (!allowedCodename) { 1359 if (SDK_CODENAMES.length > 0) { 1360 outError[0] = "Requires development platform " + targetCode 1361 + " (current platform is any of " 1362 + Arrays.toString(SDK_CODENAMES) + ")"; 1363 } else { 1364 outError[0] = "Requires development platform " + targetCode 1365 + " but this is a release platform."; 1366 } 1367 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1368 return null; 1369 } 1370 // If the code matches, it definitely targets this SDK. 1371 pkg.applicationInfo.targetSdkVersion 1372 = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; 1373 } else { 1374 pkg.applicationInfo.targetSdkVersion = targetVers; 1375 } 1376 } 1377 1378 XmlUtils.skipCurrentTag(parser); 1379 1380 } else if (tagName.equals("supports-screens")) { 1381 sa = res.obtainAttributes(attrs, 1382 com.android.internal.R.styleable.AndroidManifestSupportsScreens); 1383 1384 pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger( 1385 com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, 1386 0); 1387 pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger( 1388 com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, 1389 0); 1390 pkg.applicationInfo.largestWidthLimitDp = sa.getInteger( 1391 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, 1392 0); 1393 1394 // This is a trick to get a boolean and still able to detect 1395 // if a value was actually set. 1396 supportsSmallScreens = sa.getInteger( 1397 com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens, 1398 supportsSmallScreens); 1399 supportsNormalScreens = sa.getInteger( 1400 com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens, 1401 supportsNormalScreens); 1402 supportsLargeScreens = sa.getInteger( 1403 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens, 1404 supportsLargeScreens); 1405 supportsXLargeScreens = sa.getInteger( 1406 com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1407 supportsXLargeScreens); 1408 resizeable = sa.getInteger( 1409 com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable, 1410 resizeable); 1411 anyDensity = sa.getInteger( 1412 com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity, 1413 anyDensity); 1414 1415 sa.recycle(); 1416 1417 XmlUtils.skipCurrentTag(parser); 1418 1419 } else if (tagName.equals("protected-broadcast")) { 1420 sa = res.obtainAttributes(attrs, 1421 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast); 1422 1423 // Note: don't allow this value to be a reference to a resource 1424 // that may change. 1425 String name = sa.getNonResourceString( 1426 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name); 1427 1428 sa.recycle(); 1429 1430 if (name != null && (flags&PARSE_IS_SYSTEM) != 0) { 1431 if (pkg.protectedBroadcasts == null) { 1432 pkg.protectedBroadcasts = new ArrayList<String>(); 1433 } 1434 if (!pkg.protectedBroadcasts.contains(name)) { 1435 pkg.protectedBroadcasts.add(name.intern()); 1436 } 1437 } 1438 1439 XmlUtils.skipCurrentTag(parser); 1440 1441 } else if (tagName.equals("instrumentation")) { 1442 if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) { 1443 return null; 1444 } 1445 1446 } else if (tagName.equals("original-package")) { 1447 sa = res.obtainAttributes(attrs, 1448 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 1449 1450 String orig =sa.getNonConfigurationString( 1451 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 1452 if (!pkg.packageName.equals(orig)) { 1453 if (pkg.mOriginalPackages == null) { 1454 pkg.mOriginalPackages = new ArrayList<String>(); 1455 pkg.mRealPackage = pkg.packageName; 1456 } 1457 pkg.mOriginalPackages.add(orig); 1458 } 1459 1460 sa.recycle(); 1461 1462 XmlUtils.skipCurrentTag(parser); 1463 1464 } else if (tagName.equals("adopt-permissions")) { 1465 sa = res.obtainAttributes(attrs, 1466 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 1467 1468 String name = sa.getNonConfigurationString( 1469 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 1470 1471 sa.recycle(); 1472 1473 if (name != null) { 1474 if (pkg.mAdoptPermissions == null) { 1475 pkg.mAdoptPermissions = new ArrayList<String>(); 1476 } 1477 pkg.mAdoptPermissions.add(name); 1478 } 1479 1480 XmlUtils.skipCurrentTag(parser); 1481 1482 } else if (tagName.equals("uses-gl-texture")) { 1483 // Just skip this tag 1484 XmlUtils.skipCurrentTag(parser); 1485 continue; 1486 1487 } else if (tagName.equals("compatible-screens")) { 1488 // Just skip this tag 1489 XmlUtils.skipCurrentTag(parser); 1490 continue; 1491 } else if (tagName.equals("supports-input")) { 1492 XmlUtils.skipCurrentTag(parser); 1493 continue; 1494 1495 } else if (tagName.equals("eat-comment")) { 1496 // Just skip this tag 1497 XmlUtils.skipCurrentTag(parser); 1498 continue; 1499 1500 } else if (RIGID_PARSER) { 1501 outError[0] = "Bad element under <manifest>: " 1502 + parser.getName(); 1503 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1504 return null; 1505 1506 } else { 1507 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() 1508 + " at " + mArchiveSourcePath + " " 1509 + parser.getPositionDescription()); 1510 XmlUtils.skipCurrentTag(parser); 1511 continue; 1512 } 1513 } 1514 1515 if (!foundApp && pkg.instrumentation.size() == 0) { 1516 outError[0] = "<manifest> does not contain an <application> or <instrumentation>"; 1517 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; 1518 } 1519 1520 final int NP = PackageParser.NEW_PERMISSIONS.length; 1521 StringBuilder implicitPerms = null; 1522 for (int ip=0; ip<NP; ip++) { 1523 final PackageParser.NewPermissionInfo npi 1524 = PackageParser.NEW_PERMISSIONS[ip]; 1525 if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) { 1526 break; 1527 } 1528 if (!pkg.requestedPermissions.contains(npi.name)) { 1529 if (implicitPerms == null) { 1530 implicitPerms = new StringBuilder(128); 1531 implicitPerms.append(pkg.packageName); 1532 implicitPerms.append(": compat added "); 1533 } else { 1534 implicitPerms.append(' '); 1535 } 1536 implicitPerms.append(npi.name); 1537 pkg.requestedPermissions.add(npi.name); 1538 pkg.requestedPermissionsRequired.add(Boolean.TRUE); 1539 } 1540 } 1541 if (implicitPerms != null) { 1542 Slog.i(TAG, implicitPerms.toString()); 1543 } 1544 1545 final int NS = PackageParser.SPLIT_PERMISSIONS.length; 1546 for (int is=0; is<NS; is++) { 1547 final PackageParser.SplitPermissionInfo spi 1548 = PackageParser.SPLIT_PERMISSIONS[is]; 1549 if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk 1550 || !pkg.requestedPermissions.contains(spi.rootPerm)) { 1551 continue; 1552 } 1553 for (int in=0; in<spi.newPerms.length; in++) { 1554 final String perm = spi.newPerms[in]; 1555 if (!pkg.requestedPermissions.contains(perm)) { 1556 pkg.requestedPermissions.add(perm); 1557 pkg.requestedPermissionsRequired.add(Boolean.TRUE); 1558 } 1559 } 1560 } 1561 1562 if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 1563 && pkg.applicationInfo.targetSdkVersion 1564 >= android.os.Build.VERSION_CODES.DONUT)) { 1565 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; 1566 } 1567 if (supportsNormalScreens != 0) { 1568 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; 1569 } 1570 if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 1571 && pkg.applicationInfo.targetSdkVersion 1572 >= android.os.Build.VERSION_CODES.DONUT)) { 1573 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; 1574 } 1575 if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 1576 && pkg.applicationInfo.targetSdkVersion 1577 >= android.os.Build.VERSION_CODES.GINGERBREAD)) { 1578 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; 1579 } 1580 if (resizeable < 0 || (resizeable > 0 1581 && pkg.applicationInfo.targetSdkVersion 1582 >= android.os.Build.VERSION_CODES.DONUT)) { 1583 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; 1584 } 1585 if (anyDensity < 0 || (anyDensity > 0 1586 && pkg.applicationInfo.targetSdkVersion 1587 >= android.os.Build.VERSION_CODES.DONUT)) { 1588 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; 1589 } 1590 1591 /* 1592 * b/8528162: Ignore the <uses-permission android:required> attribute if 1593 * targetSdkVersion < JELLY_BEAN_MR2. There are lots of apps in the wild 1594 * which are improperly using this attribute, even though it never worked. 1595 */ 1596 if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) { 1597 for (int i = 0; i < pkg.requestedPermissionsRequired.size(); i++) { 1598 pkg.requestedPermissionsRequired.set(i, Boolean.TRUE); 1599 } 1600 } 1601 1602 return pkg; 1603 } 1604 1605 private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser, 1606 AttributeSet attrs, String[] outError) 1607 throws XmlPullParserException, IOException { 1608 TypedArray sa = res.obtainAttributes(attrs, 1609 com.android.internal.R.styleable.AndroidManifestUsesPermission); 1610 1611 // Note: don't allow this value to be a reference to a resource 1612 // that may change. 1613 String name = sa.getNonResourceString( 1614 com.android.internal.R.styleable.AndroidManifestUsesPermission_name); 1615/* 1616 boolean required = sa.getBoolean( 1617 com.android.internal.R.styleable.AndroidManifestUsesPermission_required, true); 1618*/ 1619 boolean required = true; // Optional <uses-permission> not supported 1620 1621 int maxSdkVersion = 0; 1622 TypedValue val = sa.peekValue( 1623 com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion); 1624 if (val != null) { 1625 if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) { 1626 maxSdkVersion = val.data; 1627 } 1628 } 1629 1630 sa.recycle(); 1631 1632 if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) { 1633 if (name != null) { 1634 int index = pkg.requestedPermissions.indexOf(name); 1635 if (index == -1) { 1636 pkg.requestedPermissions.add(name.intern()); 1637 pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE); 1638 } else { 1639 if (pkg.requestedPermissionsRequired.get(index) != required) { 1640 outError[0] = "conflicting <uses-permission> entries"; 1641 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1642 return false; 1643 } 1644 } 1645 } 1646 } 1647 1648 XmlUtils.skipCurrentTag(parser); 1649 return true; 1650 } 1651 1652 private static String buildClassName(String pkg, CharSequence clsSeq, 1653 String[] outError) { 1654 if (clsSeq == null || clsSeq.length() <= 0) { 1655 outError[0] = "Empty class name in package " + pkg; 1656 return null; 1657 } 1658 String cls = clsSeq.toString(); 1659 char c = cls.charAt(0); 1660 if (c == '.') { 1661 return (pkg + cls).intern(); 1662 } 1663 if (cls.indexOf('.') < 0) { 1664 StringBuilder b = new StringBuilder(pkg); 1665 b.append('.'); 1666 b.append(cls); 1667 return b.toString().intern(); 1668 } 1669 if (c >= 'a' && c <= 'z') { 1670 return cls.intern(); 1671 } 1672 outError[0] = "Bad class name " + cls + " in package " + pkg; 1673 return null; 1674 } 1675 1676 private static String buildCompoundName(String pkg, 1677 CharSequence procSeq, String type, String[] outError) { 1678 String proc = procSeq.toString(); 1679 char c = proc.charAt(0); 1680 if (pkg != null && c == ':') { 1681 if (proc.length() < 2) { 1682 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg 1683 + ": must be at least two characters"; 1684 return null; 1685 } 1686 String subName = proc.substring(1); 1687 String nameError = validateName(subName, false); 1688 if (nameError != null) { 1689 outError[0] = "Invalid " + type + " name " + proc + " in package " 1690 + pkg + ": " + nameError; 1691 return null; 1692 } 1693 return (pkg + proc).intern(); 1694 } 1695 String nameError = validateName(proc, true); 1696 if (nameError != null && !"system".equals(proc)) { 1697 outError[0] = "Invalid " + type + " name " + proc + " in package " 1698 + pkg + ": " + nameError; 1699 return null; 1700 } 1701 return proc.intern(); 1702 } 1703 1704 private static String buildProcessName(String pkg, String defProc, 1705 CharSequence procSeq, int flags, String[] separateProcesses, 1706 String[] outError) { 1707 if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) { 1708 return defProc != null ? defProc : pkg; 1709 } 1710 if (separateProcesses != null) { 1711 for (int i=separateProcesses.length-1; i>=0; i--) { 1712 String sp = separateProcesses[i]; 1713 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) { 1714 return pkg; 1715 } 1716 } 1717 } 1718 if (procSeq == null || procSeq.length() <= 0) { 1719 return defProc; 1720 } 1721 return buildCompoundName(pkg, procSeq, "process", outError); 1722 } 1723 1724 private static String buildTaskAffinityName(String pkg, String defProc, 1725 CharSequence procSeq, String[] outError) { 1726 if (procSeq == null) { 1727 return defProc; 1728 } 1729 if (procSeq.length() <= 0) { 1730 return null; 1731 } 1732 return buildCompoundName(pkg, procSeq, "taskAffinity", outError); 1733 } 1734 1735 private boolean parseKeys(Package owner, Resources res, 1736 XmlPullParser parser, AttributeSet attrs, String[] outError) 1737 throws XmlPullParserException, IOException { 1738 // we've encountered the 'keys' tag 1739 // all the keys and keysets that we want must be defined here 1740 // so we're going to iterate over the parser and pull out the things we want 1741 int outerDepth = parser.getDepth(); 1742 1743 int type; 1744 PublicKey currentKey = null; 1745 int currentKeyDepth = -1; 1746 Map<PublicKey, Set<String>> definedKeySets = new HashMap<PublicKey, Set<String>>(); 1747 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1748 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1749 if (type == XmlPullParser.END_TAG) { 1750 if (parser.getDepth() == currentKeyDepth) { 1751 currentKey = null; 1752 currentKeyDepth = -1; 1753 } 1754 continue; 1755 } 1756 String tagname = parser.getName(); 1757 if (tagname.equals("publicKey")) { 1758 final TypedArray sa = res.obtainAttributes(attrs, 1759 com.android.internal.R.styleable.PublicKey); 1760 final String encodedKey = sa.getNonResourceString( 1761 com.android.internal.R.styleable.PublicKey_value); 1762 currentKey = parsePublicKey(encodedKey); 1763 if (currentKey == null) { 1764 Slog.w(TAG, "No valid key in 'publicKey' tag at " 1765 + parser.getPositionDescription()); 1766 sa.recycle(); 1767 continue; 1768 } 1769 currentKeyDepth = parser.getDepth(); 1770 definedKeySets.put(currentKey, new HashSet<String>()); 1771 sa.recycle(); 1772 } else if (tagname.equals("keyset")) { 1773 if (currentKey == null) { 1774 Slog.i(TAG, "'keyset' not in 'publicKey' tag at " 1775 + parser.getPositionDescription()); 1776 continue; 1777 } 1778 final TypedArray sa = res.obtainAttributes(attrs, 1779 com.android.internal.R.styleable.KeySet); 1780 final String name = sa.getNonResourceString( 1781 com.android.internal.R.styleable.KeySet_name); 1782 definedKeySets.get(currentKey).add(name); 1783 sa.recycle(); 1784 } else if (RIGID_PARSER) { 1785 Slog.w(TAG, "Bad element under <keys>: " + parser.getName() 1786 + " at " + mArchiveSourcePath + " " 1787 + parser.getPositionDescription()); 1788 return false; 1789 } else { 1790 Slog.w(TAG, "Unknown element under <keys>: " + parser.getName() 1791 + " at " + mArchiveSourcePath + " " 1792 + parser.getPositionDescription()); 1793 XmlUtils.skipCurrentTag(parser); 1794 continue; 1795 } 1796 } 1797 1798 owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>(); 1799 for (Map.Entry<PublicKey, Set<String>> e : definedKeySets.entrySet()) { 1800 PublicKey key = e.getKey(); 1801 Set<String> keySetNames = e.getValue(); 1802 for (String alias : keySetNames) { 1803 if (owner.mKeySetMapping.containsKey(alias)) { 1804 owner.mKeySetMapping.get(alias).add(key); 1805 } else { 1806 ArraySet<PublicKey> keys = new ArraySet<PublicKey>(); 1807 keys.add(key); 1808 owner.mKeySetMapping.put(alias, keys); 1809 } 1810 } 1811 } 1812 1813 return true; 1814 } 1815 1816 private PermissionGroup parsePermissionGroup(Package owner, int flags, Resources res, 1817 XmlPullParser parser, AttributeSet attrs, String[] outError) 1818 throws XmlPullParserException, IOException { 1819 PermissionGroup perm = new PermissionGroup(owner); 1820 1821 TypedArray sa = res.obtainAttributes(attrs, 1822 com.android.internal.R.styleable.AndroidManifestPermissionGroup); 1823 1824 if (!parsePackageItemInfo(owner, perm.info, outError, 1825 "<permission-group>", sa, 1826 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name, 1827 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label, 1828 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon, 1829 com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo, 1830 com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) { 1831 sa.recycle(); 1832 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1833 return null; 1834 } 1835 1836 perm.info.descriptionRes = sa.getResourceId( 1837 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description, 1838 0); 1839 perm.info.flags = sa.getInt( 1840 com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0); 1841 perm.info.priority = sa.getInt( 1842 com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0); 1843 if (perm.info.priority > 0 && (flags&PARSE_IS_SYSTEM) == 0) { 1844 perm.info.priority = 0; 1845 } 1846 1847 sa.recycle(); 1848 1849 if (!parseAllMetaData(res, parser, attrs, "<permission-group>", perm, 1850 outError)) { 1851 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1852 return null; 1853 } 1854 1855 owner.permissionGroups.add(perm); 1856 1857 return perm; 1858 } 1859 1860 private Permission parsePermission(Package owner, Resources res, 1861 XmlPullParser parser, AttributeSet attrs, String[] outError) 1862 throws XmlPullParserException, IOException { 1863 Permission perm = new Permission(owner); 1864 1865 TypedArray sa = res.obtainAttributes(attrs, 1866 com.android.internal.R.styleable.AndroidManifestPermission); 1867 1868 if (!parsePackageItemInfo(owner, perm.info, outError, 1869 "<permission>", sa, 1870 com.android.internal.R.styleable.AndroidManifestPermission_name, 1871 com.android.internal.R.styleable.AndroidManifestPermission_label, 1872 com.android.internal.R.styleable.AndroidManifestPermission_icon, 1873 com.android.internal.R.styleable.AndroidManifestPermission_logo, 1874 com.android.internal.R.styleable.AndroidManifestPermission_banner)) { 1875 sa.recycle(); 1876 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1877 return null; 1878 } 1879 1880 // Note: don't allow this value to be a reference to a resource 1881 // that may change. 1882 perm.info.group = sa.getNonResourceString( 1883 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup); 1884 if (perm.info.group != null) { 1885 perm.info.group = perm.info.group.intern(); 1886 } 1887 1888 perm.info.descriptionRes = sa.getResourceId( 1889 com.android.internal.R.styleable.AndroidManifestPermission_description, 1890 0); 1891 1892 perm.info.protectionLevel = sa.getInt( 1893 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel, 1894 PermissionInfo.PROTECTION_NORMAL); 1895 1896 perm.info.flags = sa.getInt( 1897 com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0); 1898 1899 sa.recycle(); 1900 1901 if (perm.info.protectionLevel == -1) { 1902 outError[0] = "<permission> does not specify protectionLevel"; 1903 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1904 return null; 1905 } 1906 1907 perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel); 1908 1909 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) { 1910 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) != 1911 PermissionInfo.PROTECTION_SIGNATURE) { 1912 outError[0] = "<permission> protectionLevel specifies a flag but is " 1913 + "not based on signature type"; 1914 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1915 return null; 1916 } 1917 } 1918 1919 if (!parseAllMetaData(res, parser, attrs, "<permission>", perm, 1920 outError)) { 1921 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1922 return null; 1923 } 1924 1925 owner.permissions.add(perm); 1926 1927 return perm; 1928 } 1929 1930 private Permission parsePermissionTree(Package owner, Resources res, 1931 XmlPullParser parser, AttributeSet attrs, String[] outError) 1932 throws XmlPullParserException, IOException { 1933 Permission perm = new Permission(owner); 1934 1935 TypedArray sa = res.obtainAttributes(attrs, 1936 com.android.internal.R.styleable.AndroidManifestPermissionTree); 1937 1938 if (!parsePackageItemInfo(owner, perm.info, outError, 1939 "<permission-tree>", sa, 1940 com.android.internal.R.styleable.AndroidManifestPermissionTree_name, 1941 com.android.internal.R.styleable.AndroidManifestPermissionTree_label, 1942 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon, 1943 com.android.internal.R.styleable.AndroidManifestPermissionTree_logo, 1944 com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) { 1945 sa.recycle(); 1946 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1947 return null; 1948 } 1949 1950 sa.recycle(); 1951 1952 int index = perm.info.name.indexOf('.'); 1953 if (index > 0) { 1954 index = perm.info.name.indexOf('.', index+1); 1955 } 1956 if (index < 0) { 1957 outError[0] = "<permission-tree> name has less than three segments: " 1958 + perm.info.name; 1959 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1960 return null; 1961 } 1962 1963 perm.info.descriptionRes = 0; 1964 perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL; 1965 perm.tree = true; 1966 1967 if (!parseAllMetaData(res, parser, attrs, "<permission-tree>", perm, 1968 outError)) { 1969 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1970 return null; 1971 } 1972 1973 owner.permissions.add(perm); 1974 1975 return perm; 1976 } 1977 1978 private Instrumentation parseInstrumentation(Package owner, Resources res, 1979 XmlPullParser parser, AttributeSet attrs, String[] outError) 1980 throws XmlPullParserException, IOException { 1981 TypedArray sa = res.obtainAttributes(attrs, 1982 com.android.internal.R.styleable.AndroidManifestInstrumentation); 1983 1984 if (mParseInstrumentationArgs == null) { 1985 mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError, 1986 com.android.internal.R.styleable.AndroidManifestInstrumentation_name, 1987 com.android.internal.R.styleable.AndroidManifestInstrumentation_label, 1988 com.android.internal.R.styleable.AndroidManifestInstrumentation_icon, 1989 com.android.internal.R.styleable.AndroidManifestInstrumentation_logo, 1990 com.android.internal.R.styleable.AndroidManifestInstrumentation_banner); 1991 mParseInstrumentationArgs.tag = "<instrumentation>"; 1992 } 1993 1994 mParseInstrumentationArgs.sa = sa; 1995 1996 Instrumentation a = new Instrumentation(mParseInstrumentationArgs, 1997 new InstrumentationInfo()); 1998 if (outError[0] != null) { 1999 sa.recycle(); 2000 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2001 return null; 2002 } 2003 2004 String str; 2005 // Note: don't allow this value to be a reference to a resource 2006 // that may change. 2007 str = sa.getNonResourceString( 2008 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage); 2009 a.info.targetPackage = str != null ? str.intern() : null; 2010 2011 a.info.handleProfiling = sa.getBoolean( 2012 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling, 2013 false); 2014 2015 a.info.functionalTest = sa.getBoolean( 2016 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest, 2017 false); 2018 2019 sa.recycle(); 2020 2021 if (a.info.targetPackage == null) { 2022 outError[0] = "<instrumentation> does not specify targetPackage"; 2023 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2024 return null; 2025 } 2026 2027 if (!parseAllMetaData(res, parser, attrs, "<instrumentation>", a, 2028 outError)) { 2029 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2030 return null; 2031 } 2032 2033 owner.instrumentation.add(a); 2034 2035 return a; 2036 } 2037 2038 private boolean parseApplication(Package owner, Resources res, 2039 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 2040 throws XmlPullParserException, IOException { 2041 final ApplicationInfo ai = owner.applicationInfo; 2042 final String pkgName = owner.applicationInfo.packageName; 2043 2044 TypedArray sa = res.obtainAttributes(attrs, 2045 com.android.internal.R.styleable.AndroidManifestApplication); 2046 2047 String name = sa.getNonConfigurationString( 2048 com.android.internal.R.styleable.AndroidManifestApplication_name, 0); 2049 if (name != null) { 2050 ai.className = buildClassName(pkgName, name, outError); 2051 if (ai.className == null) { 2052 sa.recycle(); 2053 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2054 return false; 2055 } 2056 } 2057 2058 String manageSpaceActivity = sa.getNonConfigurationString( 2059 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity, 2060 Configuration.NATIVE_CONFIG_VERSION); 2061 if (manageSpaceActivity != null) { 2062 ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity, 2063 outError); 2064 } 2065 2066 boolean allowBackup = sa.getBoolean( 2067 com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true); 2068 if (allowBackup) { 2069 ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; 2070 2071 // backupAgent, killAfterRestore, and restoreAnyVersion are only relevant 2072 // if backup is possible for the given application. 2073 String backupAgent = sa.getNonConfigurationString( 2074 com.android.internal.R.styleable.AndroidManifestApplication_backupAgent, 2075 Configuration.NATIVE_CONFIG_VERSION); 2076 if (backupAgent != null) { 2077 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError); 2078 if (DEBUG_BACKUP) { 2079 Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName 2080 + " from " + pkgName + "+" + backupAgent); 2081 } 2082 2083 if (sa.getBoolean( 2084 com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore, 2085 true)) { 2086 ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE; 2087 } 2088 if (sa.getBoolean( 2089 com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion, 2090 false)) { 2091 ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION; 2092 } 2093 } 2094 } 2095 2096 TypedValue v = sa.peekValue( 2097 com.android.internal.R.styleable.AndroidManifestApplication_label); 2098 if (v != null && (ai.labelRes=v.resourceId) == 0) { 2099 ai.nonLocalizedLabel = v.coerceToString(); 2100 } 2101 2102 ai.icon = sa.getResourceId( 2103 com.android.internal.R.styleable.AndroidManifestApplication_icon, 0); 2104 ai.logo = sa.getResourceId( 2105 com.android.internal.R.styleable.AndroidManifestApplication_logo, 0); 2106 ai.banner = sa.getResourceId( 2107 com.android.internal.R.styleable.AndroidManifestApplication_banner, 0); 2108 ai.theme = sa.getResourceId( 2109 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); 2110 ai.descriptionRes = sa.getResourceId( 2111 com.android.internal.R.styleable.AndroidManifestApplication_description, 0); 2112 2113 if ((flags&PARSE_IS_SYSTEM) != 0) { 2114 if (sa.getBoolean( 2115 com.android.internal.R.styleable.AndroidManifestApplication_persistent, 2116 false)) { 2117 ai.flags |= ApplicationInfo.FLAG_PERSISTENT; 2118 } 2119 } 2120 2121 if (sa.getBoolean( 2122 com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers, 2123 false)) { 2124 owner.mRequiredForAllUsers = true; 2125 } 2126 owner.mRequiredForProfile = sa.getInt( 2127 com.android.internal.R.styleable.AndroidManifestApplication_requiredForProfile, 0); 2128 2129 String restrictedAccountType = sa.getString(com.android.internal.R.styleable 2130 .AndroidManifestApplication_restrictedAccountType); 2131 if (restrictedAccountType != null && restrictedAccountType.length() > 0) { 2132 owner.mRestrictedAccountType = restrictedAccountType; 2133 } 2134 2135 String requiredAccountType = sa.getString(com.android.internal.R.styleable 2136 .AndroidManifestApplication_requiredAccountType); 2137 if (requiredAccountType != null && requiredAccountType.length() > 0) { 2138 owner.mRequiredAccountType = requiredAccountType; 2139 } 2140 2141 if (sa.getBoolean( 2142 com.android.internal.R.styleable.AndroidManifestApplication_debuggable, 2143 false)) { 2144 ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE; 2145 } 2146 2147 if (sa.getBoolean( 2148 com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode, 2149 false)) { 2150 ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE; 2151 } 2152 2153 boolean hardwareAccelerated = sa.getBoolean( 2154 com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated, 2155 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH); 2156 2157 if (sa.getBoolean( 2158 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, 2159 true)) { 2160 ai.flags |= ApplicationInfo.FLAG_HAS_CODE; 2161 } 2162 2163 if (sa.getBoolean( 2164 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting, 2165 false)) { 2166 ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; 2167 } 2168 2169 if (sa.getBoolean( 2170 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData, 2171 true)) { 2172 ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; 2173 } 2174 2175 if (sa.getBoolean( 2176 com.android.internal.R.styleable.AndroidManifestApplication_testOnly, 2177 false)) { 2178 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY; 2179 } 2180 2181 if (sa.getBoolean( 2182 com.android.internal.R.styleable.AndroidManifestApplication_largeHeap, 2183 false)) { 2184 ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP; 2185 } 2186 2187 if (sa.getBoolean( 2188 com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl, 2189 false /* default is no RTL support*/)) { 2190 ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL; 2191 } 2192 2193 String str; 2194 str = sa.getNonConfigurationString( 2195 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0); 2196 ai.permission = (str != null && str.length() > 0) ? str.intern() : null; 2197 2198 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 2199 str = sa.getNonConfigurationString( 2200 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, 2201 Configuration.NATIVE_CONFIG_VERSION); 2202 } else { 2203 // Some older apps have been seen to use a resource reference 2204 // here that on older builds was ignored (with a warning). We 2205 // need to continue to do this for them so they don't break. 2206 str = sa.getNonResourceString( 2207 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity); 2208 } 2209 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName, 2210 str, outError); 2211 2212 if (outError[0] == null) { 2213 CharSequence pname; 2214 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 2215 pname = sa.getNonConfigurationString( 2216 com.android.internal.R.styleable.AndroidManifestApplication_process, 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 pname = sa.getNonResourceString( 2223 com.android.internal.R.styleable.AndroidManifestApplication_process); 2224 } 2225 ai.processName = buildProcessName(ai.packageName, null, pname, 2226 flags, mSeparateProcesses, outError); 2227 2228 ai.enabled = sa.getBoolean( 2229 com.android.internal.R.styleable.AndroidManifestApplication_enabled, true); 2230 2231 if (sa.getBoolean( 2232 com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) { 2233 ai.flags |= ApplicationInfo.FLAG_IS_GAME; 2234 } 2235 2236 if (false) { 2237 if (sa.getBoolean( 2238 com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState, 2239 false)) { 2240 ai.flags |= ApplicationInfo.FLAG_CANT_SAVE_STATE; 2241 2242 // A heavy-weight application can not be in a custom process. 2243 // We can do direct compare because we intern all strings. 2244 if (ai.processName != null && ai.processName != ai.packageName) { 2245 outError[0] = "cantSaveState applications can not use custom processes"; 2246 } 2247 } 2248 } 2249 } 2250 2251 ai.uiOptions = sa.getInt( 2252 com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0); 2253 2254 sa.recycle(); 2255 2256 if (outError[0] != null) { 2257 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2258 return false; 2259 } 2260 2261 final int innerDepth = parser.getDepth(); 2262 int type; 2263 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 2264 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 2265 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2266 continue; 2267 } 2268 2269 String tagName = parser.getName(); 2270 if (tagName.equals("activity")) { 2271 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false, 2272 hardwareAccelerated); 2273 if (a == null) { 2274 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2275 return false; 2276 } 2277 2278 owner.activities.add(a); 2279 2280 } else if (tagName.equals("receiver")) { 2281 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false); 2282 if (a == null) { 2283 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2284 return false; 2285 } 2286 2287 owner.receivers.add(a); 2288 2289 } else if (tagName.equals("service")) { 2290 Service s = parseService(owner, res, parser, attrs, flags, outError); 2291 if (s == null) { 2292 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2293 return false; 2294 } 2295 2296 owner.services.add(s); 2297 2298 } else if (tagName.equals("provider")) { 2299 Provider p = parseProvider(owner, res, parser, attrs, flags, outError); 2300 if (p == null) { 2301 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2302 return false; 2303 } 2304 2305 owner.providers.add(p); 2306 2307 } else if (tagName.equals("activity-alias")) { 2308 Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError); 2309 if (a == null) { 2310 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2311 return false; 2312 } 2313 2314 owner.activities.add(a); 2315 2316 } else if (parser.getName().equals("meta-data")) { 2317 // note: application meta-data is stored off to the side, so it can 2318 // remain null in the primary copy (we like to avoid extra copies because 2319 // it can be large) 2320 if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData, 2321 outError)) == null) { 2322 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2323 return false; 2324 } 2325 2326 } else if (tagName.equals("library")) { 2327 sa = res.obtainAttributes(attrs, 2328 com.android.internal.R.styleable.AndroidManifestLibrary); 2329 2330 // Note: don't allow this value to be a reference to a resource 2331 // that may change. 2332 String lname = sa.getNonResourceString( 2333 com.android.internal.R.styleable.AndroidManifestLibrary_name); 2334 2335 sa.recycle(); 2336 2337 if (lname != null) { 2338 if (owner.libraryNames == null) { 2339 owner.libraryNames = new ArrayList<String>(); 2340 } 2341 if (!owner.libraryNames.contains(lname)) { 2342 owner.libraryNames.add(lname.intern()); 2343 } 2344 } 2345 2346 XmlUtils.skipCurrentTag(parser); 2347 2348 } else if (tagName.equals("uses-library")) { 2349 sa = res.obtainAttributes(attrs, 2350 com.android.internal.R.styleable.AndroidManifestUsesLibrary); 2351 2352 // Note: don't allow this value to be a reference to a resource 2353 // that may change. 2354 String lname = sa.getNonResourceString( 2355 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 2356 boolean req = sa.getBoolean( 2357 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, 2358 true); 2359 2360 sa.recycle(); 2361 2362 if (lname != null) { 2363 if (req) { 2364 if (owner.usesLibraries == null) { 2365 owner.usesLibraries = new ArrayList<String>(); 2366 } 2367 if (!owner.usesLibraries.contains(lname)) { 2368 owner.usesLibraries.add(lname.intern()); 2369 } 2370 } else { 2371 if (owner.usesOptionalLibraries == null) { 2372 owner.usesOptionalLibraries = new ArrayList<String>(); 2373 } 2374 if (!owner.usesOptionalLibraries.contains(lname)) { 2375 owner.usesOptionalLibraries.add(lname.intern()); 2376 } 2377 } 2378 } 2379 2380 XmlUtils.skipCurrentTag(parser); 2381 2382 } else if (tagName.equals("uses-package")) { 2383 // Dependencies for app installers; we don't currently try to 2384 // enforce this. 2385 XmlUtils.skipCurrentTag(parser); 2386 2387 } else { 2388 if (!RIGID_PARSER) { 2389 Slog.w(TAG, "Unknown element under <application>: " + tagName 2390 + " at " + mArchiveSourcePath + " " 2391 + parser.getPositionDescription()); 2392 XmlUtils.skipCurrentTag(parser); 2393 continue; 2394 } else { 2395 outError[0] = "Bad element under <application>: " + tagName; 2396 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2397 return false; 2398 } 2399 } 2400 } 2401 2402 return true; 2403 } 2404 2405 private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo, 2406 String[] outError, String tag, TypedArray sa, 2407 int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) { 2408 String name = sa.getNonConfigurationString(nameRes, 0); 2409 if (name == null) { 2410 outError[0] = tag + " does not specify android:name"; 2411 return false; 2412 } 2413 2414 outInfo.name 2415 = buildClassName(owner.applicationInfo.packageName, name, outError); 2416 if (outInfo.name == null) { 2417 return false; 2418 } 2419 2420 int iconVal = sa.getResourceId(iconRes, 0); 2421 if (iconVal != 0) { 2422 outInfo.icon = iconVal; 2423 outInfo.nonLocalizedLabel = null; 2424 } 2425 2426 int logoVal = sa.getResourceId(logoRes, 0); 2427 if (logoVal != 0) { 2428 outInfo.logo = logoVal; 2429 } 2430 2431 int bannerVal = sa.getResourceId(bannerRes, 0); 2432 if (bannerVal != 0) { 2433 outInfo.banner = bannerVal; 2434 } 2435 2436 TypedValue v = sa.peekValue(labelRes); 2437 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 2438 outInfo.nonLocalizedLabel = v.coerceToString(); 2439 } 2440 2441 outInfo.packageName = owner.packageName; 2442 2443 return true; 2444 } 2445 2446 private Activity parseActivity(Package owner, Resources res, 2447 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError, 2448 boolean receiver, boolean hardwareAccelerated) 2449 throws XmlPullParserException, IOException { 2450 TypedArray sa = res.obtainAttributes(attrs, 2451 com.android.internal.R.styleable.AndroidManifestActivity); 2452 2453 if (mParseActivityArgs == null) { 2454 mParseActivityArgs = new ParseComponentArgs(owner, outError, 2455 com.android.internal.R.styleable.AndroidManifestActivity_name, 2456 com.android.internal.R.styleable.AndroidManifestActivity_label, 2457 com.android.internal.R.styleable.AndroidManifestActivity_icon, 2458 com.android.internal.R.styleable.AndroidManifestActivity_logo, 2459 com.android.internal.R.styleable.AndroidManifestActivity_banner, 2460 mSeparateProcesses, 2461 com.android.internal.R.styleable.AndroidManifestActivity_process, 2462 com.android.internal.R.styleable.AndroidManifestActivity_description, 2463 com.android.internal.R.styleable.AndroidManifestActivity_enabled); 2464 } 2465 2466 mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>"; 2467 mParseActivityArgs.sa = sa; 2468 mParseActivityArgs.flags = flags; 2469 2470 Activity a = new Activity(mParseActivityArgs, new ActivityInfo()); 2471 if (outError[0] != null) { 2472 sa.recycle(); 2473 return null; 2474 } 2475 2476 boolean setExported = sa.hasValue( 2477 com.android.internal.R.styleable.AndroidManifestActivity_exported); 2478 if (setExported) { 2479 a.info.exported = sa.getBoolean( 2480 com.android.internal.R.styleable.AndroidManifestActivity_exported, false); 2481 } 2482 2483 a.info.theme = sa.getResourceId( 2484 com.android.internal.R.styleable.AndroidManifestActivity_theme, 0); 2485 2486 a.info.uiOptions = sa.getInt( 2487 com.android.internal.R.styleable.AndroidManifestActivity_uiOptions, 2488 a.info.applicationInfo.uiOptions); 2489 2490 String parentName = sa.getNonConfigurationString( 2491 com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName, 2492 Configuration.NATIVE_CONFIG_VERSION); 2493 if (parentName != null) { 2494 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 2495 if (outError[0] == null) { 2496 a.info.parentActivityName = parentClassName; 2497 } else { 2498 Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " + 2499 parentName); 2500 outError[0] = null; 2501 } 2502 } 2503 2504 String str; 2505 str = sa.getNonConfigurationString( 2506 com.android.internal.R.styleable.AndroidManifestActivity_permission, 0); 2507 if (str == null) { 2508 a.info.permission = owner.applicationInfo.permission; 2509 } else { 2510 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 2511 } 2512 2513 str = sa.getNonConfigurationString( 2514 com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity, 2515 Configuration.NATIVE_CONFIG_VERSION); 2516 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName, 2517 owner.applicationInfo.taskAffinity, str, outError); 2518 2519 a.info.flags = 0; 2520 if (sa.getBoolean( 2521 com.android.internal.R.styleable.AndroidManifestActivity_multiprocess, 2522 false)) { 2523 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS; 2524 } 2525 2526 if (sa.getBoolean( 2527 com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch, 2528 false)) { 2529 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; 2530 } 2531 2532 if (sa.getBoolean( 2533 com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch, 2534 false)) { 2535 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; 2536 } 2537 2538 if (sa.getBoolean( 2539 com.android.internal.R.styleable.AndroidManifestActivity_noHistory, 2540 false)) { 2541 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY; 2542 } 2543 2544 if (sa.getBoolean( 2545 com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState, 2546 false)) { 2547 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; 2548 } 2549 2550 if (sa.getBoolean( 2551 com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded, 2552 false)) { 2553 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; 2554 } 2555 2556 if (sa.getBoolean( 2557 com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents, 2558 false)) { 2559 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; 2560 } 2561 2562 if (sa.getBoolean( 2563 com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting, 2564 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) { 2565 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; 2566 } 2567 2568 if (sa.getBoolean( 2569 com.android.internal.R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, 2570 false)) { 2571 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; 2572 } 2573 2574 if (sa.getBoolean( 2575 com.android.internal.R.styleable.AndroidManifestActivity_showOnLockScreen, 2576 false)) { 2577 a.info.flags |= ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN; 2578 } 2579 2580 if (sa.getBoolean( 2581 com.android.internal.R.styleable.AndroidManifestActivity_immersive, 2582 false)) { 2583 a.info.flags |= ActivityInfo.FLAG_IMMERSIVE; 2584 } 2585 2586 if (!receiver) { 2587 if (sa.getBoolean( 2588 com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated, 2589 hardwareAccelerated)) { 2590 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; 2591 } 2592 2593 a.info.launchMode = sa.getInt( 2594 com.android.internal.R.styleable.AndroidManifestActivity_launchMode, 2595 ActivityInfo.LAUNCH_MULTIPLE); 2596 a.info.documentLaunchMode = sa.getInt( 2597 com.android.internal.R.styleable.AndroidManifestActivity_documentLaunchMode, 2598 ActivityInfo.DOCUMENT_LAUNCH_NONE); 2599 a.info.maxRecents = sa.getInt( 2600 com.android.internal.R.styleable.AndroidManifestActivity_maxRecents, 2601 15); 2602 a.info.screenOrientation = sa.getInt( 2603 com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation, 2604 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 2605 a.info.configChanges = sa.getInt( 2606 com.android.internal.R.styleable.AndroidManifestActivity_configChanges, 2607 0); 2608 a.info.softInputMode = sa.getInt( 2609 com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode, 2610 0); 2611 2612 a.info.persistableMode = sa.getInteger( 2613 com.android.internal.R.styleable.AndroidManifestActivity_persistableMode, 2614 ActivityInfo.PERSIST_ROOT_ONLY); 2615 2616 if (sa.getBoolean( 2617 com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded, 2618 false)) { 2619 a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED; 2620 } 2621 2622 if (sa.getBoolean( 2623 com.android.internal.R.styleable.AndroidManifestActivity_autoRemoveFromRecents, 2624 false)) { 2625 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS; 2626 } 2627 } else { 2628 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; 2629 a.info.configChanges = 0; 2630 } 2631 2632 if (receiver) { 2633 if (sa.getBoolean( 2634 com.android.internal.R.styleable.AndroidManifestActivity_singleUser, 2635 false)) { 2636 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER; 2637 if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 2638 Slog.w(TAG, "Activity exported request ignored due to singleUser: " 2639 + a.className + " at " + mArchiveSourcePath + " " 2640 + parser.getPositionDescription()); 2641 a.info.exported = false; 2642 setExported = true; 2643 } 2644 } 2645 if (sa.getBoolean( 2646 com.android.internal.R.styleable.AndroidManifestActivity_primaryUserOnly, 2647 false)) { 2648 a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY; 2649 } 2650 } 2651 2652 sa.recycle(); 2653 2654 if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { 2655 // A heavy-weight application can not have receives in its main process 2656 // We can do direct compare because we intern all strings. 2657 if (a.info.processName == owner.packageName) { 2658 outError[0] = "Heavy-weight applications can not have receivers in main process"; 2659 } 2660 } 2661 2662 if (outError[0] != null) { 2663 return null; 2664 } 2665 2666 int outerDepth = parser.getDepth(); 2667 int type; 2668 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2669 && (type != XmlPullParser.END_TAG 2670 || parser.getDepth() > outerDepth)) { 2671 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2672 continue; 2673 } 2674 2675 if (parser.getName().equals("intent-filter")) { 2676 ActivityIntentInfo intent = new ActivityIntentInfo(a); 2677 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 2678 return null; 2679 } 2680 if (intent.countActions() == 0) { 2681 Slog.w(TAG, "No actions in intent filter at " 2682 + mArchiveSourcePath + " " 2683 + parser.getPositionDescription()); 2684 } else { 2685 a.intents.add(intent); 2686 } 2687 } else if (!receiver && parser.getName().equals("preferred")) { 2688 ActivityIntentInfo intent = new ActivityIntentInfo(a); 2689 if (!parseIntent(res, parser, attrs, false, intent, outError)) { 2690 return null; 2691 } 2692 if (intent.countActions() == 0) { 2693 Slog.w(TAG, "No actions in preferred at " 2694 + mArchiveSourcePath + " " 2695 + parser.getPositionDescription()); 2696 } else { 2697 if (owner.preferredActivityFilters == null) { 2698 owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>(); 2699 } 2700 owner.preferredActivityFilters.add(intent); 2701 } 2702 } else if (parser.getName().equals("meta-data")) { 2703 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData, 2704 outError)) == null) { 2705 return null; 2706 } 2707 } else { 2708 if (!RIGID_PARSER) { 2709 Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 2710 if (receiver) { 2711 Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName() 2712 + " at " + mArchiveSourcePath + " " 2713 + parser.getPositionDescription()); 2714 } else { 2715 Slog.w(TAG, "Unknown element under <activity>: " + parser.getName() 2716 + " at " + mArchiveSourcePath + " " 2717 + parser.getPositionDescription()); 2718 } 2719 XmlUtils.skipCurrentTag(parser); 2720 continue; 2721 } else { 2722 if (receiver) { 2723 outError[0] = "Bad element under <receiver>: " + parser.getName(); 2724 } else { 2725 outError[0] = "Bad element under <activity>: " + parser.getName(); 2726 } 2727 return null; 2728 } 2729 } 2730 } 2731 2732 if (!setExported) { 2733 a.info.exported = a.intents.size() > 0; 2734 } 2735 2736 return a; 2737 } 2738 2739 private Activity parseActivityAlias(Package owner, Resources res, 2740 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 2741 throws XmlPullParserException, IOException { 2742 TypedArray sa = res.obtainAttributes(attrs, 2743 com.android.internal.R.styleable.AndroidManifestActivityAlias); 2744 2745 String targetActivity = sa.getNonConfigurationString( 2746 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity, 2747 Configuration.NATIVE_CONFIG_VERSION); 2748 if (targetActivity == null) { 2749 outError[0] = "<activity-alias> does not specify android:targetActivity"; 2750 sa.recycle(); 2751 return null; 2752 } 2753 2754 targetActivity = buildClassName(owner.applicationInfo.packageName, 2755 targetActivity, outError); 2756 if (targetActivity == null) { 2757 sa.recycle(); 2758 return null; 2759 } 2760 2761 if (mParseActivityAliasArgs == null) { 2762 mParseActivityAliasArgs = new ParseComponentArgs(owner, outError, 2763 com.android.internal.R.styleable.AndroidManifestActivityAlias_name, 2764 com.android.internal.R.styleable.AndroidManifestActivityAlias_label, 2765 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, 2766 com.android.internal.R.styleable.AndroidManifestActivityAlias_logo, 2767 com.android.internal.R.styleable.AndroidManifestActivityAlias_banner, 2768 mSeparateProcesses, 2769 0, 2770 com.android.internal.R.styleable.AndroidManifestActivityAlias_description, 2771 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled); 2772 mParseActivityAliasArgs.tag = "<activity-alias>"; 2773 } 2774 2775 mParseActivityAliasArgs.sa = sa; 2776 mParseActivityAliasArgs.flags = flags; 2777 2778 Activity target = null; 2779 2780 final int NA = owner.activities.size(); 2781 for (int i=0; i<NA; i++) { 2782 Activity t = owner.activities.get(i); 2783 if (targetActivity.equals(t.info.name)) { 2784 target = t; 2785 break; 2786 } 2787 } 2788 2789 if (target == null) { 2790 outError[0] = "<activity-alias> target activity " + targetActivity 2791 + " not found in manifest"; 2792 sa.recycle(); 2793 return null; 2794 } 2795 2796 ActivityInfo info = new ActivityInfo(); 2797 info.targetActivity = targetActivity; 2798 info.configChanges = target.info.configChanges; 2799 info.flags = target.info.flags; 2800 info.icon = target.info.icon; 2801 info.logo = target.info.logo; 2802 info.banner = target.info.banner; 2803 info.labelRes = target.info.labelRes; 2804 info.nonLocalizedLabel = target.info.nonLocalizedLabel; 2805 info.launchMode = target.info.launchMode; 2806 info.processName = target.info.processName; 2807 if (info.descriptionRes == 0) { 2808 info.descriptionRes = target.info.descriptionRes; 2809 } 2810 info.screenOrientation = target.info.screenOrientation; 2811 info.taskAffinity = target.info.taskAffinity; 2812 info.theme = target.info.theme; 2813 info.softInputMode = target.info.softInputMode; 2814 info.uiOptions = target.info.uiOptions; 2815 info.parentActivityName = target.info.parentActivityName; 2816 2817 Activity a = new Activity(mParseActivityAliasArgs, info); 2818 if (outError[0] != null) { 2819 sa.recycle(); 2820 return null; 2821 } 2822 2823 final boolean setExported = sa.hasValue( 2824 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported); 2825 if (setExported) { 2826 a.info.exported = sa.getBoolean( 2827 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false); 2828 } 2829 2830 String str; 2831 str = sa.getNonConfigurationString( 2832 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0); 2833 if (str != null) { 2834 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 2835 } 2836 2837 String parentName = sa.getNonConfigurationString( 2838 com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName, 2839 Configuration.NATIVE_CONFIG_VERSION); 2840 if (parentName != null) { 2841 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 2842 if (outError[0] == null) { 2843 a.info.parentActivityName = parentClassName; 2844 } else { 2845 Log.e(TAG, "Activity alias " + a.info.name + 2846 " specified invalid parentActivityName " + parentName); 2847 outError[0] = null; 2848 } 2849 } 2850 2851 sa.recycle(); 2852 2853 if (outError[0] != null) { 2854 return null; 2855 } 2856 2857 int outerDepth = parser.getDepth(); 2858 int type; 2859 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2860 && (type != XmlPullParser.END_TAG 2861 || parser.getDepth() > outerDepth)) { 2862 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2863 continue; 2864 } 2865 2866 if (parser.getName().equals("intent-filter")) { 2867 ActivityIntentInfo intent = new ActivityIntentInfo(a); 2868 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 2869 return null; 2870 } 2871 if (intent.countActions() == 0) { 2872 Slog.w(TAG, "No actions in intent filter at " 2873 + mArchiveSourcePath + " " 2874 + parser.getPositionDescription()); 2875 } else { 2876 a.intents.add(intent); 2877 } 2878 } else if (parser.getName().equals("meta-data")) { 2879 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData, 2880 outError)) == null) { 2881 return null; 2882 } 2883 } else { 2884 if (!RIGID_PARSER) { 2885 Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName() 2886 + " at " + mArchiveSourcePath + " " 2887 + parser.getPositionDescription()); 2888 XmlUtils.skipCurrentTag(parser); 2889 continue; 2890 } else { 2891 outError[0] = "Bad element under <activity-alias>: " + parser.getName(); 2892 return null; 2893 } 2894 } 2895 } 2896 2897 if (!setExported) { 2898 a.info.exported = a.intents.size() > 0; 2899 } 2900 2901 return a; 2902 } 2903 2904 private Provider parseProvider(Package owner, Resources res, 2905 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 2906 throws XmlPullParserException, IOException { 2907 TypedArray sa = res.obtainAttributes(attrs, 2908 com.android.internal.R.styleable.AndroidManifestProvider); 2909 2910 if (mParseProviderArgs == null) { 2911 mParseProviderArgs = new ParseComponentArgs(owner, outError, 2912 com.android.internal.R.styleable.AndroidManifestProvider_name, 2913 com.android.internal.R.styleable.AndroidManifestProvider_label, 2914 com.android.internal.R.styleable.AndroidManifestProvider_icon, 2915 com.android.internal.R.styleable.AndroidManifestProvider_logo, 2916 com.android.internal.R.styleable.AndroidManifestProvider_banner, 2917 mSeparateProcesses, 2918 com.android.internal.R.styleable.AndroidManifestProvider_process, 2919 com.android.internal.R.styleable.AndroidManifestProvider_description, 2920 com.android.internal.R.styleable.AndroidManifestProvider_enabled); 2921 mParseProviderArgs.tag = "<provider>"; 2922 } 2923 2924 mParseProviderArgs.sa = sa; 2925 mParseProviderArgs.flags = flags; 2926 2927 Provider p = new Provider(mParseProviderArgs, new ProviderInfo()); 2928 if (outError[0] != null) { 2929 sa.recycle(); 2930 return null; 2931 } 2932 2933 boolean providerExportedDefault = false; 2934 2935 if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 2936 // For compatibility, applications targeting API level 16 or lower 2937 // should have their content providers exported by default, unless they 2938 // specify otherwise. 2939 providerExportedDefault = true; 2940 } 2941 2942 p.info.exported = sa.getBoolean( 2943 com.android.internal.R.styleable.AndroidManifestProvider_exported, 2944 providerExportedDefault); 2945 2946 String cpname = sa.getNonConfigurationString( 2947 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0); 2948 2949 p.info.isSyncable = sa.getBoolean( 2950 com.android.internal.R.styleable.AndroidManifestProvider_syncable, 2951 false); 2952 2953 String permission = sa.getNonConfigurationString( 2954 com.android.internal.R.styleable.AndroidManifestProvider_permission, 0); 2955 String str = sa.getNonConfigurationString( 2956 com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0); 2957 if (str == null) { 2958 str = permission; 2959 } 2960 if (str == null) { 2961 p.info.readPermission = owner.applicationInfo.permission; 2962 } else { 2963 p.info.readPermission = 2964 str.length() > 0 ? str.toString().intern() : null; 2965 } 2966 str = sa.getNonConfigurationString( 2967 com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0); 2968 if (str == null) { 2969 str = permission; 2970 } 2971 if (str == null) { 2972 p.info.writePermission = owner.applicationInfo.permission; 2973 } else { 2974 p.info.writePermission = 2975 str.length() > 0 ? str.toString().intern() : null; 2976 } 2977 2978 p.info.grantUriPermissions = sa.getBoolean( 2979 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions, 2980 false); 2981 2982 p.info.multiprocess = sa.getBoolean( 2983 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess, 2984 false); 2985 2986 p.info.initOrder = sa.getInt( 2987 com.android.internal.R.styleable.AndroidManifestProvider_initOrder, 2988 0); 2989 2990 p.info.flags = 0; 2991 2992 if (sa.getBoolean( 2993 com.android.internal.R.styleable.AndroidManifestProvider_singleUser, 2994 false)) { 2995 p.info.flags |= ProviderInfo.FLAG_SINGLE_USER; 2996 if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 2997 Slog.w(TAG, "Provider exported request ignored due to singleUser: " 2998 + p.className + " at " + mArchiveSourcePath + " " 2999 + parser.getPositionDescription()); 3000 p.info.exported = false; 3001 } 3002 } 3003 3004 sa.recycle(); 3005 3006 if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { 3007 // A heavy-weight application can not have providers in its main process 3008 // We can do direct compare because we intern all strings. 3009 if (p.info.processName == owner.packageName) { 3010 outError[0] = "Heavy-weight applications can not have providers in main process"; 3011 return null; 3012 } 3013 } 3014 3015 if (cpname == null) { 3016 outError[0] = "<provider> does not include authorities attribute"; 3017 return null; 3018 } 3019 p.info.authority = cpname.intern(); 3020 3021 if (!parseProviderTags(res, parser, attrs, p, outError)) { 3022 return null; 3023 } 3024 3025 return p; 3026 } 3027 3028 private boolean parseProviderTags(Resources res, 3029 XmlPullParser parser, AttributeSet attrs, 3030 Provider outInfo, String[] outError) 3031 throws XmlPullParserException, IOException { 3032 int outerDepth = parser.getDepth(); 3033 int type; 3034 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3035 && (type != XmlPullParser.END_TAG 3036 || parser.getDepth() > outerDepth)) { 3037 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3038 continue; 3039 } 3040 3041 if (parser.getName().equals("intent-filter")) { 3042 ProviderIntentInfo intent = new ProviderIntentInfo(outInfo); 3043 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 3044 return false; 3045 } 3046 outInfo.intents.add(intent); 3047 3048 } else if (parser.getName().equals("meta-data")) { 3049 if ((outInfo.metaData=parseMetaData(res, parser, attrs, 3050 outInfo.metaData, outError)) == null) { 3051 return false; 3052 } 3053 3054 } else if (parser.getName().equals("grant-uri-permission")) { 3055 TypedArray sa = res.obtainAttributes(attrs, 3056 com.android.internal.R.styleable.AndroidManifestGrantUriPermission); 3057 3058 PatternMatcher pa = null; 3059 3060 String str = sa.getNonConfigurationString( 3061 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0); 3062 if (str != null) { 3063 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); 3064 } 3065 3066 str = sa.getNonConfigurationString( 3067 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); 3068 if (str != null) { 3069 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); 3070 } 3071 3072 str = sa.getNonConfigurationString( 3073 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); 3074 if (str != null) { 3075 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 3076 } 3077 3078 sa.recycle(); 3079 3080 if (pa != null) { 3081 if (outInfo.info.uriPermissionPatterns == null) { 3082 outInfo.info.uriPermissionPatterns = new PatternMatcher[1]; 3083 outInfo.info.uriPermissionPatterns[0] = pa; 3084 } else { 3085 final int N = outInfo.info.uriPermissionPatterns.length; 3086 PatternMatcher[] newp = new PatternMatcher[N+1]; 3087 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N); 3088 newp[N] = pa; 3089 outInfo.info.uriPermissionPatterns = newp; 3090 } 3091 outInfo.info.grantUriPermissions = true; 3092 } else { 3093 if (!RIGID_PARSER) { 3094 Slog.w(TAG, "Unknown element under <path-permission>: " 3095 + parser.getName() + " at " + mArchiveSourcePath + " " 3096 + parser.getPositionDescription()); 3097 XmlUtils.skipCurrentTag(parser); 3098 continue; 3099 } else { 3100 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 3101 return false; 3102 } 3103 } 3104 XmlUtils.skipCurrentTag(parser); 3105 3106 } else if (parser.getName().equals("path-permission")) { 3107 TypedArray sa = res.obtainAttributes(attrs, 3108 com.android.internal.R.styleable.AndroidManifestPathPermission); 3109 3110 PathPermission pa = null; 3111 3112 String permission = sa.getNonConfigurationString( 3113 com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0); 3114 String readPermission = sa.getNonConfigurationString( 3115 com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0); 3116 if (readPermission == null) { 3117 readPermission = permission; 3118 } 3119 String writePermission = sa.getNonConfigurationString( 3120 com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0); 3121 if (writePermission == null) { 3122 writePermission = permission; 3123 } 3124 3125 boolean havePerm = false; 3126 if (readPermission != null) { 3127 readPermission = readPermission.intern(); 3128 havePerm = true; 3129 } 3130 if (writePermission != null) { 3131 writePermission = writePermission.intern(); 3132 havePerm = true; 3133 } 3134 3135 if (!havePerm) { 3136 if (!RIGID_PARSER) { 3137 Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: " 3138 + parser.getName() + " at " + mArchiveSourcePath + " " 3139 + parser.getPositionDescription()); 3140 XmlUtils.skipCurrentTag(parser); 3141 continue; 3142 } else { 3143 outError[0] = "No readPermission or writePermssion for <path-permission>"; 3144 return false; 3145 } 3146 } 3147 3148 String path = sa.getNonConfigurationString( 3149 com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0); 3150 if (path != null) { 3151 pa = new PathPermission(path, 3152 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission); 3153 } 3154 3155 path = sa.getNonConfigurationString( 3156 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0); 3157 if (path != null) { 3158 pa = new PathPermission(path, 3159 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission); 3160 } 3161 3162 path = sa.getNonConfigurationString( 3163 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0); 3164 if (path != null) { 3165 pa = new PathPermission(path, 3166 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission); 3167 } 3168 3169 sa.recycle(); 3170 3171 if (pa != null) { 3172 if (outInfo.info.pathPermissions == null) { 3173 outInfo.info.pathPermissions = new PathPermission[1]; 3174 outInfo.info.pathPermissions[0] = pa; 3175 } else { 3176 final int N = outInfo.info.pathPermissions.length; 3177 PathPermission[] newp = new PathPermission[N+1]; 3178 System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N); 3179 newp[N] = pa; 3180 outInfo.info.pathPermissions = newp; 3181 } 3182 } else { 3183 if (!RIGID_PARSER) { 3184 Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: " 3185 + parser.getName() + " at " + mArchiveSourcePath + " " 3186 + parser.getPositionDescription()); 3187 XmlUtils.skipCurrentTag(parser); 3188 continue; 3189 } 3190 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 3191 return false; 3192 } 3193 XmlUtils.skipCurrentTag(parser); 3194 3195 } else { 3196 if (!RIGID_PARSER) { 3197 Slog.w(TAG, "Unknown element under <provider>: " 3198 + parser.getName() + " at " + mArchiveSourcePath + " " 3199 + parser.getPositionDescription()); 3200 XmlUtils.skipCurrentTag(parser); 3201 continue; 3202 } else { 3203 outError[0] = "Bad element under <provider>: " + parser.getName(); 3204 return false; 3205 } 3206 } 3207 } 3208 return true; 3209 } 3210 3211 private Service parseService(Package owner, Resources res, 3212 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 3213 throws XmlPullParserException, IOException { 3214 TypedArray sa = res.obtainAttributes(attrs, 3215 com.android.internal.R.styleable.AndroidManifestService); 3216 3217 if (mParseServiceArgs == null) { 3218 mParseServiceArgs = new ParseComponentArgs(owner, outError, 3219 com.android.internal.R.styleable.AndroidManifestService_name, 3220 com.android.internal.R.styleable.AndroidManifestService_label, 3221 com.android.internal.R.styleable.AndroidManifestService_icon, 3222 com.android.internal.R.styleable.AndroidManifestService_logo, 3223 com.android.internal.R.styleable.AndroidManifestService_banner, 3224 mSeparateProcesses, 3225 com.android.internal.R.styleable.AndroidManifestService_process, 3226 com.android.internal.R.styleable.AndroidManifestService_description, 3227 com.android.internal.R.styleable.AndroidManifestService_enabled); 3228 mParseServiceArgs.tag = "<service>"; 3229 } 3230 3231 mParseServiceArgs.sa = sa; 3232 mParseServiceArgs.flags = flags; 3233 3234 Service s = new Service(mParseServiceArgs, new ServiceInfo()); 3235 if (outError[0] != null) { 3236 sa.recycle(); 3237 return null; 3238 } 3239 3240 boolean setExported = sa.hasValue( 3241 com.android.internal.R.styleable.AndroidManifestService_exported); 3242 if (setExported) { 3243 s.info.exported = sa.getBoolean( 3244 com.android.internal.R.styleable.AndroidManifestService_exported, false); 3245 } 3246 3247 String str = sa.getNonConfigurationString( 3248 com.android.internal.R.styleable.AndroidManifestService_permission, 0); 3249 if (str == null) { 3250 s.info.permission = owner.applicationInfo.permission; 3251 } else { 3252 s.info.permission = str.length() > 0 ? str.toString().intern() : null; 3253 } 3254 3255 s.info.flags = 0; 3256 if (sa.getBoolean( 3257 com.android.internal.R.styleable.AndroidManifestService_stopWithTask, 3258 false)) { 3259 s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK; 3260 } 3261 if (sa.getBoolean( 3262 com.android.internal.R.styleable.AndroidManifestService_isolatedProcess, 3263 false)) { 3264 s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS; 3265 } 3266 if (sa.getBoolean( 3267 com.android.internal.R.styleable.AndroidManifestService_singleUser, 3268 false)) { 3269 s.info.flags |= ServiceInfo.FLAG_SINGLE_USER; 3270 if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 3271 Slog.w(TAG, "Service exported request ignored due to singleUser: " 3272 + s.className + " at " + mArchiveSourcePath + " " 3273 + parser.getPositionDescription()); 3274 s.info.exported = false; 3275 setExported = true; 3276 } 3277 } 3278 3279 sa.recycle(); 3280 3281 if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { 3282 // A heavy-weight application can not have services in its main process 3283 // We can do direct compare because we intern all strings. 3284 if (s.info.processName == owner.packageName) { 3285 outError[0] = "Heavy-weight applications can not have services in main process"; 3286 return null; 3287 } 3288 } 3289 3290 int outerDepth = parser.getDepth(); 3291 int type; 3292 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3293 && (type != XmlPullParser.END_TAG 3294 || parser.getDepth() > outerDepth)) { 3295 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3296 continue; 3297 } 3298 3299 if (parser.getName().equals("intent-filter")) { 3300 ServiceIntentInfo intent = new ServiceIntentInfo(s); 3301 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 3302 return null; 3303 } 3304 3305 s.intents.add(intent); 3306 } else if (parser.getName().equals("meta-data")) { 3307 if ((s.metaData=parseMetaData(res, parser, attrs, s.metaData, 3308 outError)) == null) { 3309 return null; 3310 } 3311 } else { 3312 if (!RIGID_PARSER) { 3313 Slog.w(TAG, "Unknown element under <service>: " 3314 + parser.getName() + " at " + mArchiveSourcePath + " " 3315 + parser.getPositionDescription()); 3316 XmlUtils.skipCurrentTag(parser); 3317 continue; 3318 } else { 3319 outError[0] = "Bad element under <service>: " + parser.getName(); 3320 return null; 3321 } 3322 } 3323 } 3324 3325 if (!setExported) { 3326 s.info.exported = s.intents.size() > 0; 3327 } 3328 3329 return s; 3330 } 3331 3332 private boolean parseAllMetaData(Resources res, 3333 XmlPullParser parser, AttributeSet attrs, String tag, 3334 Component outInfo, String[] outError) 3335 throws XmlPullParserException, IOException { 3336 int outerDepth = parser.getDepth(); 3337 int type; 3338 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3339 && (type != XmlPullParser.END_TAG 3340 || parser.getDepth() > outerDepth)) { 3341 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3342 continue; 3343 } 3344 3345 if (parser.getName().equals("meta-data")) { 3346 if ((outInfo.metaData=parseMetaData(res, parser, attrs, 3347 outInfo.metaData, outError)) == null) { 3348 return false; 3349 } 3350 } else { 3351 if (!RIGID_PARSER) { 3352 Slog.w(TAG, "Unknown element under " + tag + ": " 3353 + parser.getName() + " at " + mArchiveSourcePath + " " 3354 + parser.getPositionDescription()); 3355 XmlUtils.skipCurrentTag(parser); 3356 continue; 3357 } else { 3358 outError[0] = "Bad element under " + tag + ": " + parser.getName(); 3359 return false; 3360 } 3361 } 3362 } 3363 return true; 3364 } 3365 3366 private Bundle parseMetaData(Resources res, 3367 XmlPullParser parser, AttributeSet attrs, 3368 Bundle data, String[] outError) 3369 throws XmlPullParserException, IOException { 3370 3371 TypedArray sa = res.obtainAttributes(attrs, 3372 com.android.internal.R.styleable.AndroidManifestMetaData); 3373 3374 if (data == null) { 3375 data = new Bundle(); 3376 } 3377 3378 String name = sa.getNonConfigurationString( 3379 com.android.internal.R.styleable.AndroidManifestMetaData_name, 0); 3380 if (name == null) { 3381 outError[0] = "<meta-data> requires an android:name attribute"; 3382 sa.recycle(); 3383 return null; 3384 } 3385 3386 name = name.intern(); 3387 3388 TypedValue v = sa.peekValue( 3389 com.android.internal.R.styleable.AndroidManifestMetaData_resource); 3390 if (v != null && v.resourceId != 0) { 3391 //Slog.i(TAG, "Meta data ref " + name + ": " + v); 3392 data.putInt(name, v.resourceId); 3393 } else { 3394 v = sa.peekValue( 3395 com.android.internal.R.styleable.AndroidManifestMetaData_value); 3396 //Slog.i(TAG, "Meta data " + name + ": " + v); 3397 if (v != null) { 3398 if (v.type == TypedValue.TYPE_STRING) { 3399 CharSequence cs = v.coerceToString(); 3400 data.putString(name, cs != null ? cs.toString().intern() : null); 3401 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { 3402 data.putBoolean(name, v.data != 0); 3403 } else if (v.type >= TypedValue.TYPE_FIRST_INT 3404 && v.type <= TypedValue.TYPE_LAST_INT) { 3405 data.putInt(name, v.data); 3406 } else if (v.type == TypedValue.TYPE_FLOAT) { 3407 data.putFloat(name, v.getFloat()); 3408 } else { 3409 if (!RIGID_PARSER) { 3410 Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: " 3411 + parser.getName() + " at " + mArchiveSourcePath + " " 3412 + parser.getPositionDescription()); 3413 } else { 3414 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types"; 3415 data = null; 3416 } 3417 } 3418 } else { 3419 outError[0] = "<meta-data> requires an android:value or android:resource attribute"; 3420 data = null; 3421 } 3422 } 3423 3424 sa.recycle(); 3425 3426 XmlUtils.skipCurrentTag(parser); 3427 3428 return data; 3429 } 3430 3431 private static VerifierInfo parseVerifier(Resources res, XmlPullParser parser, 3432 AttributeSet attrs, int flags) { 3433 final TypedArray sa = res.obtainAttributes(attrs, 3434 com.android.internal.R.styleable.AndroidManifestPackageVerifier); 3435 3436 final String packageName = sa.getNonResourceString( 3437 com.android.internal.R.styleable.AndroidManifestPackageVerifier_name); 3438 3439 final String encodedPublicKey = sa.getNonResourceString( 3440 com.android.internal.R.styleable.AndroidManifestPackageVerifier_publicKey); 3441 3442 sa.recycle(); 3443 3444 if (packageName == null || packageName.length() == 0) { 3445 Slog.i(TAG, "verifier package name was null; skipping"); 3446 return null; 3447 } 3448 3449 final PublicKey publicKey = parsePublicKey(encodedPublicKey); 3450 if (publicKey == null) { 3451 Slog.i(TAG, "Unable to parse verifier public key for " + packageName); 3452 return null; 3453 } 3454 3455 return new VerifierInfo(packageName, publicKey); 3456 } 3457 3458 public static final PublicKey parsePublicKey(final String encodedPublicKey) { 3459 if (encodedPublicKey == null) { 3460 Slog.i(TAG, "Could not parse null public key"); 3461 return null; 3462 } 3463 3464 EncodedKeySpec keySpec; 3465 try { 3466 final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT); 3467 keySpec = new X509EncodedKeySpec(encoded); 3468 } catch (IllegalArgumentException e) { 3469 Slog.i(TAG, "Could not parse verifier public key; invalid Base64"); 3470 return null; 3471 } 3472 3473 /* First try the key as an RSA key. */ 3474 try { 3475 final KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 3476 return keyFactory.generatePublic(keySpec); 3477 } catch (NoSuchAlgorithmException e) { 3478 Log.wtf(TAG, "Could not parse public key because RSA isn't included in build"); 3479 return null; 3480 } catch (InvalidKeySpecException e) { 3481 // Not a RSA public key. 3482 } 3483 3484 /* Now try it as a DSA key. */ 3485 try { 3486 final KeyFactory keyFactory = KeyFactory.getInstance("DSA"); 3487 return keyFactory.generatePublic(keySpec); 3488 } catch (NoSuchAlgorithmException e) { 3489 Log.wtf(TAG, "Could not parse public key because DSA isn't included in build"); 3490 return null; 3491 } catch (InvalidKeySpecException e) { 3492 // Not a DSA public key. 3493 } 3494 3495 return null; 3496 } 3497 3498 private static final String ANDROID_RESOURCES 3499 = "http://schemas.android.com/apk/res/android"; 3500 3501 private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs, 3502 boolean allowGlobs, IntentInfo outInfo, String[] outError) 3503 throws XmlPullParserException, IOException { 3504 3505 TypedArray sa = res.obtainAttributes(attrs, 3506 com.android.internal.R.styleable.AndroidManifestIntentFilter); 3507 3508 int priority = sa.getInt( 3509 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0); 3510 outInfo.setPriority(priority); 3511 3512 TypedValue v = sa.peekValue( 3513 com.android.internal.R.styleable.AndroidManifestIntentFilter_label); 3514 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 3515 outInfo.nonLocalizedLabel = v.coerceToString(); 3516 } 3517 3518 outInfo.icon = sa.getResourceId( 3519 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0); 3520 3521 outInfo.logo = sa.getResourceId( 3522 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0); 3523 3524 outInfo.banner = sa.getResourceId( 3525 com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0); 3526 3527 sa.recycle(); 3528 3529 int outerDepth = parser.getDepth(); 3530 int type; 3531 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 3532 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 3533 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3534 continue; 3535 } 3536 3537 String nodeName = parser.getName(); 3538 if (nodeName.equals("action")) { 3539 String value = attrs.getAttributeValue( 3540 ANDROID_RESOURCES, "name"); 3541 if (value == null || value == "") { 3542 outError[0] = "No value supplied for <android:name>"; 3543 return false; 3544 } 3545 XmlUtils.skipCurrentTag(parser); 3546 3547 outInfo.addAction(value); 3548 } else if (nodeName.equals("category")) { 3549 String value = attrs.getAttributeValue( 3550 ANDROID_RESOURCES, "name"); 3551 if (value == null || value == "") { 3552 outError[0] = "No value supplied for <android:name>"; 3553 return false; 3554 } 3555 XmlUtils.skipCurrentTag(parser); 3556 3557 outInfo.addCategory(value); 3558 3559 } else if (nodeName.equals("data")) { 3560 sa = res.obtainAttributes(attrs, 3561 com.android.internal.R.styleable.AndroidManifestData); 3562 3563 String str = sa.getNonConfigurationString( 3564 com.android.internal.R.styleable.AndroidManifestData_mimeType, 0); 3565 if (str != null) { 3566 try { 3567 outInfo.addDataType(str); 3568 } catch (IntentFilter.MalformedMimeTypeException e) { 3569 outError[0] = e.toString(); 3570 sa.recycle(); 3571 return false; 3572 } 3573 } 3574 3575 str = sa.getNonConfigurationString( 3576 com.android.internal.R.styleable.AndroidManifestData_scheme, 0); 3577 if (str != null) { 3578 outInfo.addDataScheme(str); 3579 } 3580 3581 str = sa.getNonConfigurationString( 3582 com.android.internal.R.styleable.AndroidManifestData_ssp, 0); 3583 if (str != null) { 3584 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL); 3585 } 3586 3587 str = sa.getNonConfigurationString( 3588 com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0); 3589 if (str != null) { 3590 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX); 3591 } 3592 3593 str = sa.getNonConfigurationString( 3594 com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0); 3595 if (str != null) { 3596 if (!allowGlobs) { 3597 outError[0] = "sspPattern not allowed here; ssp must be literal"; 3598 return false; 3599 } 3600 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 3601 } 3602 3603 String host = sa.getNonConfigurationString( 3604 com.android.internal.R.styleable.AndroidManifestData_host, 0); 3605 String port = sa.getNonConfigurationString( 3606 com.android.internal.R.styleable.AndroidManifestData_port, 0); 3607 if (host != null) { 3608 outInfo.addDataAuthority(host, port); 3609 } 3610 3611 str = sa.getNonConfigurationString( 3612 com.android.internal.R.styleable.AndroidManifestData_path, 0); 3613 if (str != null) { 3614 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); 3615 } 3616 3617 str = sa.getNonConfigurationString( 3618 com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0); 3619 if (str != null) { 3620 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); 3621 } 3622 3623 str = sa.getNonConfigurationString( 3624 com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0); 3625 if (str != null) { 3626 if (!allowGlobs) { 3627 outError[0] = "pathPattern not allowed here; path must be literal"; 3628 return false; 3629 } 3630 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 3631 } 3632 3633 sa.recycle(); 3634 XmlUtils.skipCurrentTag(parser); 3635 } else if (!RIGID_PARSER) { 3636 Slog.w(TAG, "Unknown element under <intent-filter>: " 3637 + parser.getName() + " at " + mArchiveSourcePath + " " 3638 + parser.getPositionDescription()); 3639 XmlUtils.skipCurrentTag(parser); 3640 } else { 3641 outError[0] = "Bad element under <intent-filter>: " + parser.getName(); 3642 return false; 3643 } 3644 } 3645 3646 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT); 3647 3648 if (DEBUG_PARSER) { 3649 final StringBuilder cats = new StringBuilder("Intent d="); 3650 cats.append(outInfo.hasDefault); 3651 cats.append(", cat="); 3652 3653 final Iterator<String> it = outInfo.categoriesIterator(); 3654 if (it != null) { 3655 while (it.hasNext()) { 3656 cats.append(' '); 3657 cats.append(it.next()); 3658 } 3659 } 3660 Slog.d(TAG, cats.toString()); 3661 } 3662 3663 return true; 3664 } 3665 3666 /** 3667 * Representation of a full package parsed from APK files on disk. A package 3668 * consists of a single base APK, and zero or more split APKs. 3669 */ 3670 public final static class Package { 3671 3672 public String packageName; 3673 3674 // TODO: work towards making these paths invariant 3675 3676 /** Base APK */ 3677 public String codePath; 3678 /** Split APKs, ordered by parsed splitName */ 3679 public String[] splitCodePaths; 3680 3681 // For now we only support one application per package. 3682 public final ApplicationInfo applicationInfo = new ApplicationInfo(); 3683 3684 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0); 3685 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0); 3686 public final ArrayList<Activity> activities = new ArrayList<Activity>(0); 3687 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0); 3688 public final ArrayList<Provider> providers = new ArrayList<Provider>(0); 3689 public final ArrayList<Service> services = new ArrayList<Service>(0); 3690 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0); 3691 3692 public final ArrayList<String> requestedPermissions = new ArrayList<String>(); 3693 public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>(); 3694 3695 public ArrayList<String> protectedBroadcasts; 3696 3697 public ArrayList<String> libraryNames = null; 3698 public ArrayList<String> usesLibraries = null; 3699 public ArrayList<String> usesOptionalLibraries = null; 3700 public String[] usesLibraryFiles = null; 3701 3702 public ArrayList<ActivityIntentInfo> preferredActivityFilters = null; 3703 3704 public ArrayList<String> mOriginalPackages = null; 3705 public String mRealPackage = null; 3706 public ArrayList<String> mAdoptPermissions = null; 3707 3708 // We store the application meta-data independently to avoid multiple unwanted references 3709 public Bundle mAppMetaData = null; 3710 3711 // The version code declared for this package. 3712 public int mVersionCode; 3713 3714 // The version name declared for this package. 3715 public String mVersionName; 3716 3717 // The shared user id that this package wants to use. 3718 public String mSharedUserId; 3719 3720 // The shared user label that this package wants to use. 3721 public int mSharedUserLabel; 3722 3723 // Signatures that were read from the package. 3724 public Signature[] mSignatures; 3725 public Certificate[][] mCertificates; 3726 3727 // For use by package manager service for quick lookup of 3728 // preferred up order. 3729 public int mPreferredOrder = 0; 3730 3731 // For use by package manager to keep track of where it needs to do dexopt. 3732 public boolean mDexOptNeeded = true; 3733 3734 // For use by package manager to keep track of when a package was last used. 3735 public long mLastPackageUsageTimeInMills; 3736 3737 // // User set enabled state. 3738 // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; 3739 // 3740 // // Whether the package has been stopped. 3741 // public boolean mSetStopped = false; 3742 3743 // Additional data supplied by callers. 3744 public Object mExtras; 3745 3746 // Whether an operation is currently pending on this package 3747 public boolean mOperationPending; 3748 3749 /* 3750 * Applications hardware preferences 3751 */ 3752 public final ArrayList<ConfigurationInfo> configPreferences = 3753 new ArrayList<ConfigurationInfo>(); 3754 3755 /* 3756 * Applications requested features 3757 */ 3758 public ArrayList<FeatureInfo> reqFeatures = null; 3759 3760 public int installLocation; 3761 3762 /* An app that's required for all users and cannot be uninstalled for a user */ 3763 public boolean mRequiredForAllUsers; 3764 3765 /* For which types of profile this app is required */ 3766 public int mRequiredForProfile; 3767 3768 /* The restricted account authenticator type that is used by this application */ 3769 public String mRestrictedAccountType; 3770 3771 /* The required account type without which this application will not function */ 3772 public String mRequiredAccountType; 3773 3774 /** 3775 * Digest suitable for comparing whether this package's manifest is the 3776 * same as another. 3777 */ 3778 public ManifestDigest manifestDigest; 3779 3780 public String mOverlayTarget; 3781 public int mOverlayPriority; 3782 public boolean mTrustedOverlay; 3783 3784 /** 3785 * Data used to feed the KeySetManager 3786 */ 3787 public ArraySet<PublicKey> mSigningKeys; 3788 public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping; 3789 3790 public Package(String packageName) { 3791 this.packageName = packageName; 3792 applicationInfo.packageName = packageName; 3793 applicationInfo.uid = -1; 3794 } 3795 3796 public Collection<String> getAllCodePaths() { 3797 ArrayList<String> paths = new ArrayList<>(); 3798 paths.add(codePath); 3799 if (!ArrayUtils.isEmpty(splitCodePaths)) { 3800 Collections.addAll(paths, splitCodePaths); 3801 } 3802 return paths; 3803 } 3804 3805 public void setPackageName(String newName) { 3806 packageName = newName; 3807 applicationInfo.packageName = newName; 3808 for (int i=permissions.size()-1; i>=0; i--) { 3809 permissions.get(i).setPackageName(newName); 3810 } 3811 for (int i=permissionGroups.size()-1; i>=0; i--) { 3812 permissionGroups.get(i).setPackageName(newName); 3813 } 3814 for (int i=activities.size()-1; i>=0; i--) { 3815 activities.get(i).setPackageName(newName); 3816 } 3817 for (int i=receivers.size()-1; i>=0; i--) { 3818 receivers.get(i).setPackageName(newName); 3819 } 3820 for (int i=providers.size()-1; i>=0; i--) { 3821 providers.get(i).setPackageName(newName); 3822 } 3823 for (int i=services.size()-1; i>=0; i--) { 3824 services.get(i).setPackageName(newName); 3825 } 3826 for (int i=instrumentation.size()-1; i>=0; i--) { 3827 instrumentation.get(i).setPackageName(newName); 3828 } 3829 } 3830 3831 public boolean hasComponentClassName(String name) { 3832 for (int i=activities.size()-1; i>=0; i--) { 3833 if (name.equals(activities.get(i).className)) { 3834 return true; 3835 } 3836 } 3837 for (int i=receivers.size()-1; i>=0; i--) { 3838 if (name.equals(receivers.get(i).className)) { 3839 return true; 3840 } 3841 } 3842 for (int i=providers.size()-1; i>=0; i--) { 3843 if (name.equals(providers.get(i).className)) { 3844 return true; 3845 } 3846 } 3847 for (int i=services.size()-1; i>=0; i--) { 3848 if (name.equals(services.get(i).className)) { 3849 return true; 3850 } 3851 } 3852 for (int i=instrumentation.size()-1; i>=0; i--) { 3853 if (name.equals(instrumentation.get(i).className)) { 3854 return true; 3855 } 3856 } 3857 return false; 3858 } 3859 3860 public String toString() { 3861 return "Package{" 3862 + Integer.toHexString(System.identityHashCode(this)) 3863 + " " + packageName + "}"; 3864 } 3865 } 3866 3867 public static class Component<II extends IntentInfo> { 3868 public final Package owner; 3869 public final ArrayList<II> intents; 3870 public final String className; 3871 public Bundle metaData; 3872 3873 ComponentName componentName; 3874 String componentShortName; 3875 3876 public Component(Package _owner) { 3877 owner = _owner; 3878 intents = null; 3879 className = null; 3880 } 3881 3882 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) { 3883 owner = args.owner; 3884 intents = new ArrayList<II>(0); 3885 String name = args.sa.getNonConfigurationString(args.nameRes, 0); 3886 if (name == null) { 3887 className = null; 3888 args.outError[0] = args.tag + " does not specify android:name"; 3889 return; 3890 } 3891 3892 outInfo.name 3893 = buildClassName(owner.applicationInfo.packageName, name, args.outError); 3894 if (outInfo.name == null) { 3895 className = null; 3896 args.outError[0] = args.tag + " does not have valid android:name"; 3897 return; 3898 } 3899 3900 className = outInfo.name; 3901 3902 int iconVal = args.sa.getResourceId(args.iconRes, 0); 3903 if (iconVal != 0) { 3904 outInfo.icon = iconVal; 3905 outInfo.nonLocalizedLabel = null; 3906 } 3907 3908 int logoVal = args.sa.getResourceId(args.logoRes, 0); 3909 if (logoVal != 0) { 3910 outInfo.logo = logoVal; 3911 } 3912 3913 int bannerVal = args.sa.getResourceId(args.bannerRes, 0); 3914 if (bannerVal != 0) { 3915 outInfo.banner = bannerVal; 3916 } 3917 3918 TypedValue v = args.sa.peekValue(args.labelRes); 3919 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 3920 outInfo.nonLocalizedLabel = v.coerceToString(); 3921 } 3922 3923 outInfo.packageName = owner.packageName; 3924 } 3925 3926 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) { 3927 this(args, (PackageItemInfo)outInfo); 3928 if (args.outError[0] != null) { 3929 return; 3930 } 3931 3932 if (args.processRes != 0) { 3933 CharSequence pname; 3934 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 3935 pname = args.sa.getNonConfigurationString(args.processRes, 3936 Configuration.NATIVE_CONFIG_VERSION); 3937 } else { 3938 // Some older apps have been seen to use a resource reference 3939 // here that on older builds was ignored (with a warning). We 3940 // need to continue to do this for them so they don't break. 3941 pname = args.sa.getNonResourceString(args.processRes); 3942 } 3943 outInfo.processName = buildProcessName(owner.applicationInfo.packageName, 3944 owner.applicationInfo.processName, pname, 3945 args.flags, args.sepProcesses, args.outError); 3946 } 3947 3948 if (args.descriptionRes != 0) { 3949 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0); 3950 } 3951 3952 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true); 3953 } 3954 3955 public Component(Component<II> clone) { 3956 owner = clone.owner; 3957 intents = clone.intents; 3958 className = clone.className; 3959 componentName = clone.componentName; 3960 componentShortName = clone.componentShortName; 3961 } 3962 3963 public ComponentName getComponentName() { 3964 if (componentName != null) { 3965 return componentName; 3966 } 3967 if (className != null) { 3968 componentName = new ComponentName(owner.applicationInfo.packageName, 3969 className); 3970 } 3971 return componentName; 3972 } 3973 3974 public void appendComponentShortName(StringBuilder sb) { 3975 ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className); 3976 } 3977 3978 public void printComponentShortName(PrintWriter pw) { 3979 ComponentName.printShortString(pw, owner.applicationInfo.packageName, className); 3980 } 3981 3982 public void setPackageName(String packageName) { 3983 componentName = null; 3984 componentShortName = null; 3985 } 3986 } 3987 3988 public final static class Permission extends Component<IntentInfo> { 3989 public final PermissionInfo info; 3990 public boolean tree; 3991 public PermissionGroup group; 3992 3993 public Permission(Package _owner) { 3994 super(_owner); 3995 info = new PermissionInfo(); 3996 } 3997 3998 public Permission(Package _owner, PermissionInfo _info) { 3999 super(_owner); 4000 info = _info; 4001 } 4002 4003 public void setPackageName(String packageName) { 4004 super.setPackageName(packageName); 4005 info.packageName = packageName; 4006 } 4007 4008 public String toString() { 4009 return "Permission{" 4010 + Integer.toHexString(System.identityHashCode(this)) 4011 + " " + info.name + "}"; 4012 } 4013 } 4014 4015 public final static class PermissionGroup extends Component<IntentInfo> { 4016 public final PermissionGroupInfo info; 4017 4018 public PermissionGroup(Package _owner) { 4019 super(_owner); 4020 info = new PermissionGroupInfo(); 4021 } 4022 4023 public PermissionGroup(Package _owner, PermissionGroupInfo _info) { 4024 super(_owner); 4025 info = _info; 4026 } 4027 4028 public void setPackageName(String packageName) { 4029 super.setPackageName(packageName); 4030 info.packageName = packageName; 4031 } 4032 4033 public String toString() { 4034 return "PermissionGroup{" 4035 + Integer.toHexString(System.identityHashCode(this)) 4036 + " " + info.name + "}"; 4037 } 4038 } 4039 4040 private static boolean copyNeeded(int flags, Package p, 4041 PackageUserState state, Bundle metaData, int userId) { 4042 if (userId != 0) { 4043 // We always need to copy for other users, since we need 4044 // to fix up the uid. 4045 return true; 4046 } 4047 if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 4048 boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 4049 if (p.applicationInfo.enabled != enabled) { 4050 return true; 4051 } 4052 } 4053 if (!state.installed || state.blocked) { 4054 return true; 4055 } 4056 if (state.stopped) { 4057 return true; 4058 } 4059 if ((flags & PackageManager.GET_META_DATA) != 0 4060 && (metaData != null || p.mAppMetaData != null)) { 4061 return true; 4062 } 4063 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 4064 && p.usesLibraryFiles != null) { 4065 return true; 4066 } 4067 return false; 4068 } 4069 4070 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 4071 PackageUserState state) { 4072 return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId()); 4073 } 4074 4075 private static void updateApplicationInfo(ApplicationInfo ai, int flags, 4076 PackageUserState state) { 4077 // CompatibilityMode is global state. 4078 if (!sCompatibilityModeEnabled) { 4079 ai.disableCompatibilityMode(); 4080 } 4081 if (state.installed) { 4082 ai.flags |= ApplicationInfo.FLAG_INSTALLED; 4083 } else { 4084 ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; 4085 } 4086 if (state.blocked) { 4087 ai.flags |= ApplicationInfo.FLAG_BLOCKED; 4088 } else { 4089 ai.flags &= ~ApplicationInfo.FLAG_BLOCKED; 4090 } 4091 if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 4092 ai.enabled = true; 4093 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { 4094 ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0; 4095 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED 4096 || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { 4097 ai.enabled = false; 4098 } 4099 ai.enabledSetting = state.enabled; 4100 } 4101 4102 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 4103 PackageUserState state, int userId) { 4104 if (p == null) return null; 4105 if (!checkUseInstalledOrBlocked(flags, state)) { 4106 return null; 4107 } 4108 if (!copyNeeded(flags, p, state, null, userId) 4109 && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0 4110 || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { 4111 // In this case it is safe to directly modify the internal ApplicationInfo state: 4112 // - CompatibilityMode is global state, so will be the same for every call. 4113 // - We only come in to here if the app should reported as installed; this is the 4114 // default state, and we will do a copy otherwise. 4115 // - The enable state will always be reported the same for the application across 4116 // calls; the only exception is for the UNTIL_USED mode, and in that case we will 4117 // be doing a copy. 4118 updateApplicationInfo(p.applicationInfo, flags, state); 4119 return p.applicationInfo; 4120 } 4121 4122 // Make shallow copy so we can store the metadata/libraries safely 4123 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo); 4124 if (userId != 0) { 4125 ai.uid = UserHandle.getUid(userId, ai.uid); 4126 ai.dataDir = PackageManager.getDataDirForUser(userId, ai.packageName); 4127 } 4128 if ((flags & PackageManager.GET_META_DATA) != 0) { 4129 ai.metaData = p.mAppMetaData; 4130 } 4131 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { 4132 ai.sharedLibraryFiles = p.usesLibraryFiles; 4133 } 4134 if (state.stopped) { 4135 ai.flags |= ApplicationInfo.FLAG_STOPPED; 4136 } else { 4137 ai.flags &= ~ApplicationInfo.FLAG_STOPPED; 4138 } 4139 updateApplicationInfo(ai, flags, state); 4140 return ai; 4141 } 4142 4143 public static final PermissionInfo generatePermissionInfo( 4144 Permission p, int flags) { 4145 if (p == null) return null; 4146 if ((flags&PackageManager.GET_META_DATA) == 0) { 4147 return p.info; 4148 } 4149 PermissionInfo pi = new PermissionInfo(p.info); 4150 pi.metaData = p.metaData; 4151 return pi; 4152 } 4153 4154 public static final PermissionGroupInfo generatePermissionGroupInfo( 4155 PermissionGroup pg, int flags) { 4156 if (pg == null) return null; 4157 if ((flags&PackageManager.GET_META_DATA) == 0) { 4158 return pg.info; 4159 } 4160 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info); 4161 pgi.metaData = pg.metaData; 4162 return pgi; 4163 } 4164 4165 public final static class Activity extends Component<ActivityIntentInfo> { 4166 public final ActivityInfo info; 4167 4168 public Activity(final ParseComponentArgs args, final ActivityInfo _info) { 4169 super(args, _info); 4170 info = _info; 4171 info.applicationInfo = args.owner.applicationInfo; 4172 } 4173 4174 public void setPackageName(String packageName) { 4175 super.setPackageName(packageName); 4176 info.packageName = packageName; 4177 } 4178 4179 public String toString() { 4180 StringBuilder sb = new StringBuilder(128); 4181 sb.append("Activity{"); 4182 sb.append(Integer.toHexString(System.identityHashCode(this))); 4183 sb.append(' '); 4184 appendComponentShortName(sb); 4185 sb.append('}'); 4186 return sb.toString(); 4187 } 4188 } 4189 4190 public static final ActivityInfo generateActivityInfo(Activity a, int flags, 4191 PackageUserState state, int userId) { 4192 if (a == null) return null; 4193 if (!checkUseInstalledOrBlocked(flags, state)) { 4194 return null; 4195 } 4196 if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) { 4197 return a.info; 4198 } 4199 // Make shallow copies so we can store the metadata safely 4200 ActivityInfo ai = new ActivityInfo(a.info); 4201 ai.metaData = a.metaData; 4202 ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId); 4203 return ai; 4204 } 4205 4206 public final static class Service extends Component<ServiceIntentInfo> { 4207 public final ServiceInfo info; 4208 4209 public Service(final ParseComponentArgs args, final ServiceInfo _info) { 4210 super(args, _info); 4211 info = _info; 4212 info.applicationInfo = args.owner.applicationInfo; 4213 } 4214 4215 public void setPackageName(String packageName) { 4216 super.setPackageName(packageName); 4217 info.packageName = packageName; 4218 } 4219 4220 public String toString() { 4221 StringBuilder sb = new StringBuilder(128); 4222 sb.append("Service{"); 4223 sb.append(Integer.toHexString(System.identityHashCode(this))); 4224 sb.append(' '); 4225 appendComponentShortName(sb); 4226 sb.append('}'); 4227 return sb.toString(); 4228 } 4229 } 4230 4231 public static final ServiceInfo generateServiceInfo(Service s, int flags, 4232 PackageUserState state, int userId) { 4233 if (s == null) return null; 4234 if (!checkUseInstalledOrBlocked(flags, state)) { 4235 return null; 4236 } 4237 if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) { 4238 return s.info; 4239 } 4240 // Make shallow copies so we can store the metadata safely 4241 ServiceInfo si = new ServiceInfo(s.info); 4242 si.metaData = s.metaData; 4243 si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId); 4244 return si; 4245 } 4246 4247 public final static class Provider extends Component<ProviderIntentInfo> { 4248 public final ProviderInfo info; 4249 public boolean syncable; 4250 4251 public Provider(final ParseComponentArgs args, final ProviderInfo _info) { 4252 super(args, _info); 4253 info = _info; 4254 info.applicationInfo = args.owner.applicationInfo; 4255 syncable = false; 4256 } 4257 4258 public Provider(Provider existingProvider) { 4259 super(existingProvider); 4260 this.info = existingProvider.info; 4261 this.syncable = existingProvider.syncable; 4262 } 4263 4264 public void setPackageName(String packageName) { 4265 super.setPackageName(packageName); 4266 info.packageName = packageName; 4267 } 4268 4269 public String toString() { 4270 StringBuilder sb = new StringBuilder(128); 4271 sb.append("Provider{"); 4272 sb.append(Integer.toHexString(System.identityHashCode(this))); 4273 sb.append(' '); 4274 appendComponentShortName(sb); 4275 sb.append('}'); 4276 return sb.toString(); 4277 } 4278 } 4279 4280 public static final ProviderInfo generateProviderInfo(Provider p, int flags, 4281 PackageUserState state, int userId) { 4282 if (p == null) return null; 4283 if (!checkUseInstalledOrBlocked(flags, state)) { 4284 return null; 4285 } 4286 if (!copyNeeded(flags, p.owner, state, p.metaData, userId) 4287 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 4288 || p.info.uriPermissionPatterns == null)) { 4289 return p.info; 4290 } 4291 // Make shallow copies so we can store the metadata safely 4292 ProviderInfo pi = new ProviderInfo(p.info); 4293 pi.metaData = p.metaData; 4294 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { 4295 pi.uriPermissionPatterns = null; 4296 } 4297 pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId); 4298 return pi; 4299 } 4300 4301 public final static class Instrumentation extends Component { 4302 public final InstrumentationInfo info; 4303 4304 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) { 4305 super(args, _info); 4306 info = _info; 4307 } 4308 4309 public void setPackageName(String packageName) { 4310 super.setPackageName(packageName); 4311 info.packageName = packageName; 4312 } 4313 4314 public String toString() { 4315 StringBuilder sb = new StringBuilder(128); 4316 sb.append("Instrumentation{"); 4317 sb.append(Integer.toHexString(System.identityHashCode(this))); 4318 sb.append(' '); 4319 appendComponentShortName(sb); 4320 sb.append('}'); 4321 return sb.toString(); 4322 } 4323 } 4324 4325 public static final InstrumentationInfo generateInstrumentationInfo( 4326 Instrumentation i, int flags) { 4327 if (i == null) return null; 4328 if ((flags&PackageManager.GET_META_DATA) == 0) { 4329 return i.info; 4330 } 4331 InstrumentationInfo ii = new InstrumentationInfo(i.info); 4332 ii.metaData = i.metaData; 4333 return ii; 4334 } 4335 4336 public static class IntentInfo extends IntentFilter { 4337 public boolean hasDefault; 4338 public int labelRes; 4339 public CharSequence nonLocalizedLabel; 4340 public int icon; 4341 public int logo; 4342 public int banner; 4343 public int preferred; 4344 } 4345 4346 public final static class ActivityIntentInfo extends IntentInfo { 4347 public final Activity activity; 4348 4349 public ActivityIntentInfo(Activity _activity) { 4350 activity = _activity; 4351 } 4352 4353 public String toString() { 4354 StringBuilder sb = new StringBuilder(128); 4355 sb.append("ActivityIntentInfo{"); 4356 sb.append(Integer.toHexString(System.identityHashCode(this))); 4357 sb.append(' '); 4358 activity.appendComponentShortName(sb); 4359 sb.append('}'); 4360 return sb.toString(); 4361 } 4362 } 4363 4364 public final static class ServiceIntentInfo extends IntentInfo { 4365 public final Service service; 4366 4367 public ServiceIntentInfo(Service _service) { 4368 service = _service; 4369 } 4370 4371 public String toString() { 4372 StringBuilder sb = new StringBuilder(128); 4373 sb.append("ServiceIntentInfo{"); 4374 sb.append(Integer.toHexString(System.identityHashCode(this))); 4375 sb.append(' '); 4376 service.appendComponentShortName(sb); 4377 sb.append('}'); 4378 return sb.toString(); 4379 } 4380 } 4381 4382 public static final class ProviderIntentInfo extends IntentInfo { 4383 public final Provider provider; 4384 4385 public ProviderIntentInfo(Provider provider) { 4386 this.provider = provider; 4387 } 4388 4389 public String toString() { 4390 StringBuilder sb = new StringBuilder(128); 4391 sb.append("ProviderIntentInfo{"); 4392 sb.append(Integer.toHexString(System.identityHashCode(this))); 4393 sb.append(' '); 4394 provider.appendComponentShortName(sb); 4395 sb.append('}'); 4396 return sb.toString(); 4397 } 4398 } 4399 4400 /** 4401 * @hide 4402 */ 4403 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { 4404 sCompatibilityModeEnabled = compatibilityModeEnabled; 4405 } 4406 4407 private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>(); 4408 4409 public static long readFullyIgnoringContents(InputStream in) throws IOException { 4410 byte[] buffer = sBuffer.getAndSet(null); 4411 if (buffer == null) { 4412 buffer = new byte[4096]; 4413 } 4414 4415 int n = 0; 4416 int count = 0; 4417 while ((n = in.read(buffer, 0, buffer.length)) != -1) { 4418 count += n; 4419 } 4420 4421 sBuffer.set(buffer); 4422 return count; 4423 } 4424 4425 public static void closeQuietly(StrictJarFile jarFile) { 4426 if (jarFile != null) { 4427 try { 4428 jarFile.close(); 4429 } catch (Exception ignored) { 4430 } 4431 } 4432 } 4433 4434 public static class PackageParserException extends Exception { 4435 public final int error; 4436 4437 public PackageParserException(int error, String detailMessage) { 4438 super(detailMessage); 4439 this.error = error; 4440 } 4441 4442 public PackageParserException(int error, String detailMessage, Throwable throwable) { 4443 super(detailMessage, throwable); 4444 this.error = error; 4445 } 4446 } 4447} 4448