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