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