PackageParser.java revision 90d8ee650be988d8479f4f14ae8e541bb4cb034b
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 org.xmlpull.v1.XmlPullParser; 20import org.xmlpull.v1.XmlPullParserException; 21 22import android.content.ComponentName; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.content.res.AssetManager; 26import android.content.res.Configuration; 27import android.content.res.Resources; 28import android.content.res.TypedArray; 29import android.content.res.XmlResourceParser; 30import android.os.Build; 31import android.os.Bundle; 32import android.os.PatternMatcher; 33import android.provider.Settings; 34import android.util.AttributeSet; 35import android.util.Config; 36import android.util.DisplayMetrics; 37import android.util.Log; 38import android.util.TypedValue; 39 40import com.android.internal.util.XmlUtils; 41 42import java.io.File; 43import java.io.IOException; 44import java.io.InputStream; 45import java.lang.ref.WeakReference; 46import java.security.cert.Certificate; 47import java.security.cert.CertificateEncodingException; 48import java.util.ArrayList; 49import java.util.Enumeration; 50import java.util.Iterator; 51import java.util.List; 52import java.util.jar.JarEntry; 53import java.util.jar.JarFile; 54 55/** 56 * Package archive parsing 57 * 58 * {@hide} 59 */ 60public class PackageParser { 61 /** @hide */ 62 public static class NewPermissionInfo { 63 public final String name; 64 public final int sdkVersion; 65 public final int fileVersion; 66 67 public NewPermissionInfo(String name, int sdkVersion, int fileVersion) { 68 this.name = name; 69 this.sdkVersion = sdkVersion; 70 this.fileVersion = fileVersion; 71 } 72 } 73 74 /** 75 * List of new permissions that have been added since 1.0. 76 * NOTE: These must be declared in SDK version order, with permissions 77 * added to older SDKs appearing before those added to newer SDKs. 78 * @hide 79 */ 80 public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] = 81 new PackageParser.NewPermissionInfo[] { 82 new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 83 android.os.Build.VERSION_CODES.DONUT, 0), 84 new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE, 85 android.os.Build.VERSION_CODES.DONUT, 0) 86 }; 87 88 private String mArchiveSourcePath; 89 private String[] mSeparateProcesses; 90 private static final int SDK_VERSION = Build.VERSION.SDK_INT; 91 private static final String SDK_CODENAME = "REL".equals(Build.VERSION.CODENAME) 92 ? null : Build.VERSION.CODENAME; 93 94 private int mParseError = PackageManager.INSTALL_SUCCEEDED; 95 96 private static final Object mSync = new Object(); 97 private static WeakReference<byte[]> mReadBuffer; 98 99 private static boolean sCompatibilityModeEnabled = true; 100 private static final int PARSE_DEFAULT_INSTALL_LOCATION = PackageInfo.INSTALL_LOCATION_UNSPECIFIED; 101 102 static class ParsePackageItemArgs { 103 final Package owner; 104 final String[] outError; 105 final int nameRes; 106 final int labelRes; 107 final int iconRes; 108 109 String tag; 110 TypedArray sa; 111 112 ParsePackageItemArgs(Package _owner, String[] _outError, 113 int _nameRes, int _labelRes, int _iconRes) { 114 owner = _owner; 115 outError = _outError; 116 nameRes = _nameRes; 117 labelRes = _labelRes; 118 iconRes = _iconRes; 119 } 120 } 121 122 static class ParseComponentArgs extends ParsePackageItemArgs { 123 final String[] sepProcesses; 124 final int processRes; 125 final int descriptionRes; 126 final int enabledRes; 127 int flags; 128 129 ParseComponentArgs(Package _owner, String[] _outError, 130 int _nameRes, int _labelRes, int _iconRes, 131 String[] _sepProcesses, int _processRes, 132 int _descriptionRes, int _enabledRes) { 133 super(_owner, _outError, _nameRes, _labelRes, _iconRes); 134 sepProcesses = _sepProcesses; 135 processRes = _processRes; 136 descriptionRes = _descriptionRes; 137 enabledRes = _enabledRes; 138 } 139 } 140 141 /* Light weight package info. 142 * @hide 143 */ 144 public static class PackageLite { 145 public String packageName; 146 public int installLocation; 147 public String mScanPath; 148 public PackageLite(String packageName, int installLocation) { 149 this.packageName = packageName; 150 this.installLocation = installLocation; 151 } 152 } 153 154 private ParsePackageItemArgs mParseInstrumentationArgs; 155 private ParseComponentArgs mParseActivityArgs; 156 private ParseComponentArgs mParseActivityAliasArgs; 157 private ParseComponentArgs mParseServiceArgs; 158 private ParseComponentArgs mParseProviderArgs; 159 160 /** If set to true, we will only allow package files that exactly match 161 * the DTD. Otherwise, we try to get as much from the package as we 162 * can without failing. This should normally be set to false, to 163 * support extensions to the DTD in future versions. */ 164 private static final boolean RIGID_PARSER = false; 165 166 private static final String TAG = "PackageParser"; 167 168 public PackageParser(String archiveSourcePath) { 169 mArchiveSourcePath = archiveSourcePath; 170 } 171 172 public void setSeparateProcesses(String[] procs) { 173 mSeparateProcesses = procs; 174 } 175 176 private static final boolean isPackageFilename(String name) { 177 return name.endsWith(".apk"); 178 } 179 180 /** 181 * Generate and return the {@link PackageInfo} for a parsed package. 182 * 183 * @param p the parsed package. 184 * @param flags indicating which optional information is included. 185 */ 186 public static PackageInfo generatePackageInfo(PackageParser.Package p, 187 int gids[], int flags) { 188 189 PackageInfo pi = new PackageInfo(); 190 pi.packageName = p.packageName; 191 pi.versionCode = p.mVersionCode; 192 pi.versionName = p.mVersionName; 193 pi.sharedUserId = p.mSharedUserId; 194 pi.sharedUserLabel = p.mSharedUserLabel; 195 pi.applicationInfo = p.applicationInfo; 196 pi.installLocation = p.installLocation; 197 if ((flags&PackageManager.GET_GIDS) != 0) { 198 pi.gids = gids; 199 } 200 if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) { 201 int N = p.configPreferences.size(); 202 if (N > 0) { 203 pi.configPreferences = new ConfigurationInfo[N]; 204 p.configPreferences.toArray(pi.configPreferences); 205 } 206 N = p.reqFeatures != null ? p.reqFeatures.size() : 0; 207 if (N > 0) { 208 pi.reqFeatures = new FeatureInfo[N]; 209 p.reqFeatures.toArray(pi.reqFeatures); 210 } 211 } 212 if ((flags&PackageManager.GET_ACTIVITIES) != 0) { 213 int N = p.activities.size(); 214 if (N > 0) { 215 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 216 pi.activities = new ActivityInfo[N]; 217 } else { 218 int num = 0; 219 for (int i=0; i<N; i++) { 220 if (p.activities.get(i).info.enabled) num++; 221 } 222 pi.activities = new ActivityInfo[num]; 223 } 224 for (int i=0, j=0; i<N; i++) { 225 final Activity activity = p.activities.get(i); 226 if (activity.info.enabled 227 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 228 pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags); 229 } 230 } 231 } 232 } 233 if ((flags&PackageManager.GET_RECEIVERS) != 0) { 234 int N = p.receivers.size(); 235 if (N > 0) { 236 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 237 pi.receivers = new ActivityInfo[N]; 238 } else { 239 int num = 0; 240 for (int i=0; i<N; i++) { 241 if (p.receivers.get(i).info.enabled) num++; 242 } 243 pi.receivers = new ActivityInfo[num]; 244 } 245 for (int i=0, j=0; i<N; i++) { 246 final Activity activity = p.receivers.get(i); 247 if (activity.info.enabled 248 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 249 pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags); 250 } 251 } 252 } 253 } 254 if ((flags&PackageManager.GET_SERVICES) != 0) { 255 int N = p.services.size(); 256 if (N > 0) { 257 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 258 pi.services = new ServiceInfo[N]; 259 } else { 260 int num = 0; 261 for (int i=0; i<N; i++) { 262 if (p.services.get(i).info.enabled) num++; 263 } 264 pi.services = new ServiceInfo[num]; 265 } 266 for (int i=0, j=0; i<N; i++) { 267 final Service service = p.services.get(i); 268 if (service.info.enabled 269 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 270 pi.services[j++] = generateServiceInfo(p.services.get(i), flags); 271 } 272 } 273 } 274 } 275 if ((flags&PackageManager.GET_PROVIDERS) != 0) { 276 int N = p.providers.size(); 277 if (N > 0) { 278 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 279 pi.providers = new ProviderInfo[N]; 280 } else { 281 int num = 0; 282 for (int i=0; i<N; i++) { 283 if (p.providers.get(i).info.enabled) num++; 284 } 285 pi.providers = new ProviderInfo[num]; 286 } 287 for (int i=0, j=0; i<N; i++) { 288 final Provider provider = p.providers.get(i); 289 if (provider.info.enabled 290 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 291 pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags); 292 } 293 } 294 } 295 } 296 if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) { 297 int N = p.instrumentation.size(); 298 if (N > 0) { 299 pi.instrumentation = new InstrumentationInfo[N]; 300 for (int i=0; i<N; i++) { 301 pi.instrumentation[i] = generateInstrumentationInfo( 302 p.instrumentation.get(i), flags); 303 } 304 } 305 } 306 if ((flags&PackageManager.GET_PERMISSIONS) != 0) { 307 int N = p.permissions.size(); 308 if (N > 0) { 309 pi.permissions = new PermissionInfo[N]; 310 for (int i=0; i<N; i++) { 311 pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags); 312 } 313 } 314 N = p.requestedPermissions.size(); 315 if (N > 0) { 316 pi.requestedPermissions = new String[N]; 317 for (int i=0; i<N; i++) { 318 pi.requestedPermissions[i] = p.requestedPermissions.get(i); 319 } 320 } 321 } 322 if ((flags&PackageManager.GET_SIGNATURES) != 0) { 323 int N = (p.mSignatures != null) ? p.mSignatures.length : 0; 324 if (N > 0) { 325 pi.signatures = new Signature[N]; 326 System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N); 327 } 328 } 329 return pi; 330 } 331 332 private Certificate[] loadCertificates(JarFile jarFile, JarEntry je, 333 byte[] readBuffer) { 334 try { 335 // We must read the stream for the JarEntry to retrieve 336 // its certificates. 337 InputStream is = jarFile.getInputStream(je); 338 while (is.read(readBuffer, 0, readBuffer.length) != -1) { 339 // not using 340 } 341 is.close(); 342 return je != null ? je.getCertificates() : null; 343 } catch (IOException e) { 344 Log.w(TAG, "Exception reading " + je.getName() + " in " 345 + jarFile.getName(), e); 346 } 347 return null; 348 } 349 350 public final static int PARSE_IS_SYSTEM = 1<<0; 351 public final static int PARSE_CHATTY = 1<<1; 352 public final static int PARSE_MUST_BE_APK = 1<<2; 353 public final static int PARSE_IGNORE_PROCESSES = 1<<3; 354 public final static int PARSE_FORWARD_LOCK = 1<<4; 355 public final static int PARSE_ON_SDCARD = 1<<5; 356 357 public int getParseError() { 358 return mParseError; 359 } 360 361 public Package parsePackage(File sourceFile, String destCodePath, 362 DisplayMetrics metrics, int flags) { 363 mParseError = PackageManager.INSTALL_SUCCEEDED; 364 365 mArchiveSourcePath = sourceFile.getPath(); 366 if (!sourceFile.isFile()) { 367 Log.w(TAG, "Skipping dir: " + mArchiveSourcePath); 368 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; 369 return null; 370 } 371 if (!isPackageFilename(sourceFile.getName()) 372 && (flags&PARSE_MUST_BE_APK) != 0) { 373 if ((flags&PARSE_IS_SYSTEM) == 0) { 374 // We expect to have non-.apk files in the system dir, 375 // so don't warn about them. 376 Log.w(TAG, "Skipping non-package file: " + mArchiveSourcePath); 377 } 378 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; 379 return null; 380 } 381 382 if ((flags&PARSE_CHATTY) != 0 && Config.LOGD) Log.d( 383 TAG, "Scanning package: " + mArchiveSourcePath); 384 385 XmlResourceParser parser = null; 386 AssetManager assmgr = null; 387 boolean assetError = true; 388 try { 389 assmgr = new AssetManager(); 390 int cookie = assmgr.addAssetPath(mArchiveSourcePath); 391 if(cookie != 0) { 392 parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml"); 393 assetError = false; 394 } else { 395 Log.w(TAG, "Failed adding asset path:"+mArchiveSourcePath); 396 } 397 } catch (Exception e) { 398 Log.w(TAG, "Unable to read AndroidManifest.xml of " 399 + mArchiveSourcePath, e); 400 } 401 if(assetError) { 402 if (assmgr != null) assmgr.close(); 403 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; 404 return null; 405 } 406 String[] errorText = new String[1]; 407 Package pkg = null; 408 Exception errorException = null; 409 try { 410 // XXXX todo: need to figure out correct configuration. 411 Resources res = new Resources(assmgr, metrics, null); 412 pkg = parsePackage(res, parser, flags, errorText); 413 } catch (Exception e) { 414 errorException = e; 415 mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; 416 } 417 418 419 if (pkg == null) { 420 if (errorException != null) { 421 Log.w(TAG, mArchiveSourcePath, errorException); 422 } else { 423 Log.w(TAG, mArchiveSourcePath + " (at " 424 + parser.getPositionDescription() 425 + "): " + errorText[0]); 426 } 427 parser.close(); 428 assmgr.close(); 429 if (mParseError == PackageManager.INSTALL_SUCCEEDED) { 430 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 431 } 432 return null; 433 } 434 435 parser.close(); 436 assmgr.close(); 437 438 // Set code and resource paths 439 pkg.mPath = destCodePath; 440 pkg.mScanPath = mArchiveSourcePath; 441 //pkg.applicationInfo.sourceDir = destCodePath; 442 //pkg.applicationInfo.publicSourceDir = destRes; 443 pkg.mSignatures = null; 444 445 return pkg; 446 } 447 448 public boolean collectCertificates(Package pkg, int flags) { 449 pkg.mSignatures = null; 450 451 WeakReference<byte[]> readBufferRef; 452 byte[] readBuffer = null; 453 synchronized (mSync) { 454 readBufferRef = mReadBuffer; 455 if (readBufferRef != null) { 456 mReadBuffer = null; 457 readBuffer = readBufferRef.get(); 458 } 459 if (readBuffer == null) { 460 readBuffer = new byte[8192]; 461 readBufferRef = new WeakReference<byte[]>(readBuffer); 462 } 463 } 464 465 try { 466 JarFile jarFile = new JarFile(mArchiveSourcePath); 467 468 Certificate[] certs = null; 469 470 if ((flags&PARSE_IS_SYSTEM) != 0) { 471 // If this package comes from the system image, then we 472 // can trust it... we'll just use the AndroidManifest.xml 473 // to retrieve its signatures, not validating all of the 474 // files. 475 JarEntry jarEntry = jarFile.getJarEntry("AndroidManifest.xml"); 476 certs = loadCertificates(jarFile, jarEntry, readBuffer); 477 if (certs == null) { 478 Log.e(TAG, "Package " + pkg.packageName 479 + " has no certificates at entry " 480 + jarEntry.getName() + "; ignoring!"); 481 jarFile.close(); 482 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; 483 return false; 484 } 485 if (false) { 486 Log.i(TAG, "File " + mArchiveSourcePath + ": entry=" + jarEntry 487 + " certs=" + (certs != null ? certs.length : 0)); 488 if (certs != null) { 489 final int N = certs.length; 490 for (int i=0; i<N; i++) { 491 Log.i(TAG, " Public key: " 492 + certs[i].getPublicKey().getEncoded() 493 + " " + certs[i].getPublicKey()); 494 } 495 } 496 } 497 498 } else { 499 Enumeration entries = jarFile.entries(); 500 while (entries.hasMoreElements()) { 501 JarEntry je = (JarEntry)entries.nextElement(); 502 if (je.isDirectory()) continue; 503 if (je.getName().startsWith("META-INF/")) continue; 504 Certificate[] localCerts = loadCertificates(jarFile, je, 505 readBuffer); 506 if (false) { 507 Log.i(TAG, "File " + mArchiveSourcePath + " entry " + je.getName() 508 + ": certs=" + certs + " (" 509 + (certs != null ? certs.length : 0) + ")"); 510 } 511 if (localCerts == null) { 512 Log.e(TAG, "Package " + pkg.packageName 513 + " has no certificates at entry " 514 + je.getName() + "; ignoring!"); 515 jarFile.close(); 516 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; 517 return false; 518 } else if (certs == null) { 519 certs = localCerts; 520 } else { 521 // Ensure all certificates match. 522 for (int i=0; i<certs.length; i++) { 523 boolean found = false; 524 for (int j=0; j<localCerts.length; j++) { 525 if (certs[i] != null && 526 certs[i].equals(localCerts[j])) { 527 found = true; 528 break; 529 } 530 } 531 if (!found || certs.length != localCerts.length) { 532 Log.e(TAG, "Package " + pkg.packageName 533 + " has mismatched certificates at entry " 534 + je.getName() + "; ignoring!"); 535 jarFile.close(); 536 mParseError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; 537 return false; 538 } 539 } 540 } 541 } 542 } 543 jarFile.close(); 544 545 synchronized (mSync) { 546 mReadBuffer = readBufferRef; 547 } 548 549 if (certs != null && certs.length > 0) { 550 final int N = certs.length; 551 pkg.mSignatures = new Signature[certs.length]; 552 for (int i=0; i<N; i++) { 553 pkg.mSignatures[i] = new Signature( 554 certs[i].getEncoded()); 555 } 556 } else { 557 Log.e(TAG, "Package " + pkg.packageName 558 + " has no certificates; ignoring!"); 559 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; 560 return false; 561 } 562 } catch (CertificateEncodingException e) { 563 Log.w(TAG, "Exception reading " + mArchiveSourcePath, e); 564 mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; 565 return false; 566 } catch (IOException e) { 567 Log.w(TAG, "Exception reading " + mArchiveSourcePath, e); 568 mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; 569 return false; 570 } catch (RuntimeException e) { 571 Log.w(TAG, "Exception reading " + mArchiveSourcePath, e); 572 mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; 573 return false; 574 } 575 576 return true; 577 } 578 579 /* 580 * Utility method that retrieves just the package name and install 581 * location from the apk location at the given file path. 582 * @param packageFilePath file location of the apk 583 * @param flags Special parse flags 584 * @return PackageLite object with package information. 585 */ 586 public static PackageLite parsePackageLite(String packageFilePath, int flags) { 587 XmlResourceParser parser = null; 588 AssetManager assmgr = null; 589 try { 590 assmgr = new AssetManager(); 591 int cookie = assmgr.addAssetPath(packageFilePath); 592 parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml"); 593 } catch (Exception e) { 594 if (assmgr != null) assmgr.close(); 595 Log.w(TAG, "Unable to read AndroidManifest.xml of " 596 + packageFilePath, e); 597 return null; 598 } 599 AttributeSet attrs = parser; 600 String errors[] = new String[1]; 601 PackageLite packageLite = null; 602 try { 603 packageLite = parsePackageLite(parser, attrs, flags, errors); 604 } catch (IOException e) { 605 Log.w(TAG, packageFilePath, e); 606 } catch (XmlPullParserException e) { 607 Log.w(TAG, packageFilePath, e); 608 } finally { 609 if (parser != null) parser.close(); 610 if (assmgr != null) assmgr.close(); 611 } 612 if (packageLite == null) { 613 Log.e(TAG, "parsePackageLite error: " + errors[0]); 614 return null; 615 } 616 return packageLite; 617 } 618 619 private static String validateName(String name, boolean requiresSeparator) { 620 final int N = name.length(); 621 boolean hasSep = false; 622 boolean front = true; 623 for (int i=0; i<N; i++) { 624 final char c = name.charAt(i); 625 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { 626 front = false; 627 continue; 628 } 629 if (!front) { 630 if ((c >= '0' && c <= '9') || c == '_') { 631 continue; 632 } 633 } 634 if (c == '.') { 635 hasSep = true; 636 front = true; 637 continue; 638 } 639 return "bad character '" + c + "'"; 640 } 641 return hasSep || !requiresSeparator 642 ? null : "must have at least one '.' separator"; 643 } 644 645 private static String parsePackageName(XmlPullParser parser, 646 AttributeSet attrs, int flags, String[] outError) 647 throws IOException, XmlPullParserException { 648 649 int type; 650 while ((type=parser.next()) != parser.START_TAG 651 && type != parser.END_DOCUMENT) { 652 ; 653 } 654 655 if (type != parser.START_TAG) { 656 outError[0] = "No start tag found"; 657 return null; 658 } 659 if ((flags&PARSE_CHATTY) != 0 && Config.LOGV) Log.v( 660 TAG, "Root element name: '" + parser.getName() + "'"); 661 if (!parser.getName().equals("manifest")) { 662 outError[0] = "No <manifest> tag"; 663 return null; 664 } 665 String pkgName = attrs.getAttributeValue(null, "package"); 666 if (pkgName == null || pkgName.length() == 0) { 667 outError[0] = "<manifest> does not specify package"; 668 return null; 669 } 670 String nameError = validateName(pkgName, true); 671 if (nameError != null && !"android".equals(pkgName)) { 672 outError[0] = "<manifest> specifies bad package name \"" 673 + pkgName + "\": " + nameError; 674 return null; 675 } 676 677 return pkgName.intern(); 678 } 679 680 private static PackageLite parsePackageLite(XmlPullParser parser, 681 AttributeSet attrs, int flags, String[] outError) 682 throws IOException, XmlPullParserException { 683 684 int type; 685 while ((type=parser.next()) != parser.START_TAG 686 && type != parser.END_DOCUMENT) { 687 ; 688 } 689 690 if (type != parser.START_TAG) { 691 outError[0] = "No start tag found"; 692 return null; 693 } 694 if ((flags&PARSE_CHATTY) != 0 && Config.LOGV) Log.v( 695 TAG, "Root element name: '" + parser.getName() + "'"); 696 if (!parser.getName().equals("manifest")) { 697 outError[0] = "No <manifest> tag"; 698 return null; 699 } 700 String pkgName = attrs.getAttributeValue(null, "package"); 701 if (pkgName == null || pkgName.length() == 0) { 702 outError[0] = "<manifest> does not specify package"; 703 return null; 704 } 705 String nameError = validateName(pkgName, true); 706 if (nameError != null && !"android".equals(pkgName)) { 707 outError[0] = "<manifest> specifies bad package name \"" 708 + pkgName + "\": " + nameError; 709 return null; 710 } 711 int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; 712 for (int i = 0; i < attrs.getAttributeCount(); i++) { 713 String attr = attrs.getAttributeName(i); 714 if (attr.equals("installLocation")) { 715 installLocation = attrs.getAttributeIntValue(i, 716 PARSE_DEFAULT_INSTALL_LOCATION); 717 break; 718 } 719 } 720 return new PackageLite(pkgName.intern(), installLocation); 721 } 722 723 /** 724 * Temporary. 725 */ 726 static public Signature stringToSignature(String str) { 727 final int N = str.length(); 728 byte[] sig = new byte[N]; 729 for (int i=0; i<N; i++) { 730 sig[i] = (byte)str.charAt(i); 731 } 732 return new Signature(sig); 733 } 734 735 private Package parsePackage( 736 Resources res, XmlResourceParser parser, int flags, String[] outError) 737 throws XmlPullParserException, IOException { 738 AttributeSet attrs = parser; 739 740 mParseInstrumentationArgs = null; 741 mParseActivityArgs = null; 742 mParseServiceArgs = null; 743 mParseProviderArgs = null; 744 745 String pkgName = parsePackageName(parser, attrs, flags, outError); 746 if (pkgName == null) { 747 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 748 return null; 749 } 750 int type; 751 752 final Package pkg = new Package(pkgName); 753 boolean foundApp = false; 754 755 TypedArray sa = res.obtainAttributes(attrs, 756 com.android.internal.R.styleable.AndroidManifest); 757 pkg.mVersionCode = sa.getInteger( 758 com.android.internal.R.styleable.AndroidManifest_versionCode, 0); 759 pkg.mVersionName = sa.getNonConfigurationString( 760 com.android.internal.R.styleable.AndroidManifest_versionName, 0); 761 if (pkg.mVersionName != null) { 762 pkg.mVersionName = pkg.mVersionName.intern(); 763 } 764 String str = sa.getNonConfigurationString( 765 com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); 766 if (str != null && str.length() > 0) { 767 String nameError = validateName(str, true); 768 if (nameError != null && !"android".equals(pkgName)) { 769 outError[0] = "<manifest> specifies bad sharedUserId name \"" 770 + str + "\": " + nameError; 771 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; 772 return null; 773 } 774 pkg.mSharedUserId = str.intern(); 775 pkg.mSharedUserLabel = sa.getResourceId( 776 com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0); 777 } 778 sa.recycle(); 779 780 pkg.installLocation = sa.getInteger( 781 com.android.internal.R.styleable.AndroidManifest_installLocation, 782 PARSE_DEFAULT_INSTALL_LOCATION); 783 784 // Resource boolean are -1, so 1 means we don't know the value. 785 int supportsSmallScreens = 1; 786 int supportsNormalScreens = 1; 787 int supportsLargeScreens = 1; 788 int resizeable = 1; 789 int anyDensity = 1; 790 791 int outerDepth = parser.getDepth(); 792 while ((type=parser.next()) != parser.END_DOCUMENT 793 && (type != parser.END_TAG || parser.getDepth() > outerDepth)) { 794 if (type == parser.END_TAG || type == parser.TEXT) { 795 continue; 796 } 797 798 String tagName = parser.getName(); 799 if (tagName.equals("application")) { 800 if (foundApp) { 801 if (RIGID_PARSER) { 802 outError[0] = "<manifest> has more than one <application>"; 803 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 804 return null; 805 } else { 806 Log.w(TAG, "<manifest> has more than one <application>"); 807 XmlUtils.skipCurrentTag(parser); 808 continue; 809 } 810 } 811 812 foundApp = true; 813 if (!parseApplication(pkg, res, parser, attrs, flags, outError)) { 814 return null; 815 } 816 } else if (tagName.equals("permission-group")) { 817 if (parsePermissionGroup(pkg, res, parser, attrs, outError) == null) { 818 return null; 819 } 820 } else if (tagName.equals("permission")) { 821 if (parsePermission(pkg, res, parser, attrs, outError) == null) { 822 return null; 823 } 824 } else if (tagName.equals("permission-tree")) { 825 if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) { 826 return null; 827 } 828 } else if (tagName.equals("uses-permission")) { 829 sa = res.obtainAttributes(attrs, 830 com.android.internal.R.styleable.AndroidManifestUsesPermission); 831 832 // Note: don't allow this value to be a reference to a resource 833 // that may change. 834 String name = sa.getNonResourceString( 835 com.android.internal.R.styleable.AndroidManifestUsesPermission_name); 836 837 sa.recycle(); 838 839 if (name != null && !pkg.requestedPermissions.contains(name)) { 840 pkg.requestedPermissions.add(name.intern()); 841 } 842 843 XmlUtils.skipCurrentTag(parser); 844 845 } else if (tagName.equals("uses-configuration")) { 846 ConfigurationInfo cPref = new ConfigurationInfo(); 847 sa = res.obtainAttributes(attrs, 848 com.android.internal.R.styleable.AndroidManifestUsesConfiguration); 849 cPref.reqTouchScreen = sa.getInt( 850 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, 851 Configuration.TOUCHSCREEN_UNDEFINED); 852 cPref.reqKeyboardType = sa.getInt( 853 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, 854 Configuration.KEYBOARD_UNDEFINED); 855 if (sa.getBoolean( 856 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, 857 false)) { 858 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; 859 } 860 cPref.reqNavigation = sa.getInt( 861 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation, 862 Configuration.NAVIGATION_UNDEFINED); 863 if (sa.getBoolean( 864 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, 865 false)) { 866 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; 867 } 868 sa.recycle(); 869 pkg.configPreferences.add(cPref); 870 871 XmlUtils.skipCurrentTag(parser); 872 873 } else if (tagName.equals("uses-feature")) { 874 FeatureInfo fi = new FeatureInfo(); 875 sa = res.obtainAttributes(attrs, 876 com.android.internal.R.styleable.AndroidManifestUsesFeature); 877 // Note: don't allow this value to be a reference to a resource 878 // that may change. 879 fi.name = sa.getNonResourceString( 880 com.android.internal.R.styleable.AndroidManifestUsesFeature_name); 881 if (fi.name == null) { 882 fi.reqGlEsVersion = sa.getInt( 883 com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion, 884 FeatureInfo.GL_ES_VERSION_UNDEFINED); 885 } 886 if (sa.getBoolean( 887 com.android.internal.R.styleable.AndroidManifestUsesFeature_required, 888 true)) { 889 fi.flags |= FeatureInfo.FLAG_REQUIRED; 890 } 891 sa.recycle(); 892 if (pkg.reqFeatures == null) { 893 pkg.reqFeatures = new ArrayList<FeatureInfo>(); 894 } 895 pkg.reqFeatures.add(fi); 896 897 if (fi.name == null) { 898 ConfigurationInfo cPref = new ConfigurationInfo(); 899 cPref.reqGlEsVersion = fi.reqGlEsVersion; 900 pkg.configPreferences.add(cPref); 901 } 902 903 XmlUtils.skipCurrentTag(parser); 904 905 } else if (tagName.equals("uses-sdk")) { 906 if (SDK_VERSION > 0) { 907 sa = res.obtainAttributes(attrs, 908 com.android.internal.R.styleable.AndroidManifestUsesSdk); 909 910 int minVers = 0; 911 String minCode = null; 912 int targetVers = 0; 913 String targetCode = null; 914 915 TypedValue val = sa.peekValue( 916 com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); 917 if (val != null) { 918 if (val.type == TypedValue.TYPE_STRING && val.string != null) { 919 targetCode = minCode = val.string.toString(); 920 } else { 921 // If it's not a string, it's an integer. 922 targetVers = minVers = val.data; 923 } 924 } 925 926 val = sa.peekValue( 927 com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); 928 if (val != null) { 929 if (val.type == TypedValue.TYPE_STRING && val.string != null) { 930 targetCode = minCode = val.string.toString(); 931 } else { 932 // If it's not a string, it's an integer. 933 targetVers = val.data; 934 } 935 } 936 937 sa.recycle(); 938 939 if (minCode != null) { 940 if (!minCode.equals(SDK_CODENAME)) { 941 if (SDK_CODENAME != null) { 942 outError[0] = "Requires development platform " + minCode 943 + " (current platform is " + SDK_CODENAME + ")"; 944 } else { 945 outError[0] = "Requires development platform " + minCode 946 + " but this is a release platform."; 947 } 948 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 949 return null; 950 } 951 } else if (minVers > SDK_VERSION) { 952 outError[0] = "Requires newer sdk version #" + minVers 953 + " (current version is #" + SDK_VERSION + ")"; 954 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 955 return null; 956 } 957 958 if (targetCode != null) { 959 if (!targetCode.equals(SDK_CODENAME)) { 960 if (SDK_CODENAME != null) { 961 outError[0] = "Requires development platform " + targetCode 962 + " (current platform is " + SDK_CODENAME + ")"; 963 } else { 964 outError[0] = "Requires development platform " + targetCode 965 + " but this is a release platform."; 966 } 967 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 968 return null; 969 } 970 // If the code matches, it definitely targets this SDK. 971 pkg.applicationInfo.targetSdkVersion 972 = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; 973 } else { 974 pkg.applicationInfo.targetSdkVersion = targetVers; 975 } 976 } 977 978 XmlUtils.skipCurrentTag(parser); 979 980 } else if (tagName.equals("supports-screens")) { 981 sa = res.obtainAttributes(attrs, 982 com.android.internal.R.styleable.AndroidManifestSupportsScreens); 983 984 // This is a trick to get a boolean and still able to detect 985 // if a value was actually set. 986 supportsSmallScreens = sa.getInteger( 987 com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens, 988 supportsSmallScreens); 989 supportsNormalScreens = sa.getInteger( 990 com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens, 991 supportsNormalScreens); 992 supportsLargeScreens = sa.getInteger( 993 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens, 994 supportsLargeScreens); 995 resizeable = sa.getInteger( 996 com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable, 997 supportsLargeScreens); 998 anyDensity = sa.getInteger( 999 com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity, 1000 anyDensity); 1001 1002 sa.recycle(); 1003 1004 XmlUtils.skipCurrentTag(parser); 1005 1006 } else if (tagName.equals("protected-broadcast")) { 1007 sa = res.obtainAttributes(attrs, 1008 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast); 1009 1010 // Note: don't allow this value to be a reference to a resource 1011 // that may change. 1012 String name = sa.getNonResourceString( 1013 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name); 1014 1015 sa.recycle(); 1016 1017 if (name != null && (flags&PARSE_IS_SYSTEM) != 0) { 1018 if (pkg.protectedBroadcasts == null) { 1019 pkg.protectedBroadcasts = new ArrayList<String>(); 1020 } 1021 if (!pkg.protectedBroadcasts.contains(name)) { 1022 pkg.protectedBroadcasts.add(name.intern()); 1023 } 1024 } 1025 1026 XmlUtils.skipCurrentTag(parser); 1027 1028 } else if (tagName.equals("instrumentation")) { 1029 if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) { 1030 return null; 1031 } 1032 1033 } else if (tagName.equals("original-package")) { 1034 sa = res.obtainAttributes(attrs, 1035 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 1036 1037 String orig =sa.getNonConfigurationString( 1038 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 1039 if (!pkg.packageName.equals(orig)) { 1040 if (pkg.mOriginalPackages == null) { 1041 pkg.mOriginalPackages = new ArrayList<String>(); 1042 pkg.mRealPackage = pkg.packageName; 1043 } 1044 pkg.mOriginalPackages.add(orig); 1045 } 1046 1047 sa.recycle(); 1048 1049 XmlUtils.skipCurrentTag(parser); 1050 1051 } else if (tagName.equals("adopt-permissions")) { 1052 sa = res.obtainAttributes(attrs, 1053 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 1054 1055 String name = sa.getNonConfigurationString( 1056 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 1057 1058 sa.recycle(); 1059 1060 if (name != null) { 1061 if (pkg.mAdoptPermissions == null) { 1062 pkg.mAdoptPermissions = new ArrayList<String>(); 1063 } 1064 pkg.mAdoptPermissions.add(name); 1065 } 1066 1067 XmlUtils.skipCurrentTag(parser); 1068 1069 } else if (tagName.equals("eat-comment")) { 1070 // Just skip this tag 1071 XmlUtils.skipCurrentTag(parser); 1072 continue; 1073 1074 } else if (RIGID_PARSER) { 1075 outError[0] = "Bad element under <manifest>: " 1076 + parser.getName(); 1077 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1078 return null; 1079 1080 } else { 1081 Log.w(TAG, "Unknown element under <manifest>: " + parser.getName() 1082 + " at " + mArchiveSourcePath + " " 1083 + parser.getPositionDescription()); 1084 XmlUtils.skipCurrentTag(parser); 1085 continue; 1086 } 1087 } 1088 1089 if (!foundApp && pkg.instrumentation.size() == 0) { 1090 outError[0] = "<manifest> does not contain an <application> or <instrumentation>"; 1091 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; 1092 } 1093 1094 final int NP = PackageParser.NEW_PERMISSIONS.length; 1095 StringBuilder implicitPerms = null; 1096 for (int ip=0; ip<NP; ip++) { 1097 final PackageParser.NewPermissionInfo npi 1098 = PackageParser.NEW_PERMISSIONS[ip]; 1099 if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) { 1100 break; 1101 } 1102 if (!pkg.requestedPermissions.contains(npi.name)) { 1103 if (implicitPerms == null) { 1104 implicitPerms = new StringBuilder(128); 1105 implicitPerms.append(pkg.packageName); 1106 implicitPerms.append(": compat added "); 1107 } else { 1108 implicitPerms.append(' '); 1109 } 1110 implicitPerms.append(npi.name); 1111 pkg.requestedPermissions.add(npi.name); 1112 } 1113 } 1114 if (implicitPerms != null) { 1115 Log.i(TAG, implicitPerms.toString()); 1116 } 1117 1118 if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 1119 && pkg.applicationInfo.targetSdkVersion 1120 >= android.os.Build.VERSION_CODES.DONUT)) { 1121 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; 1122 } 1123 if (supportsNormalScreens != 0) { 1124 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; 1125 } 1126 if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 1127 && pkg.applicationInfo.targetSdkVersion 1128 >= android.os.Build.VERSION_CODES.DONUT)) { 1129 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; 1130 } 1131 if (resizeable < 0 || (resizeable > 0 1132 && pkg.applicationInfo.targetSdkVersion 1133 >= android.os.Build.VERSION_CODES.DONUT)) { 1134 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; 1135 } 1136 if (anyDensity < 0 || (anyDensity > 0 1137 && pkg.applicationInfo.targetSdkVersion 1138 >= android.os.Build.VERSION_CODES.DONUT)) { 1139 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; 1140 } 1141 1142 return pkg; 1143 } 1144 1145 private static String buildClassName(String pkg, CharSequence clsSeq, 1146 String[] outError) { 1147 if (clsSeq == null || clsSeq.length() <= 0) { 1148 outError[0] = "Empty class name in package " + pkg; 1149 return null; 1150 } 1151 String cls = clsSeq.toString(); 1152 char c = cls.charAt(0); 1153 if (c == '.') { 1154 return (pkg + cls).intern(); 1155 } 1156 if (cls.indexOf('.') < 0) { 1157 StringBuilder b = new StringBuilder(pkg); 1158 b.append('.'); 1159 b.append(cls); 1160 return b.toString().intern(); 1161 } 1162 if (c >= 'a' && c <= 'z') { 1163 return cls.intern(); 1164 } 1165 outError[0] = "Bad class name " + cls + " in package " + pkg; 1166 return null; 1167 } 1168 1169 private static String buildCompoundName(String pkg, 1170 CharSequence procSeq, String type, String[] outError) { 1171 String proc = procSeq.toString(); 1172 char c = proc.charAt(0); 1173 if (pkg != null && c == ':') { 1174 if (proc.length() < 2) { 1175 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg 1176 + ": must be at least two characters"; 1177 return null; 1178 } 1179 String subName = proc.substring(1); 1180 String nameError = validateName(subName, false); 1181 if (nameError != null) { 1182 outError[0] = "Invalid " + type + " name " + proc + " in package " 1183 + pkg + ": " + nameError; 1184 return null; 1185 } 1186 return (pkg + proc).intern(); 1187 } 1188 String nameError = validateName(proc, true); 1189 if (nameError != null && !"system".equals(proc)) { 1190 outError[0] = "Invalid " + type + " name " + proc + " in package " 1191 + pkg + ": " + nameError; 1192 return null; 1193 } 1194 return proc.intern(); 1195 } 1196 1197 private static String buildProcessName(String pkg, String defProc, 1198 CharSequence procSeq, int flags, String[] separateProcesses, 1199 String[] outError) { 1200 if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) { 1201 return defProc != null ? defProc : pkg; 1202 } 1203 if (separateProcesses != null) { 1204 for (int i=separateProcesses.length-1; i>=0; i--) { 1205 String sp = separateProcesses[i]; 1206 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) { 1207 return pkg; 1208 } 1209 } 1210 } 1211 if (procSeq == null || procSeq.length() <= 0) { 1212 return defProc; 1213 } 1214 return buildCompoundName(pkg, procSeq, "package", outError); 1215 } 1216 1217 private static String buildTaskAffinityName(String pkg, String defProc, 1218 CharSequence procSeq, String[] outError) { 1219 if (procSeq == null) { 1220 return defProc; 1221 } 1222 if (procSeq.length() <= 0) { 1223 return null; 1224 } 1225 return buildCompoundName(pkg, procSeq, "taskAffinity", outError); 1226 } 1227 1228 private PermissionGroup parsePermissionGroup(Package owner, Resources res, 1229 XmlPullParser parser, AttributeSet attrs, String[] outError) 1230 throws XmlPullParserException, IOException { 1231 PermissionGroup perm = new PermissionGroup(owner); 1232 1233 TypedArray sa = res.obtainAttributes(attrs, 1234 com.android.internal.R.styleable.AndroidManifestPermissionGroup); 1235 1236 if (!parsePackageItemInfo(owner, perm.info, outError, 1237 "<permission-group>", sa, 1238 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name, 1239 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label, 1240 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon)) { 1241 sa.recycle(); 1242 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1243 return null; 1244 } 1245 1246 perm.info.descriptionRes = sa.getResourceId( 1247 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description, 1248 0); 1249 1250 sa.recycle(); 1251 1252 if (!parseAllMetaData(res, parser, attrs, "<permission-group>", perm, 1253 outError)) { 1254 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1255 return null; 1256 } 1257 1258 owner.permissionGroups.add(perm); 1259 1260 return perm; 1261 } 1262 1263 private Permission parsePermission(Package owner, Resources res, 1264 XmlPullParser parser, AttributeSet attrs, String[] outError) 1265 throws XmlPullParserException, IOException { 1266 Permission perm = new Permission(owner); 1267 1268 TypedArray sa = res.obtainAttributes(attrs, 1269 com.android.internal.R.styleable.AndroidManifestPermission); 1270 1271 if (!parsePackageItemInfo(owner, perm.info, outError, 1272 "<permission>", sa, 1273 com.android.internal.R.styleable.AndroidManifestPermission_name, 1274 com.android.internal.R.styleable.AndroidManifestPermission_label, 1275 com.android.internal.R.styleable.AndroidManifestPermission_icon)) { 1276 sa.recycle(); 1277 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1278 return null; 1279 } 1280 1281 // Note: don't allow this value to be a reference to a resource 1282 // that may change. 1283 perm.info.group = sa.getNonResourceString( 1284 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup); 1285 if (perm.info.group != null) { 1286 perm.info.group = perm.info.group.intern(); 1287 } 1288 1289 perm.info.descriptionRes = sa.getResourceId( 1290 com.android.internal.R.styleable.AndroidManifestPermission_description, 1291 0); 1292 1293 perm.info.protectionLevel = sa.getInt( 1294 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel, 1295 PermissionInfo.PROTECTION_NORMAL); 1296 1297 sa.recycle(); 1298 1299 if (perm.info.protectionLevel == -1) { 1300 outError[0] = "<permission> does not specify protectionLevel"; 1301 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1302 return null; 1303 } 1304 1305 if (!parseAllMetaData(res, parser, attrs, "<permission>", perm, 1306 outError)) { 1307 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1308 return null; 1309 } 1310 1311 owner.permissions.add(perm); 1312 1313 return perm; 1314 } 1315 1316 private Permission parsePermissionTree(Package owner, Resources res, 1317 XmlPullParser parser, AttributeSet attrs, String[] outError) 1318 throws XmlPullParserException, IOException { 1319 Permission perm = new Permission(owner); 1320 1321 TypedArray sa = res.obtainAttributes(attrs, 1322 com.android.internal.R.styleable.AndroidManifestPermissionTree); 1323 1324 if (!parsePackageItemInfo(owner, perm.info, outError, 1325 "<permission-tree>", sa, 1326 com.android.internal.R.styleable.AndroidManifestPermissionTree_name, 1327 com.android.internal.R.styleable.AndroidManifestPermissionTree_label, 1328 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon)) { 1329 sa.recycle(); 1330 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1331 return null; 1332 } 1333 1334 sa.recycle(); 1335 1336 int index = perm.info.name.indexOf('.'); 1337 if (index > 0) { 1338 index = perm.info.name.indexOf('.', index+1); 1339 } 1340 if (index < 0) { 1341 outError[0] = "<permission-tree> name has less than three segments: " 1342 + perm.info.name; 1343 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1344 return null; 1345 } 1346 1347 perm.info.descriptionRes = 0; 1348 perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL; 1349 perm.tree = true; 1350 1351 if (!parseAllMetaData(res, parser, attrs, "<permission-tree>", perm, 1352 outError)) { 1353 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1354 return null; 1355 } 1356 1357 owner.permissions.add(perm); 1358 1359 return perm; 1360 } 1361 1362 private Instrumentation parseInstrumentation(Package owner, Resources res, 1363 XmlPullParser parser, AttributeSet attrs, String[] outError) 1364 throws XmlPullParserException, IOException { 1365 TypedArray sa = res.obtainAttributes(attrs, 1366 com.android.internal.R.styleable.AndroidManifestInstrumentation); 1367 1368 if (mParseInstrumentationArgs == null) { 1369 mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError, 1370 com.android.internal.R.styleable.AndroidManifestInstrumentation_name, 1371 com.android.internal.R.styleable.AndroidManifestInstrumentation_label, 1372 com.android.internal.R.styleable.AndroidManifestInstrumentation_icon); 1373 mParseInstrumentationArgs.tag = "<instrumentation>"; 1374 } 1375 1376 mParseInstrumentationArgs.sa = sa; 1377 1378 Instrumentation a = new Instrumentation(mParseInstrumentationArgs, 1379 new InstrumentationInfo()); 1380 if (outError[0] != null) { 1381 sa.recycle(); 1382 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1383 return null; 1384 } 1385 1386 String str; 1387 // Note: don't allow this value to be a reference to a resource 1388 // that may change. 1389 str = sa.getNonResourceString( 1390 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage); 1391 a.info.targetPackage = str != null ? str.intern() : null; 1392 1393 a.info.handleProfiling = sa.getBoolean( 1394 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling, 1395 false); 1396 1397 a.info.functionalTest = sa.getBoolean( 1398 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest, 1399 false); 1400 1401 sa.recycle(); 1402 1403 if (a.info.targetPackage == null) { 1404 outError[0] = "<instrumentation> does not specify targetPackage"; 1405 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1406 return null; 1407 } 1408 1409 if (!parseAllMetaData(res, parser, attrs, "<instrumentation>", a, 1410 outError)) { 1411 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1412 return null; 1413 } 1414 1415 owner.instrumentation.add(a); 1416 1417 return a; 1418 } 1419 1420 private boolean parseApplication(Package owner, Resources res, 1421 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 1422 throws XmlPullParserException, IOException { 1423 final ApplicationInfo ai = owner.applicationInfo; 1424 final String pkgName = owner.applicationInfo.packageName; 1425 1426 TypedArray sa = res.obtainAttributes(attrs, 1427 com.android.internal.R.styleable.AndroidManifestApplication); 1428 1429 String name = sa.getNonConfigurationString( 1430 com.android.internal.R.styleable.AndroidManifestApplication_name, 0); 1431 if (name != null) { 1432 ai.className = buildClassName(pkgName, name, outError); 1433 if (ai.className == null) { 1434 sa.recycle(); 1435 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1436 return false; 1437 } 1438 } 1439 1440 String manageSpaceActivity = sa.getNonConfigurationString( 1441 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity, 0); 1442 if (manageSpaceActivity != null) { 1443 ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity, 1444 outError); 1445 } 1446 1447 boolean allowBackup = sa.getBoolean( 1448 com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true); 1449 if (allowBackup) { 1450 ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; 1451 1452 // backupAgent, killAfterRestore, and restoreAnyVersion are only relevant 1453 // if backup is possible for the given application. 1454 String backupAgent = sa.getNonConfigurationString( 1455 com.android.internal.R.styleable.AndroidManifestApplication_backupAgent, 0); 1456 if (backupAgent != null) { 1457 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError); 1458 if (false) { 1459 Log.v(TAG, "android:backupAgent = " + ai.backupAgentName 1460 + " from " + pkgName + "+" + backupAgent); 1461 } 1462 1463 if (sa.getBoolean( 1464 com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore, 1465 true)) { 1466 ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE; 1467 } 1468 if (sa.getBoolean( 1469 com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion, 1470 false)) { 1471 ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION; 1472 } 1473 } 1474 } 1475 1476 TypedValue v = sa.peekValue( 1477 com.android.internal.R.styleable.AndroidManifestApplication_label); 1478 if (v != null && (ai.labelRes=v.resourceId) == 0) { 1479 ai.nonLocalizedLabel = v.coerceToString(); 1480 } 1481 1482 ai.icon = sa.getResourceId( 1483 com.android.internal.R.styleable.AndroidManifestApplication_icon, 0); 1484 ai.theme = sa.getResourceId( 1485 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); 1486 ai.descriptionRes = sa.getResourceId( 1487 com.android.internal.R.styleable.AndroidManifestApplication_description, 0); 1488 1489 if ((flags&PARSE_IS_SYSTEM) != 0) { 1490 if (sa.getBoolean( 1491 com.android.internal.R.styleable.AndroidManifestApplication_persistent, 1492 false)) { 1493 ai.flags |= ApplicationInfo.FLAG_PERSISTENT; 1494 } 1495 } 1496 1497 if ((flags & PARSE_FORWARD_LOCK) != 0) { 1498 ai.flags |= ApplicationInfo.FLAG_FORWARD_LOCK; 1499 } 1500 1501 if ((flags & PARSE_ON_SDCARD) != 0) { 1502 ai.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; 1503 } 1504 1505 if (sa.getBoolean( 1506 com.android.internal.R.styleable.AndroidManifestApplication_debuggable, 1507 false)) { 1508 ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE; 1509 } 1510 1511 if (sa.getBoolean( 1512 com.android.internal.R.styleable.AndroidManifestApplication_safeMode, 1513 false)) { 1514 ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE; 1515 } 1516 1517 if (sa.getBoolean( 1518 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, 1519 true)) { 1520 ai.flags |= ApplicationInfo.FLAG_HAS_CODE; 1521 } 1522 1523 if (sa.getBoolean( 1524 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting, 1525 false)) { 1526 ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; 1527 } 1528 1529 if (sa.getBoolean( 1530 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData, 1531 true)) { 1532 ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; 1533 } 1534 1535 if (sa.getBoolean( 1536 com.android.internal.R.styleable.AndroidManifestApplication_testOnly, 1537 false)) { 1538 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY; 1539 } 1540 1541 if (sa.getBoolean( 1542 com.android.internal.R.styleable.AndroidManifestApplication_neverEncrypt, 1543 false)) { 1544 ai.flags |= ApplicationInfo.FLAG_NEVER_ENCRYPT; 1545 } 1546 1547 String str; 1548 str = sa.getNonConfigurationString( 1549 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0); 1550 ai.permission = (str != null && str.length() > 0) ? str.intern() : null; 1551 1552 str = sa.getNonConfigurationString( 1553 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, 0); 1554 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName, 1555 str, outError); 1556 1557 if (outError[0] == null) { 1558 ai.processName = buildProcessName(ai.packageName, null, sa.getNonConfigurationString( 1559 com.android.internal.R.styleable.AndroidManifestApplication_process, 0), 1560 flags, mSeparateProcesses, outError); 1561 1562 ai.enabled = sa.getBoolean( 1563 com.android.internal.R.styleable.AndroidManifestApplication_enabled, true); 1564 } 1565 1566 sa.recycle(); 1567 1568 if (outError[0] != null) { 1569 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1570 return false; 1571 } 1572 1573 final int innerDepth = parser.getDepth(); 1574 1575 int type; 1576 while ((type=parser.next()) != parser.END_DOCUMENT 1577 && (type != parser.END_TAG || parser.getDepth() > innerDepth)) { 1578 if (type == parser.END_TAG || type == parser.TEXT) { 1579 continue; 1580 } 1581 1582 String tagName = parser.getName(); 1583 if (tagName.equals("activity")) { 1584 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false); 1585 if (a == null) { 1586 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1587 return false; 1588 } 1589 1590 owner.activities.add(a); 1591 1592 } else if (tagName.equals("receiver")) { 1593 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true); 1594 if (a == null) { 1595 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1596 return false; 1597 } 1598 1599 owner.receivers.add(a); 1600 1601 } else if (tagName.equals("service")) { 1602 Service s = parseService(owner, res, parser, attrs, flags, outError); 1603 if (s == null) { 1604 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1605 return false; 1606 } 1607 1608 owner.services.add(s); 1609 1610 } else if (tagName.equals("provider")) { 1611 Provider p = parseProvider(owner, res, parser, attrs, flags, outError); 1612 if (p == null) { 1613 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1614 return false; 1615 } 1616 1617 owner.providers.add(p); 1618 1619 } else if (tagName.equals("activity-alias")) { 1620 Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError); 1621 if (a == null) { 1622 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1623 return false; 1624 } 1625 1626 owner.activities.add(a); 1627 1628 } else if (parser.getName().equals("meta-data")) { 1629 // note: application meta-data is stored off to the side, so it can 1630 // remain null in the primary copy (we like to avoid extra copies because 1631 // it can be large) 1632 if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData, 1633 outError)) == null) { 1634 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1635 return false; 1636 } 1637 1638 } else if (tagName.equals("uses-library")) { 1639 sa = res.obtainAttributes(attrs, 1640 com.android.internal.R.styleable.AndroidManifestUsesLibrary); 1641 1642 // Note: don't allow this value to be a reference to a resource 1643 // that may change. 1644 String lname = sa.getNonResourceString( 1645 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 1646 boolean req = sa.getBoolean( 1647 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, 1648 true); 1649 1650 sa.recycle(); 1651 1652 if (lname != null) { 1653 if (req) { 1654 if (owner.usesLibraries == null) { 1655 owner.usesLibraries = new ArrayList<String>(); 1656 } 1657 if (!owner.usesLibraries.contains(lname)) { 1658 owner.usesLibraries.add(lname.intern()); 1659 } 1660 } else { 1661 if (owner.usesOptionalLibraries == null) { 1662 owner.usesOptionalLibraries = new ArrayList<String>(); 1663 } 1664 if (!owner.usesOptionalLibraries.contains(lname)) { 1665 owner.usesOptionalLibraries.add(lname.intern()); 1666 } 1667 } 1668 } 1669 1670 XmlUtils.skipCurrentTag(parser); 1671 1672 } else { 1673 if (!RIGID_PARSER) { 1674 Log.w(TAG, "Unknown element under <application>: " + tagName 1675 + " at " + mArchiveSourcePath + " " 1676 + parser.getPositionDescription()); 1677 XmlUtils.skipCurrentTag(parser); 1678 continue; 1679 } else { 1680 outError[0] = "Bad element under <application>: " + tagName; 1681 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1682 return false; 1683 } 1684 } 1685 } 1686 1687 return true; 1688 } 1689 1690 private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo, 1691 String[] outError, String tag, TypedArray sa, 1692 int nameRes, int labelRes, int iconRes) { 1693 String name = sa.getNonConfigurationString(nameRes, 0); 1694 if (name == null) { 1695 outError[0] = tag + " does not specify android:name"; 1696 return false; 1697 } 1698 1699 outInfo.name 1700 = buildClassName(owner.applicationInfo.packageName, name, outError); 1701 if (outInfo.name == null) { 1702 return false; 1703 } 1704 1705 int iconVal = sa.getResourceId(iconRes, 0); 1706 if (iconVal != 0) { 1707 outInfo.icon = iconVal; 1708 outInfo.nonLocalizedLabel = null; 1709 } 1710 1711 TypedValue v = sa.peekValue(labelRes); 1712 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 1713 outInfo.nonLocalizedLabel = v.coerceToString(); 1714 } 1715 1716 outInfo.packageName = owner.packageName; 1717 1718 return true; 1719 } 1720 1721 private Activity parseActivity(Package owner, Resources res, 1722 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError, 1723 boolean receiver) throws XmlPullParserException, IOException { 1724 TypedArray sa = res.obtainAttributes(attrs, 1725 com.android.internal.R.styleable.AndroidManifestActivity); 1726 1727 if (mParseActivityArgs == null) { 1728 mParseActivityArgs = new ParseComponentArgs(owner, outError, 1729 com.android.internal.R.styleable.AndroidManifestActivity_name, 1730 com.android.internal.R.styleable.AndroidManifestActivity_label, 1731 com.android.internal.R.styleable.AndroidManifestActivity_icon, 1732 mSeparateProcesses, 1733 com.android.internal.R.styleable.AndroidManifestActivity_process, 1734 com.android.internal.R.styleable.AndroidManifestActivity_description, 1735 com.android.internal.R.styleable.AndroidManifestActivity_enabled); 1736 } 1737 1738 mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>"; 1739 mParseActivityArgs.sa = sa; 1740 mParseActivityArgs.flags = flags; 1741 1742 Activity a = new Activity(mParseActivityArgs, new ActivityInfo()); 1743 if (outError[0] != null) { 1744 sa.recycle(); 1745 return null; 1746 } 1747 1748 final boolean setExported = sa.hasValue( 1749 com.android.internal.R.styleable.AndroidManifestActivity_exported); 1750 if (setExported) { 1751 a.info.exported = sa.getBoolean( 1752 com.android.internal.R.styleable.AndroidManifestActivity_exported, false); 1753 } 1754 1755 a.info.theme = sa.getResourceId( 1756 com.android.internal.R.styleable.AndroidManifestActivity_theme, 0); 1757 1758 String str; 1759 str = sa.getNonConfigurationString( 1760 com.android.internal.R.styleable.AndroidManifestActivity_permission, 0); 1761 if (str == null) { 1762 a.info.permission = owner.applicationInfo.permission; 1763 } else { 1764 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 1765 } 1766 1767 str = sa.getNonConfigurationString( 1768 com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity, 0); 1769 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName, 1770 owner.applicationInfo.taskAffinity, str, outError); 1771 1772 a.info.flags = 0; 1773 if (sa.getBoolean( 1774 com.android.internal.R.styleable.AndroidManifestActivity_multiprocess, 1775 false)) { 1776 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS; 1777 } 1778 1779 if (sa.getBoolean( 1780 com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch, 1781 false)) { 1782 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; 1783 } 1784 1785 if (sa.getBoolean( 1786 com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch, 1787 false)) { 1788 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; 1789 } 1790 1791 if (sa.getBoolean( 1792 com.android.internal.R.styleable.AndroidManifestActivity_noHistory, 1793 false)) { 1794 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY; 1795 } 1796 1797 if (sa.getBoolean( 1798 com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState, 1799 false)) { 1800 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; 1801 } 1802 1803 if (sa.getBoolean( 1804 com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded, 1805 false)) { 1806 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; 1807 } 1808 1809 if (sa.getBoolean( 1810 com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents, 1811 false)) { 1812 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; 1813 } 1814 1815 if (sa.getBoolean( 1816 com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting, 1817 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) { 1818 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; 1819 } 1820 1821 if (sa.getBoolean( 1822 com.android.internal.R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, 1823 false)) { 1824 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; 1825 } 1826 1827 if (!receiver) { 1828 a.info.launchMode = sa.getInt( 1829 com.android.internal.R.styleable.AndroidManifestActivity_launchMode, 1830 ActivityInfo.LAUNCH_MULTIPLE); 1831 a.info.screenOrientation = sa.getInt( 1832 com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation, 1833 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1834 a.info.configChanges = sa.getInt( 1835 com.android.internal.R.styleable.AndroidManifestActivity_configChanges, 1836 0); 1837 a.info.softInputMode = sa.getInt( 1838 com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode, 1839 0); 1840 } else { 1841 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; 1842 a.info.configChanges = 0; 1843 } 1844 1845 sa.recycle(); 1846 1847 if (outError[0] != null) { 1848 return null; 1849 } 1850 1851 int outerDepth = parser.getDepth(); 1852 int type; 1853 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 1854 && (type != XmlPullParser.END_TAG 1855 || parser.getDepth() > outerDepth)) { 1856 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1857 continue; 1858 } 1859 1860 if (parser.getName().equals("intent-filter")) { 1861 ActivityIntentInfo intent = new ActivityIntentInfo(a); 1862 if (!parseIntent(res, parser, attrs, flags, intent, outError, !receiver)) { 1863 return null; 1864 } 1865 if (intent.countActions() == 0) { 1866 Log.w(TAG, "No actions in intent filter at " 1867 + mArchiveSourcePath + " " 1868 + parser.getPositionDescription()); 1869 } else { 1870 a.intents.add(intent); 1871 } 1872 } else if (parser.getName().equals("meta-data")) { 1873 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData, 1874 outError)) == null) { 1875 return null; 1876 } 1877 } else { 1878 if (!RIGID_PARSER) { 1879 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 1880 if (receiver) { 1881 Log.w(TAG, "Unknown element under <receiver>: " + parser.getName() 1882 + " at " + mArchiveSourcePath + " " 1883 + parser.getPositionDescription()); 1884 } else { 1885 Log.w(TAG, "Unknown element under <activity>: " + parser.getName() 1886 + " at " + mArchiveSourcePath + " " 1887 + parser.getPositionDescription()); 1888 } 1889 XmlUtils.skipCurrentTag(parser); 1890 continue; 1891 } 1892 if (receiver) { 1893 outError[0] = "Bad element under <receiver>: " + parser.getName(); 1894 } else { 1895 outError[0] = "Bad element under <activity>: " + parser.getName(); 1896 } 1897 return null; 1898 } 1899 } 1900 1901 if (!setExported) { 1902 a.info.exported = a.intents.size() > 0; 1903 } 1904 1905 return a; 1906 } 1907 1908 private Activity parseActivityAlias(Package owner, Resources res, 1909 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 1910 throws XmlPullParserException, IOException { 1911 TypedArray sa = res.obtainAttributes(attrs, 1912 com.android.internal.R.styleable.AndroidManifestActivityAlias); 1913 1914 String targetActivity = sa.getNonConfigurationString( 1915 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity, 0); 1916 if (targetActivity == null) { 1917 outError[0] = "<activity-alias> does not specify android:targetActivity"; 1918 sa.recycle(); 1919 return null; 1920 } 1921 1922 targetActivity = buildClassName(owner.applicationInfo.packageName, 1923 targetActivity, outError); 1924 if (targetActivity == null) { 1925 sa.recycle(); 1926 return null; 1927 } 1928 1929 if (mParseActivityAliasArgs == null) { 1930 mParseActivityAliasArgs = new ParseComponentArgs(owner, outError, 1931 com.android.internal.R.styleable.AndroidManifestActivityAlias_name, 1932 com.android.internal.R.styleable.AndroidManifestActivityAlias_label, 1933 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, 1934 mSeparateProcesses, 1935 0, 1936 com.android.internal.R.styleable.AndroidManifestActivityAlias_description, 1937 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled); 1938 mParseActivityAliasArgs.tag = "<activity-alias>"; 1939 } 1940 1941 mParseActivityAliasArgs.sa = sa; 1942 mParseActivityAliasArgs.flags = flags; 1943 1944 Activity target = null; 1945 1946 final int NA = owner.activities.size(); 1947 for (int i=0; i<NA; i++) { 1948 Activity t = owner.activities.get(i); 1949 if (targetActivity.equals(t.info.name)) { 1950 target = t; 1951 break; 1952 } 1953 } 1954 1955 if (target == null) { 1956 outError[0] = "<activity-alias> target activity " + targetActivity 1957 + " not found in manifest"; 1958 sa.recycle(); 1959 return null; 1960 } 1961 1962 ActivityInfo info = new ActivityInfo(); 1963 info.targetActivity = targetActivity; 1964 info.configChanges = target.info.configChanges; 1965 info.flags = target.info.flags; 1966 info.icon = target.info.icon; 1967 info.labelRes = target.info.labelRes; 1968 info.nonLocalizedLabel = target.info.nonLocalizedLabel; 1969 info.launchMode = target.info.launchMode; 1970 info.processName = target.info.processName; 1971 if (info.descriptionRes == 0) { 1972 info.descriptionRes = target.info.descriptionRes; 1973 } 1974 info.screenOrientation = target.info.screenOrientation; 1975 info.taskAffinity = target.info.taskAffinity; 1976 info.theme = target.info.theme; 1977 1978 Activity a = new Activity(mParseActivityAliasArgs, info); 1979 if (outError[0] != null) { 1980 sa.recycle(); 1981 return null; 1982 } 1983 1984 final boolean setExported = sa.hasValue( 1985 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported); 1986 if (setExported) { 1987 a.info.exported = sa.getBoolean( 1988 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false); 1989 } 1990 1991 String str; 1992 str = sa.getNonConfigurationString( 1993 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0); 1994 if (str != null) { 1995 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 1996 } 1997 1998 sa.recycle(); 1999 2000 if (outError[0] != null) { 2001 return null; 2002 } 2003 2004 int outerDepth = parser.getDepth(); 2005 int type; 2006 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2007 && (type != XmlPullParser.END_TAG 2008 || parser.getDepth() > outerDepth)) { 2009 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2010 continue; 2011 } 2012 2013 if (parser.getName().equals("intent-filter")) { 2014 ActivityIntentInfo intent = new ActivityIntentInfo(a); 2015 if (!parseIntent(res, parser, attrs, flags, intent, outError, true)) { 2016 return null; 2017 } 2018 if (intent.countActions() == 0) { 2019 Log.w(TAG, "No actions in intent filter at " 2020 + mArchiveSourcePath + " " 2021 + parser.getPositionDescription()); 2022 } else { 2023 a.intents.add(intent); 2024 } 2025 } else if (parser.getName().equals("meta-data")) { 2026 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData, 2027 outError)) == null) { 2028 return null; 2029 } 2030 } else { 2031 if (!RIGID_PARSER) { 2032 Log.w(TAG, "Unknown element under <activity-alias>: " + parser.getName() 2033 + " at " + mArchiveSourcePath + " " 2034 + parser.getPositionDescription()); 2035 XmlUtils.skipCurrentTag(parser); 2036 continue; 2037 } 2038 outError[0] = "Bad element under <activity-alias>: " + parser.getName(); 2039 return null; 2040 } 2041 } 2042 2043 if (!setExported) { 2044 a.info.exported = a.intents.size() > 0; 2045 } 2046 2047 return a; 2048 } 2049 2050 private Provider parseProvider(Package owner, Resources res, 2051 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 2052 throws XmlPullParserException, IOException { 2053 TypedArray sa = res.obtainAttributes(attrs, 2054 com.android.internal.R.styleable.AndroidManifestProvider); 2055 2056 if (mParseProviderArgs == null) { 2057 mParseProviderArgs = new ParseComponentArgs(owner, outError, 2058 com.android.internal.R.styleable.AndroidManifestProvider_name, 2059 com.android.internal.R.styleable.AndroidManifestProvider_label, 2060 com.android.internal.R.styleable.AndroidManifestProvider_icon, 2061 mSeparateProcesses, 2062 com.android.internal.R.styleable.AndroidManifestProvider_process, 2063 com.android.internal.R.styleable.AndroidManifestProvider_description, 2064 com.android.internal.R.styleable.AndroidManifestProvider_enabled); 2065 mParseProviderArgs.tag = "<provider>"; 2066 } 2067 2068 mParseProviderArgs.sa = sa; 2069 mParseProviderArgs.flags = flags; 2070 2071 Provider p = new Provider(mParseProviderArgs, new ProviderInfo()); 2072 if (outError[0] != null) { 2073 sa.recycle(); 2074 return null; 2075 } 2076 2077 p.info.exported = sa.getBoolean( 2078 com.android.internal.R.styleable.AndroidManifestProvider_exported, true); 2079 2080 String cpname = sa.getNonConfigurationString( 2081 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0); 2082 2083 p.info.isSyncable = sa.getBoolean( 2084 com.android.internal.R.styleable.AndroidManifestProvider_syncable, 2085 false); 2086 2087 String permission = sa.getNonConfigurationString( 2088 com.android.internal.R.styleable.AndroidManifestProvider_permission, 0); 2089 String str = sa.getNonConfigurationString( 2090 com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0); 2091 if (str == null) { 2092 str = permission; 2093 } 2094 if (str == null) { 2095 p.info.readPermission = owner.applicationInfo.permission; 2096 } else { 2097 p.info.readPermission = 2098 str.length() > 0 ? str.toString().intern() : null; 2099 } 2100 str = sa.getNonConfigurationString( 2101 com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0); 2102 if (str == null) { 2103 str = permission; 2104 } 2105 if (str == null) { 2106 p.info.writePermission = owner.applicationInfo.permission; 2107 } else { 2108 p.info.writePermission = 2109 str.length() > 0 ? str.toString().intern() : null; 2110 } 2111 2112 p.info.grantUriPermissions = sa.getBoolean( 2113 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions, 2114 false); 2115 2116 p.info.multiprocess = sa.getBoolean( 2117 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess, 2118 false); 2119 2120 p.info.initOrder = sa.getInt( 2121 com.android.internal.R.styleable.AndroidManifestProvider_initOrder, 2122 0); 2123 2124 sa.recycle(); 2125 2126 if (cpname == null) { 2127 outError[0] = "<provider> does not incude authorities attribute"; 2128 return null; 2129 } 2130 p.info.authority = cpname.intern(); 2131 2132 if (!parseProviderTags(res, parser, attrs, p, outError)) { 2133 return null; 2134 } 2135 2136 return p; 2137 } 2138 2139 private boolean parseProviderTags(Resources res, 2140 XmlPullParser parser, AttributeSet attrs, 2141 Provider outInfo, String[] outError) 2142 throws XmlPullParserException, IOException { 2143 int outerDepth = parser.getDepth(); 2144 int type; 2145 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2146 && (type != XmlPullParser.END_TAG 2147 || parser.getDepth() > outerDepth)) { 2148 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2149 continue; 2150 } 2151 2152 if (parser.getName().equals("meta-data")) { 2153 if ((outInfo.metaData=parseMetaData(res, parser, attrs, 2154 outInfo.metaData, outError)) == null) { 2155 return false; 2156 } 2157 2158 } else if (parser.getName().equals("grant-uri-permission")) { 2159 TypedArray sa = res.obtainAttributes(attrs, 2160 com.android.internal.R.styleable.AndroidManifestGrantUriPermission); 2161 2162 PatternMatcher pa = null; 2163 2164 String str = sa.getNonConfigurationString( 2165 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0); 2166 if (str != null) { 2167 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); 2168 } 2169 2170 str = sa.getNonConfigurationString( 2171 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); 2172 if (str != null) { 2173 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); 2174 } 2175 2176 str = sa.getNonConfigurationString( 2177 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); 2178 if (str != null) { 2179 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 2180 } 2181 2182 sa.recycle(); 2183 2184 if (pa != null) { 2185 if (outInfo.info.uriPermissionPatterns == null) { 2186 outInfo.info.uriPermissionPatterns = new PatternMatcher[1]; 2187 outInfo.info.uriPermissionPatterns[0] = pa; 2188 } else { 2189 final int N = outInfo.info.uriPermissionPatterns.length; 2190 PatternMatcher[] newp = new PatternMatcher[N+1]; 2191 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N); 2192 newp[N] = pa; 2193 outInfo.info.uriPermissionPatterns = newp; 2194 } 2195 outInfo.info.grantUriPermissions = true; 2196 } else { 2197 if (!RIGID_PARSER) { 2198 Log.w(TAG, "Unknown element under <path-permission>: " 2199 + parser.getName() + " at " + mArchiveSourcePath + " " 2200 + parser.getPositionDescription()); 2201 XmlUtils.skipCurrentTag(parser); 2202 continue; 2203 } 2204 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 2205 return false; 2206 } 2207 XmlUtils.skipCurrentTag(parser); 2208 2209 } else if (parser.getName().equals("path-permission")) { 2210 TypedArray sa = res.obtainAttributes(attrs, 2211 com.android.internal.R.styleable.AndroidManifestPathPermission); 2212 2213 PathPermission pa = null; 2214 2215 String permission = sa.getNonConfigurationString( 2216 com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0); 2217 String readPermission = sa.getNonConfigurationString( 2218 com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0); 2219 if (readPermission == null) { 2220 readPermission = permission; 2221 } 2222 String writePermission = sa.getNonConfigurationString( 2223 com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0); 2224 if (writePermission == null) { 2225 writePermission = permission; 2226 } 2227 2228 boolean havePerm = false; 2229 if (readPermission != null) { 2230 readPermission = readPermission.intern(); 2231 havePerm = true; 2232 } 2233 if (writePermission != null) { 2234 writePermission = writePermission.intern(); 2235 havePerm = true; 2236 } 2237 2238 if (!havePerm) { 2239 if (!RIGID_PARSER) { 2240 Log.w(TAG, "No readPermission or writePermssion for <path-permission>: " 2241 + parser.getName() + " at " + mArchiveSourcePath + " " 2242 + parser.getPositionDescription()); 2243 XmlUtils.skipCurrentTag(parser); 2244 continue; 2245 } 2246 outError[0] = "No readPermission or writePermssion for <path-permission>"; 2247 return false; 2248 } 2249 2250 String path = sa.getNonConfigurationString( 2251 com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0); 2252 if (path != null) { 2253 pa = new PathPermission(path, 2254 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission); 2255 } 2256 2257 path = sa.getNonConfigurationString( 2258 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0); 2259 if (path != null) { 2260 pa = new PathPermission(path, 2261 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission); 2262 } 2263 2264 path = sa.getNonConfigurationString( 2265 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0); 2266 if (path != null) { 2267 pa = new PathPermission(path, 2268 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission); 2269 } 2270 2271 sa.recycle(); 2272 2273 if (pa != null) { 2274 if (outInfo.info.pathPermissions == null) { 2275 outInfo.info.pathPermissions = new PathPermission[1]; 2276 outInfo.info.pathPermissions[0] = pa; 2277 } else { 2278 final int N = outInfo.info.pathPermissions.length; 2279 PathPermission[] newp = new PathPermission[N+1]; 2280 System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N); 2281 newp[N] = pa; 2282 outInfo.info.pathPermissions = newp; 2283 } 2284 } else { 2285 if (!RIGID_PARSER) { 2286 Log.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: " 2287 + parser.getName() + " at " + mArchiveSourcePath + " " 2288 + parser.getPositionDescription()); 2289 XmlUtils.skipCurrentTag(parser); 2290 continue; 2291 } 2292 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 2293 return false; 2294 } 2295 XmlUtils.skipCurrentTag(parser); 2296 2297 } else { 2298 if (!RIGID_PARSER) { 2299 Log.w(TAG, "Unknown element under <provider>: " 2300 + parser.getName() + " at " + mArchiveSourcePath + " " 2301 + parser.getPositionDescription()); 2302 XmlUtils.skipCurrentTag(parser); 2303 continue; 2304 } 2305 outError[0] = "Bad element under <provider>: " 2306 + parser.getName(); 2307 return false; 2308 } 2309 } 2310 return true; 2311 } 2312 2313 private Service parseService(Package owner, Resources res, 2314 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 2315 throws XmlPullParserException, IOException { 2316 TypedArray sa = res.obtainAttributes(attrs, 2317 com.android.internal.R.styleable.AndroidManifestService); 2318 2319 if (mParseServiceArgs == null) { 2320 mParseServiceArgs = new ParseComponentArgs(owner, outError, 2321 com.android.internal.R.styleable.AndroidManifestService_name, 2322 com.android.internal.R.styleable.AndroidManifestService_label, 2323 com.android.internal.R.styleable.AndroidManifestService_icon, 2324 mSeparateProcesses, 2325 com.android.internal.R.styleable.AndroidManifestService_process, 2326 com.android.internal.R.styleable.AndroidManifestService_description, 2327 com.android.internal.R.styleable.AndroidManifestService_enabled); 2328 mParseServiceArgs.tag = "<service>"; 2329 } 2330 2331 mParseServiceArgs.sa = sa; 2332 mParseServiceArgs.flags = flags; 2333 2334 Service s = new Service(mParseServiceArgs, new ServiceInfo()); 2335 if (outError[0] != null) { 2336 sa.recycle(); 2337 return null; 2338 } 2339 2340 final boolean setExported = sa.hasValue( 2341 com.android.internal.R.styleable.AndroidManifestService_exported); 2342 if (setExported) { 2343 s.info.exported = sa.getBoolean( 2344 com.android.internal.R.styleable.AndroidManifestService_exported, false); 2345 } 2346 2347 String str = sa.getNonConfigurationString( 2348 com.android.internal.R.styleable.AndroidManifestService_permission, 0); 2349 if (str == null) { 2350 s.info.permission = owner.applicationInfo.permission; 2351 } else { 2352 s.info.permission = str.length() > 0 ? str.toString().intern() : null; 2353 } 2354 2355 sa.recycle(); 2356 2357 int outerDepth = parser.getDepth(); 2358 int type; 2359 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2360 && (type != XmlPullParser.END_TAG 2361 || parser.getDepth() > outerDepth)) { 2362 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2363 continue; 2364 } 2365 2366 if (parser.getName().equals("intent-filter")) { 2367 ServiceIntentInfo intent = new ServiceIntentInfo(s); 2368 if (!parseIntent(res, parser, attrs, flags, intent, outError, false)) { 2369 return null; 2370 } 2371 2372 s.intents.add(intent); 2373 } else if (parser.getName().equals("meta-data")) { 2374 if ((s.metaData=parseMetaData(res, parser, attrs, s.metaData, 2375 outError)) == null) { 2376 return null; 2377 } 2378 } else { 2379 if (!RIGID_PARSER) { 2380 Log.w(TAG, "Unknown element under <service>: " 2381 + parser.getName() + " at " + mArchiveSourcePath + " " 2382 + parser.getPositionDescription()); 2383 XmlUtils.skipCurrentTag(parser); 2384 continue; 2385 } 2386 outError[0] = "Bad element under <service>: " 2387 + parser.getName(); 2388 return null; 2389 } 2390 } 2391 2392 if (!setExported) { 2393 s.info.exported = s.intents.size() > 0; 2394 } 2395 2396 return s; 2397 } 2398 2399 private boolean parseAllMetaData(Resources res, 2400 XmlPullParser parser, AttributeSet attrs, String tag, 2401 Component outInfo, String[] outError) 2402 throws XmlPullParserException, IOException { 2403 int outerDepth = parser.getDepth(); 2404 int type; 2405 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2406 && (type != XmlPullParser.END_TAG 2407 || parser.getDepth() > outerDepth)) { 2408 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2409 continue; 2410 } 2411 2412 if (parser.getName().equals("meta-data")) { 2413 if ((outInfo.metaData=parseMetaData(res, parser, attrs, 2414 outInfo.metaData, outError)) == null) { 2415 return false; 2416 } 2417 } else { 2418 if (!RIGID_PARSER) { 2419 Log.w(TAG, "Unknown element under " + tag + ": " 2420 + parser.getName() + " at " + mArchiveSourcePath + " " 2421 + parser.getPositionDescription()); 2422 XmlUtils.skipCurrentTag(parser); 2423 continue; 2424 } 2425 outError[0] = "Bad element under " + tag + ": " 2426 + parser.getName(); 2427 return false; 2428 } 2429 } 2430 return true; 2431 } 2432 2433 private Bundle parseMetaData(Resources res, 2434 XmlPullParser parser, AttributeSet attrs, 2435 Bundle data, String[] outError) 2436 throws XmlPullParserException, IOException { 2437 2438 TypedArray sa = res.obtainAttributes(attrs, 2439 com.android.internal.R.styleable.AndroidManifestMetaData); 2440 2441 if (data == null) { 2442 data = new Bundle(); 2443 } 2444 2445 String name = sa.getNonConfigurationString( 2446 com.android.internal.R.styleable.AndroidManifestMetaData_name, 0); 2447 if (name == null) { 2448 outError[0] = "<meta-data> requires an android:name attribute"; 2449 sa.recycle(); 2450 return null; 2451 } 2452 2453 name = name.intern(); 2454 2455 TypedValue v = sa.peekValue( 2456 com.android.internal.R.styleable.AndroidManifestMetaData_resource); 2457 if (v != null && v.resourceId != 0) { 2458 //Log.i(TAG, "Meta data ref " + name + ": " + v); 2459 data.putInt(name, v.resourceId); 2460 } else { 2461 v = sa.peekValue( 2462 com.android.internal.R.styleable.AndroidManifestMetaData_value); 2463 //Log.i(TAG, "Meta data " + name + ": " + v); 2464 if (v != null) { 2465 if (v.type == TypedValue.TYPE_STRING) { 2466 CharSequence cs = v.coerceToString(); 2467 data.putString(name, cs != null ? cs.toString().intern() : null); 2468 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { 2469 data.putBoolean(name, v.data != 0); 2470 } else if (v.type >= TypedValue.TYPE_FIRST_INT 2471 && v.type <= TypedValue.TYPE_LAST_INT) { 2472 data.putInt(name, v.data); 2473 } else if (v.type == TypedValue.TYPE_FLOAT) { 2474 data.putFloat(name, v.getFloat()); 2475 } else { 2476 if (!RIGID_PARSER) { 2477 Log.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: " 2478 + parser.getName() + " at " + mArchiveSourcePath + " " 2479 + parser.getPositionDescription()); 2480 } else { 2481 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types"; 2482 data = null; 2483 } 2484 } 2485 } else { 2486 outError[0] = "<meta-data> requires an android:value or android:resource attribute"; 2487 data = null; 2488 } 2489 } 2490 2491 sa.recycle(); 2492 2493 XmlUtils.skipCurrentTag(parser); 2494 2495 return data; 2496 } 2497 2498 private static final String ANDROID_RESOURCES 2499 = "http://schemas.android.com/apk/res/android"; 2500 2501 private boolean parseIntent(Resources res, 2502 XmlPullParser parser, AttributeSet attrs, int flags, 2503 IntentInfo outInfo, String[] outError, boolean isActivity) 2504 throws XmlPullParserException, IOException { 2505 2506 TypedArray sa = res.obtainAttributes(attrs, 2507 com.android.internal.R.styleable.AndroidManifestIntentFilter); 2508 2509 int priority = sa.getInt( 2510 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0); 2511 if (priority > 0 && isActivity && (flags&PARSE_IS_SYSTEM) == 0) { 2512 Log.w(TAG, "Activity with priority > 0, forcing to 0 at " 2513 + mArchiveSourcePath + " " 2514 + parser.getPositionDescription()); 2515 priority = 0; 2516 } 2517 outInfo.setPriority(priority); 2518 2519 TypedValue v = sa.peekValue( 2520 com.android.internal.R.styleable.AndroidManifestIntentFilter_label); 2521 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 2522 outInfo.nonLocalizedLabel = v.coerceToString(); 2523 } 2524 2525 outInfo.icon = sa.getResourceId( 2526 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0); 2527 2528 sa.recycle(); 2529 2530 int outerDepth = parser.getDepth(); 2531 int type; 2532 while ((type=parser.next()) != parser.END_DOCUMENT 2533 && (type != parser.END_TAG || parser.getDepth() > outerDepth)) { 2534 if (type == parser.END_TAG || type == parser.TEXT) { 2535 continue; 2536 } 2537 2538 String nodeName = parser.getName(); 2539 if (nodeName.equals("action")) { 2540 String value = attrs.getAttributeValue( 2541 ANDROID_RESOURCES, "name"); 2542 if (value == null || value == "") { 2543 outError[0] = "No value supplied for <android:name>"; 2544 return false; 2545 } 2546 XmlUtils.skipCurrentTag(parser); 2547 2548 outInfo.addAction(value); 2549 } else if (nodeName.equals("category")) { 2550 String value = attrs.getAttributeValue( 2551 ANDROID_RESOURCES, "name"); 2552 if (value == null || value == "") { 2553 outError[0] = "No value supplied for <android:name>"; 2554 return false; 2555 } 2556 XmlUtils.skipCurrentTag(parser); 2557 2558 outInfo.addCategory(value); 2559 2560 } else if (nodeName.equals("data")) { 2561 sa = res.obtainAttributes(attrs, 2562 com.android.internal.R.styleable.AndroidManifestData); 2563 2564 String str = sa.getNonConfigurationString( 2565 com.android.internal.R.styleable.AndroidManifestData_mimeType, 0); 2566 if (str != null) { 2567 try { 2568 outInfo.addDataType(str); 2569 } catch (IntentFilter.MalformedMimeTypeException e) { 2570 outError[0] = e.toString(); 2571 sa.recycle(); 2572 return false; 2573 } 2574 } 2575 2576 str = sa.getNonConfigurationString( 2577 com.android.internal.R.styleable.AndroidManifestData_scheme, 0); 2578 if (str != null) { 2579 outInfo.addDataScheme(str); 2580 } 2581 2582 String host = sa.getNonConfigurationString( 2583 com.android.internal.R.styleable.AndroidManifestData_host, 0); 2584 String port = sa.getNonConfigurationString( 2585 com.android.internal.R.styleable.AndroidManifestData_port, 0); 2586 if (host != null) { 2587 outInfo.addDataAuthority(host, port); 2588 } 2589 2590 str = sa.getNonConfigurationString( 2591 com.android.internal.R.styleable.AndroidManifestData_path, 0); 2592 if (str != null) { 2593 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); 2594 } 2595 2596 str = sa.getNonConfigurationString( 2597 com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0); 2598 if (str != null) { 2599 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); 2600 } 2601 2602 str = sa.getNonConfigurationString( 2603 com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0); 2604 if (str != null) { 2605 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 2606 } 2607 2608 sa.recycle(); 2609 XmlUtils.skipCurrentTag(parser); 2610 } else if (!RIGID_PARSER) { 2611 Log.w(TAG, "Unknown element under <intent-filter>: " 2612 + parser.getName() + " at " + mArchiveSourcePath + " " 2613 + parser.getPositionDescription()); 2614 XmlUtils.skipCurrentTag(parser); 2615 } else { 2616 outError[0] = "Bad element under <intent-filter>: " + parser.getName(); 2617 return false; 2618 } 2619 } 2620 2621 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT); 2622 if (false) { 2623 String cats = ""; 2624 Iterator<String> it = outInfo.categoriesIterator(); 2625 while (it != null && it.hasNext()) { 2626 cats += " " + it.next(); 2627 } 2628 System.out.println("Intent d=" + 2629 outInfo.hasDefault + ", cat=" + cats); 2630 } 2631 2632 return true; 2633 } 2634 2635 public final static class Package { 2636 public String packageName; 2637 2638 // For now we only support one application per package. 2639 public final ApplicationInfo applicationInfo = new ApplicationInfo(); 2640 2641 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0); 2642 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0); 2643 public final ArrayList<Activity> activities = new ArrayList<Activity>(0); 2644 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0); 2645 public final ArrayList<Provider> providers = new ArrayList<Provider>(0); 2646 public final ArrayList<Service> services = new ArrayList<Service>(0); 2647 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0); 2648 2649 public final ArrayList<String> requestedPermissions = new ArrayList<String>(); 2650 2651 public ArrayList<String> protectedBroadcasts; 2652 2653 public ArrayList<String> usesLibraries = null; 2654 public ArrayList<String> usesOptionalLibraries = null; 2655 public String[] usesLibraryFiles = null; 2656 2657 public ArrayList<String> mOriginalPackages = null; 2658 public String mRealPackage = null; 2659 public ArrayList<String> mAdoptPermissions = null; 2660 2661 // We store the application meta-data independently to avoid multiple unwanted references 2662 public Bundle mAppMetaData = null; 2663 2664 // If this is a 3rd party app, this is the path of the zip file. 2665 public String mPath; 2666 2667 // The version code declared for this package. 2668 public int mVersionCode; 2669 2670 // The version name declared for this package. 2671 public String mVersionName; 2672 2673 // The shared user id that this package wants to use. 2674 public String mSharedUserId; 2675 2676 // The shared user label that this package wants to use. 2677 public int mSharedUserLabel; 2678 2679 // Signatures that were read from the package. 2680 public Signature mSignatures[]; 2681 2682 // For use by package manager service for quick lookup of 2683 // preferred up order. 2684 public int mPreferredOrder = 0; 2685 2686 // For use by the package manager to keep track of the path to the 2687 // file an app came from. 2688 public String mScanPath; 2689 2690 // For use by package manager to keep track of where it has done dexopt. 2691 public boolean mDidDexOpt; 2692 2693 // Additional data supplied by callers. 2694 public Object mExtras; 2695 2696 /* 2697 * Applications hardware preferences 2698 */ 2699 public final ArrayList<ConfigurationInfo> configPreferences = 2700 new ArrayList<ConfigurationInfo>(); 2701 2702 /* 2703 * Applications requested features 2704 */ 2705 public ArrayList<FeatureInfo> reqFeatures = null; 2706 2707 public int installLocation; 2708 2709 public Package(String _name) { 2710 packageName = _name; 2711 applicationInfo.packageName = _name; 2712 applicationInfo.uid = -1; 2713 } 2714 2715 public void setPackageName(String newName) { 2716 packageName = newName; 2717 applicationInfo.packageName = newName; 2718 for (int i=permissions.size()-1; i>=0; i--) { 2719 permissions.get(i).setPackageName(newName); 2720 } 2721 for (int i=permissionGroups.size()-1; i>=0; i--) { 2722 permissionGroups.get(i).setPackageName(newName); 2723 } 2724 for (int i=activities.size()-1; i>=0; i--) { 2725 activities.get(i).setPackageName(newName); 2726 } 2727 for (int i=receivers.size()-1; i>=0; i--) { 2728 receivers.get(i).setPackageName(newName); 2729 } 2730 for (int i=providers.size()-1; i>=0; i--) { 2731 providers.get(i).setPackageName(newName); 2732 } 2733 for (int i=services.size()-1; i>=0; i--) { 2734 services.get(i).setPackageName(newName); 2735 } 2736 for (int i=instrumentation.size()-1; i>=0; i--) { 2737 instrumentation.get(i).setPackageName(newName); 2738 } 2739 } 2740 2741 public String toString() { 2742 return "Package{" 2743 + Integer.toHexString(System.identityHashCode(this)) 2744 + " " + packageName + "}"; 2745 } 2746 } 2747 2748 public static class Component<II extends IntentInfo> { 2749 public final Package owner; 2750 public final ArrayList<II> intents; 2751 public final String className; 2752 public Bundle metaData; 2753 2754 ComponentName componentName; 2755 String componentShortName; 2756 2757 public Component(Package _owner) { 2758 owner = _owner; 2759 intents = null; 2760 className = null; 2761 } 2762 2763 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) { 2764 owner = args.owner; 2765 intents = new ArrayList<II>(0); 2766 String name = args.sa.getNonConfigurationString(args.nameRes, 0); 2767 if (name == null) { 2768 className = null; 2769 args.outError[0] = args.tag + " does not specify android:name"; 2770 return; 2771 } 2772 2773 outInfo.name 2774 = buildClassName(owner.applicationInfo.packageName, name, args.outError); 2775 if (outInfo.name == null) { 2776 className = null; 2777 args.outError[0] = args.tag + " does not have valid android:name"; 2778 return; 2779 } 2780 2781 className = outInfo.name; 2782 2783 int iconVal = args.sa.getResourceId(args.iconRes, 0); 2784 if (iconVal != 0) { 2785 outInfo.icon = iconVal; 2786 outInfo.nonLocalizedLabel = null; 2787 } 2788 2789 TypedValue v = args.sa.peekValue(args.labelRes); 2790 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 2791 outInfo.nonLocalizedLabel = v.coerceToString(); 2792 } 2793 2794 outInfo.packageName = owner.packageName; 2795 } 2796 2797 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) { 2798 this(args, (PackageItemInfo)outInfo); 2799 if (args.outError[0] != null) { 2800 return; 2801 } 2802 2803 if (args.processRes != 0) { 2804 outInfo.processName = buildProcessName(owner.applicationInfo.packageName, 2805 owner.applicationInfo.processName, 2806 args.sa.getNonConfigurationString(args.processRes, 0), 2807 args.flags, args.sepProcesses, args.outError); 2808 } 2809 2810 if (args.descriptionRes != 0) { 2811 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0); 2812 } 2813 2814 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true); 2815 } 2816 2817 public Component(Component<II> clone) { 2818 owner = clone.owner; 2819 intents = clone.intents; 2820 className = clone.className; 2821 componentName = clone.componentName; 2822 componentShortName = clone.componentShortName; 2823 } 2824 2825 public ComponentName getComponentName() { 2826 if (componentName != null) { 2827 return componentName; 2828 } 2829 if (className != null) { 2830 componentName = new ComponentName(owner.applicationInfo.packageName, 2831 className); 2832 } 2833 return componentName; 2834 } 2835 2836 public String getComponentShortName() { 2837 if (componentShortName != null) { 2838 return componentShortName; 2839 } 2840 ComponentName component = getComponentName(); 2841 if (component != null) { 2842 componentShortName = component.flattenToShortString(); 2843 } 2844 return componentShortName; 2845 } 2846 2847 public void setPackageName(String packageName) { 2848 componentName = null; 2849 componentShortName = null; 2850 } 2851 } 2852 2853 public final static class Permission extends Component<IntentInfo> { 2854 public final PermissionInfo info; 2855 public boolean tree; 2856 public PermissionGroup group; 2857 2858 public Permission(Package _owner) { 2859 super(_owner); 2860 info = new PermissionInfo(); 2861 } 2862 2863 public Permission(Package _owner, PermissionInfo _info) { 2864 super(_owner); 2865 info = _info; 2866 } 2867 2868 public void setPackageName(String packageName) { 2869 super.setPackageName(packageName); 2870 info.packageName = packageName; 2871 } 2872 2873 public String toString() { 2874 return "Permission{" 2875 + Integer.toHexString(System.identityHashCode(this)) 2876 + " " + info.name + "}"; 2877 } 2878 } 2879 2880 public final static class PermissionGroup extends Component<IntentInfo> { 2881 public final PermissionGroupInfo info; 2882 2883 public PermissionGroup(Package _owner) { 2884 super(_owner); 2885 info = new PermissionGroupInfo(); 2886 } 2887 2888 public PermissionGroup(Package _owner, PermissionGroupInfo _info) { 2889 super(_owner); 2890 info = _info; 2891 } 2892 2893 public void setPackageName(String packageName) { 2894 super.setPackageName(packageName); 2895 info.packageName = packageName; 2896 } 2897 2898 public String toString() { 2899 return "PermissionGroup{" 2900 + Integer.toHexString(System.identityHashCode(this)) 2901 + " " + info.name + "}"; 2902 } 2903 } 2904 2905 private static boolean copyNeeded(int flags, Package p, Bundle metaData) { 2906 if ((flags & PackageManager.GET_META_DATA) != 0 2907 && (metaData != null || p.mAppMetaData != null)) { 2908 return true; 2909 } 2910 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 2911 && p.usesLibraryFiles != null) { 2912 return true; 2913 } 2914 return false; 2915 } 2916 2917 public static ApplicationInfo generateApplicationInfo(Package p, int flags) { 2918 if (p == null) return null; 2919 if (!copyNeeded(flags, p, null)) { 2920 // CompatibilityMode is global state. It's safe to modify the instance 2921 // of the package. 2922 if (!sCompatibilityModeEnabled) { 2923 p.applicationInfo.disableCompatibilityMode(); 2924 } 2925 return p.applicationInfo; 2926 } 2927 2928 // Make shallow copy so we can store the metadata/libraries safely 2929 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo); 2930 if ((flags & PackageManager.GET_META_DATA) != 0) { 2931 ai.metaData = p.mAppMetaData; 2932 } 2933 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { 2934 ai.sharedLibraryFiles = p.usesLibraryFiles; 2935 } 2936 if (!sCompatibilityModeEnabled) { 2937 ai.disableCompatibilityMode(); 2938 } 2939 return ai; 2940 } 2941 2942 public static final PermissionInfo generatePermissionInfo( 2943 Permission p, int flags) { 2944 if (p == null) return null; 2945 if ((flags&PackageManager.GET_META_DATA) == 0) { 2946 return p.info; 2947 } 2948 PermissionInfo pi = new PermissionInfo(p.info); 2949 pi.metaData = p.metaData; 2950 return pi; 2951 } 2952 2953 public static final PermissionGroupInfo generatePermissionGroupInfo( 2954 PermissionGroup pg, int flags) { 2955 if (pg == null) return null; 2956 if ((flags&PackageManager.GET_META_DATA) == 0) { 2957 return pg.info; 2958 } 2959 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info); 2960 pgi.metaData = pg.metaData; 2961 return pgi; 2962 } 2963 2964 public final static class Activity extends Component<ActivityIntentInfo> { 2965 public final ActivityInfo info; 2966 2967 public Activity(final ParseComponentArgs args, final ActivityInfo _info) { 2968 super(args, _info); 2969 info = _info; 2970 info.applicationInfo = args.owner.applicationInfo; 2971 } 2972 2973 public void setPackageName(String packageName) { 2974 super.setPackageName(packageName); 2975 info.packageName = packageName; 2976 } 2977 2978 public String toString() { 2979 return "Activity{" 2980 + Integer.toHexString(System.identityHashCode(this)) 2981 + " " + getComponentShortName() + "}"; 2982 } 2983 } 2984 2985 public static final ActivityInfo generateActivityInfo(Activity a, 2986 int flags) { 2987 if (a == null) return null; 2988 if (!copyNeeded(flags, a.owner, a.metaData)) { 2989 return a.info; 2990 } 2991 // Make shallow copies so we can store the metadata safely 2992 ActivityInfo ai = new ActivityInfo(a.info); 2993 ai.metaData = a.metaData; 2994 ai.applicationInfo = generateApplicationInfo(a.owner, flags); 2995 return ai; 2996 } 2997 2998 public final static class Service extends Component<ServiceIntentInfo> { 2999 public final ServiceInfo info; 3000 3001 public Service(final ParseComponentArgs args, final ServiceInfo _info) { 3002 super(args, _info); 3003 info = _info; 3004 info.applicationInfo = args.owner.applicationInfo; 3005 } 3006 3007 public void setPackageName(String packageName) { 3008 super.setPackageName(packageName); 3009 info.packageName = packageName; 3010 } 3011 3012 public String toString() { 3013 return "Service{" 3014 + Integer.toHexString(System.identityHashCode(this)) 3015 + " " + getComponentShortName() + "}"; 3016 } 3017 } 3018 3019 public static final ServiceInfo generateServiceInfo(Service s, int flags) { 3020 if (s == null) return null; 3021 if (!copyNeeded(flags, s.owner, s.metaData)) { 3022 return s.info; 3023 } 3024 // Make shallow copies so we can store the metadata safely 3025 ServiceInfo si = new ServiceInfo(s.info); 3026 si.metaData = s.metaData; 3027 si.applicationInfo = generateApplicationInfo(s.owner, flags); 3028 return si; 3029 } 3030 3031 public final static class Provider extends Component { 3032 public final ProviderInfo info; 3033 public boolean syncable; 3034 3035 public Provider(final ParseComponentArgs args, final ProviderInfo _info) { 3036 super(args, _info); 3037 info = _info; 3038 info.applicationInfo = args.owner.applicationInfo; 3039 syncable = false; 3040 } 3041 3042 public Provider(Provider existingProvider) { 3043 super(existingProvider); 3044 this.info = existingProvider.info; 3045 this.syncable = existingProvider.syncable; 3046 } 3047 3048 public void setPackageName(String packageName) { 3049 super.setPackageName(packageName); 3050 info.packageName = packageName; 3051 } 3052 3053 public String toString() { 3054 return "Provider{" 3055 + Integer.toHexString(System.identityHashCode(this)) 3056 + " " + info.name + "}"; 3057 } 3058 } 3059 3060 public static final ProviderInfo generateProviderInfo(Provider p, 3061 int flags) { 3062 if (p == null) return null; 3063 if (!copyNeeded(flags, p.owner, p.metaData) 3064 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 3065 || p.info.uriPermissionPatterns == null)) { 3066 return p.info; 3067 } 3068 // Make shallow copies so we can store the metadata safely 3069 ProviderInfo pi = new ProviderInfo(p.info); 3070 pi.metaData = p.metaData; 3071 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { 3072 pi.uriPermissionPatterns = null; 3073 } 3074 pi.applicationInfo = generateApplicationInfo(p.owner, flags); 3075 return pi; 3076 } 3077 3078 public final static class Instrumentation extends Component { 3079 public final InstrumentationInfo info; 3080 3081 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) { 3082 super(args, _info); 3083 info = _info; 3084 } 3085 3086 public void setPackageName(String packageName) { 3087 super.setPackageName(packageName); 3088 info.packageName = packageName; 3089 } 3090 3091 public String toString() { 3092 return "Instrumentation{" 3093 + Integer.toHexString(System.identityHashCode(this)) 3094 + " " + getComponentShortName() + "}"; 3095 } 3096 } 3097 3098 public static final InstrumentationInfo generateInstrumentationInfo( 3099 Instrumentation i, int flags) { 3100 if (i == null) return null; 3101 if ((flags&PackageManager.GET_META_DATA) == 0) { 3102 return i.info; 3103 } 3104 InstrumentationInfo ii = new InstrumentationInfo(i.info); 3105 ii.metaData = i.metaData; 3106 return ii; 3107 } 3108 3109 public static class IntentInfo extends IntentFilter { 3110 public boolean hasDefault; 3111 public int labelRes; 3112 public CharSequence nonLocalizedLabel; 3113 public int icon; 3114 } 3115 3116 public final static class ActivityIntentInfo extends IntentInfo { 3117 public final Activity activity; 3118 3119 public ActivityIntentInfo(Activity _activity) { 3120 activity = _activity; 3121 } 3122 3123 public String toString() { 3124 return "ActivityIntentInfo{" 3125 + Integer.toHexString(System.identityHashCode(this)) 3126 + " " + activity.info.name + "}"; 3127 } 3128 } 3129 3130 public final static class ServiceIntentInfo extends IntentInfo { 3131 public final Service service; 3132 3133 public ServiceIntentInfo(Service _service) { 3134 service = _service; 3135 } 3136 3137 public String toString() { 3138 return "ServiceIntentInfo{" 3139 + Integer.toHexString(System.identityHashCode(this)) 3140 + " " + service.info.name + "}"; 3141 } 3142 } 3143 3144 /** 3145 * @hide 3146 */ 3147 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { 3148 sCompatibilityModeEnabled = compatibilityModeEnabled; 3149 } 3150} 3151