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