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