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