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