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