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