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