PackageParser.java revision 5e1ab335e6e8fbfa19c64d53880a22f472010953
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 1300 // backupAgent, killAfterRestore, and restoreNeedsApplication are only relevant 1301 // if backup is possible for the given application. 1302 String backupAgent = sa.getNonResourceString( 1303 com.android.internal.R.styleable.AndroidManifestApplication_backupAgent); 1304 if (backupAgent != null) { 1305 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError); 1306 Log.v(TAG, "android:backupAgent = " + ai.backupAgentName 1307 + " from " + pkgName + "+" + backupAgent); 1308 1309 if (sa.getBoolean( 1310 com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore, 1311 true)) { 1312 ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE; 1313 } 1314 if (sa.getBoolean( 1315 com.android.internal.R.styleable.AndroidManifestApplication_restoreNeedsApplication, 1316 false)) { 1317 ai.flags |= ApplicationInfo.FLAG_RESTORE_NEEDS_APPLICATION; 1318 } 1319 } 1320 } 1321 1322 TypedValue v = sa.peekValue( 1323 com.android.internal.R.styleable.AndroidManifestApplication_label); 1324 if (v != null && (ai.labelRes=v.resourceId) == 0) { 1325 ai.nonLocalizedLabel = v.coerceToString(); 1326 } 1327 1328 ai.icon = sa.getResourceId( 1329 com.android.internal.R.styleable.AndroidManifestApplication_icon, 0); 1330 ai.theme = sa.getResourceId( 1331 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); 1332 ai.descriptionRes = sa.getResourceId( 1333 com.android.internal.R.styleable.AndroidManifestApplication_description, 0); 1334 1335 if ((flags&PARSE_IS_SYSTEM) != 0) { 1336 if (sa.getBoolean( 1337 com.android.internal.R.styleable.AndroidManifestApplication_persistent, 1338 false)) { 1339 ai.flags |= ApplicationInfo.FLAG_PERSISTENT; 1340 } 1341 } 1342 1343 if (sa.getBoolean( 1344 com.android.internal.R.styleable.AndroidManifestApplication_debuggable, 1345 false)) { 1346 ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE; 1347 } 1348 1349 if (sa.getBoolean( 1350 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, 1351 true)) { 1352 ai.flags |= ApplicationInfo.FLAG_HAS_CODE; 1353 } 1354 1355 if (sa.getBoolean( 1356 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting, 1357 false)) { 1358 ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; 1359 } 1360 1361 if (sa.getBoolean( 1362 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData, 1363 true)) { 1364 ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; 1365 } 1366 1367 if (sa.getBoolean( 1368 com.android.internal.R.styleable.AndroidManifestApplication_testOnly, 1369 false)) { 1370 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY; 1371 } 1372 1373 String str; 1374 str = sa.getNonResourceString( 1375 com.android.internal.R.styleable.AndroidManifestApplication_permission); 1376 ai.permission = (str != null && str.length() > 0) ? str.intern() : null; 1377 1378 str = sa.getNonResourceString( 1379 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity); 1380 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName, 1381 str, outError); 1382 1383 if (outError[0] == null) { 1384 ai.processName = buildProcessName(ai.packageName, null, sa.getNonResourceString( 1385 com.android.internal.R.styleable.AndroidManifestApplication_process), 1386 flags, mSeparateProcesses, outError); 1387 1388 ai.enabled = sa.getBoolean(com.android.internal.R.styleable.AndroidManifestApplication_enabled, true); 1389 } 1390 1391 sa.recycle(); 1392 1393 if (outError[0] != null) { 1394 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1395 return false; 1396 } 1397 1398 final int innerDepth = parser.getDepth(); 1399 1400 int type; 1401 while ((type=parser.next()) != parser.END_DOCUMENT 1402 && (type != parser.END_TAG || parser.getDepth() > innerDepth)) { 1403 if (type == parser.END_TAG || type == parser.TEXT) { 1404 continue; 1405 } 1406 1407 String tagName = parser.getName(); 1408 if (tagName.equals("activity")) { 1409 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false); 1410 if (a == null) { 1411 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1412 return false; 1413 } 1414 1415 owner.activities.add(a); 1416 1417 } else if (tagName.equals("receiver")) { 1418 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true); 1419 if (a == null) { 1420 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1421 return false; 1422 } 1423 1424 owner.receivers.add(a); 1425 1426 } else if (tagName.equals("service")) { 1427 Service s = parseService(owner, res, parser, attrs, flags, outError); 1428 if (s == null) { 1429 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1430 return false; 1431 } 1432 1433 owner.services.add(s); 1434 1435 } else if (tagName.equals("provider")) { 1436 Provider p = parseProvider(owner, res, parser, attrs, flags, outError); 1437 if (p == null) { 1438 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1439 return false; 1440 } 1441 1442 owner.providers.add(p); 1443 1444 } else if (tagName.equals("activity-alias")) { 1445 Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError); 1446 if (a == null) { 1447 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1448 return false; 1449 } 1450 1451 owner.activities.add(a); 1452 1453 } else if (parser.getName().equals("meta-data")) { 1454 // note: application meta-data is stored off to the side, so it can 1455 // remain null in the primary copy (we like to avoid extra copies because 1456 // it can be large) 1457 if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData, 1458 outError)) == null) { 1459 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1460 return false; 1461 } 1462 1463 } else if (tagName.equals("uses-library")) { 1464 sa = res.obtainAttributes(attrs, 1465 com.android.internal.R.styleable.AndroidManifestUsesLibrary); 1466 1467 String lname = sa.getNonResourceString( 1468 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 1469 boolean req = sa.getBoolean( 1470 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, 1471 true); 1472 1473 sa.recycle(); 1474 1475 if (lname != null) { 1476 if (req) { 1477 if (owner.usesLibraries == null) { 1478 owner.usesLibraries = new ArrayList<String>(); 1479 } 1480 if (!owner.usesLibraries.contains(lname)) { 1481 owner.usesLibraries.add(lname.intern()); 1482 } 1483 } else { 1484 if (owner.usesOptionalLibraries == null) { 1485 owner.usesOptionalLibraries = new ArrayList<String>(); 1486 } 1487 if (!owner.usesOptionalLibraries.contains(lname)) { 1488 owner.usesOptionalLibraries.add(lname.intern()); 1489 } 1490 } 1491 } 1492 1493 XmlUtils.skipCurrentTag(parser); 1494 1495 } else { 1496 if (!RIGID_PARSER) { 1497 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 1498 Log.w(TAG, "Unknown element under <application>: " + tagName); 1499 XmlUtils.skipCurrentTag(parser); 1500 continue; 1501 } else { 1502 outError[0] = "Bad element under <application>: " + tagName; 1503 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1504 return false; 1505 } 1506 } 1507 } 1508 1509 return true; 1510 } 1511 1512 private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo, 1513 String[] outError, String tag, TypedArray sa, 1514 int nameRes, int labelRes, int iconRes) { 1515 String name = sa.getNonResourceString(nameRes); 1516 if (name == null) { 1517 outError[0] = tag + " does not specify android:name"; 1518 return false; 1519 } 1520 1521 outInfo.name 1522 = buildClassName(owner.applicationInfo.packageName, name, outError); 1523 if (outInfo.name == null) { 1524 return false; 1525 } 1526 1527 int iconVal = sa.getResourceId(iconRes, 0); 1528 if (iconVal != 0) { 1529 outInfo.icon = iconVal; 1530 outInfo.nonLocalizedLabel = null; 1531 } 1532 1533 TypedValue v = sa.peekValue(labelRes); 1534 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 1535 outInfo.nonLocalizedLabel = v.coerceToString(); 1536 } 1537 1538 outInfo.packageName = owner.packageName; 1539 1540 return true; 1541 } 1542 1543 private boolean parseComponentInfo(Package owner, int flags, 1544 ComponentInfo outInfo, String[] outError, String tag, TypedArray sa, 1545 int nameRes, int labelRes, int iconRes, int processRes, 1546 int enabledRes) { 1547 if (!parsePackageItemInfo(owner, outInfo, outError, tag, sa, 1548 nameRes, labelRes, iconRes)) { 1549 return false; 1550 } 1551 1552 if (processRes != 0) { 1553 outInfo.processName = buildProcessName(owner.applicationInfo.packageName, 1554 owner.applicationInfo.processName, sa.getNonResourceString(processRes), 1555 flags, mSeparateProcesses, outError); 1556 } 1557 outInfo.enabled = sa.getBoolean(enabledRes, true); 1558 1559 return outError[0] == null; 1560 } 1561 1562 private Activity parseActivity(Package owner, Resources res, 1563 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError, 1564 boolean receiver) throws XmlPullParserException, IOException { 1565 TypedArray sa = res.obtainAttributes(attrs, 1566 com.android.internal.R.styleable.AndroidManifestActivity); 1567 1568 if (mParseActivityArgs == null) { 1569 mParseActivityArgs = new ParseComponentArgs(owner, outError, 1570 com.android.internal.R.styleable.AndroidManifestActivity_name, 1571 com.android.internal.R.styleable.AndroidManifestActivity_label, 1572 com.android.internal.R.styleable.AndroidManifestActivity_icon, 1573 mSeparateProcesses, 1574 com.android.internal.R.styleable.AndroidManifestActivity_process, 1575 com.android.internal.R.styleable.AndroidManifestActivity_enabled); 1576 } 1577 1578 mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>"; 1579 mParseActivityArgs.sa = sa; 1580 mParseActivityArgs.flags = flags; 1581 1582 Activity a = new Activity(mParseActivityArgs, new ActivityInfo()); 1583 if (outError[0] != null) { 1584 sa.recycle(); 1585 return null; 1586 } 1587 1588 final boolean setExported = sa.hasValue( 1589 com.android.internal.R.styleable.AndroidManifestActivity_exported); 1590 if (setExported) { 1591 a.info.exported = sa.getBoolean( 1592 com.android.internal.R.styleable.AndroidManifestActivity_exported, false); 1593 } 1594 1595 a.info.theme = sa.getResourceId( 1596 com.android.internal.R.styleable.AndroidManifestActivity_theme, 0); 1597 1598 String str; 1599 str = sa.getNonResourceString( 1600 com.android.internal.R.styleable.AndroidManifestActivity_permission); 1601 if (str == null) { 1602 a.info.permission = owner.applicationInfo.permission; 1603 } else { 1604 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 1605 } 1606 1607 str = sa.getNonResourceString( 1608 com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity); 1609 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName, 1610 owner.applicationInfo.taskAffinity, str, outError); 1611 1612 a.info.flags = 0; 1613 if (sa.getBoolean( 1614 com.android.internal.R.styleable.AndroidManifestActivity_multiprocess, 1615 false)) { 1616 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS; 1617 } 1618 1619 if (sa.getBoolean( 1620 com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch, 1621 false)) { 1622 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; 1623 } 1624 1625 if (sa.getBoolean( 1626 com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch, 1627 false)) { 1628 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; 1629 } 1630 1631 if (sa.getBoolean( 1632 com.android.internal.R.styleable.AndroidManifestActivity_noHistory, 1633 false)) { 1634 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY; 1635 } 1636 1637 if (sa.getBoolean( 1638 com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState, 1639 false)) { 1640 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; 1641 } 1642 1643 if (sa.getBoolean( 1644 com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded, 1645 false)) { 1646 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; 1647 } 1648 1649 if (sa.getBoolean( 1650 com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents, 1651 false)) { 1652 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; 1653 } 1654 1655 if (sa.getBoolean( 1656 com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting, 1657 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) { 1658 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; 1659 } 1660 1661 if (!receiver) { 1662 a.info.launchMode = sa.getInt( 1663 com.android.internal.R.styleable.AndroidManifestActivity_launchMode, 1664 ActivityInfo.LAUNCH_MULTIPLE); 1665 a.info.screenOrientation = sa.getInt( 1666 com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation, 1667 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1668 a.info.configChanges = sa.getInt( 1669 com.android.internal.R.styleable.AndroidManifestActivity_configChanges, 1670 0); 1671 a.info.softInputMode = sa.getInt( 1672 com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode, 1673 0); 1674 } else { 1675 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; 1676 a.info.configChanges = 0; 1677 } 1678 1679 sa.recycle(); 1680 1681 if (outError[0] != null) { 1682 return null; 1683 } 1684 1685 int outerDepth = parser.getDepth(); 1686 int type; 1687 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 1688 && (type != XmlPullParser.END_TAG 1689 || parser.getDepth() > outerDepth)) { 1690 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1691 continue; 1692 } 1693 1694 if (parser.getName().equals("intent-filter")) { 1695 ActivityIntentInfo intent = new ActivityIntentInfo(a); 1696 if (!parseIntent(res, parser, attrs, flags, intent, outError, !receiver)) { 1697 return null; 1698 } 1699 if (intent.countActions() == 0) { 1700 Log.w(TAG, "Intent filter for activity " + intent 1701 + " defines no actions"); 1702 } else { 1703 a.intents.add(intent); 1704 } 1705 } else if (parser.getName().equals("meta-data")) { 1706 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData, 1707 outError)) == null) { 1708 return null; 1709 } 1710 } else { 1711 if (!RIGID_PARSER) { 1712 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 1713 if (receiver) { 1714 Log.w(TAG, "Unknown element under <receiver>: " + parser.getName()); 1715 } else { 1716 Log.w(TAG, "Unknown element under <activity>: " + parser.getName()); 1717 } 1718 XmlUtils.skipCurrentTag(parser); 1719 continue; 1720 } 1721 if (receiver) { 1722 outError[0] = "Bad element under <receiver>: " + parser.getName(); 1723 } else { 1724 outError[0] = "Bad element under <activity>: " + parser.getName(); 1725 } 1726 return null; 1727 } 1728 } 1729 1730 if (!setExported) { 1731 a.info.exported = a.intents.size() > 0; 1732 } 1733 1734 return a; 1735 } 1736 1737 private Activity parseActivityAlias(Package owner, Resources res, 1738 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 1739 throws XmlPullParserException, IOException { 1740 TypedArray sa = res.obtainAttributes(attrs, 1741 com.android.internal.R.styleable.AndroidManifestActivityAlias); 1742 1743 String targetActivity = sa.getNonResourceString( 1744 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity); 1745 if (targetActivity == null) { 1746 outError[0] = "<activity-alias> does not specify android:targetActivity"; 1747 sa.recycle(); 1748 return null; 1749 } 1750 1751 targetActivity = buildClassName(owner.applicationInfo.packageName, 1752 targetActivity, outError); 1753 if (targetActivity == null) { 1754 sa.recycle(); 1755 return null; 1756 } 1757 1758 if (mParseActivityAliasArgs == null) { 1759 mParseActivityAliasArgs = new ParseComponentArgs(owner, outError, 1760 com.android.internal.R.styleable.AndroidManifestActivityAlias_name, 1761 com.android.internal.R.styleable.AndroidManifestActivityAlias_label, 1762 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, 1763 mSeparateProcesses, 1764 0, 1765 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled); 1766 mParseActivityAliasArgs.tag = "<activity-alias>"; 1767 } 1768 1769 mParseActivityAliasArgs.sa = sa; 1770 mParseActivityAliasArgs.flags = flags; 1771 1772 Activity target = null; 1773 1774 final int NA = owner.activities.size(); 1775 for (int i=0; i<NA; i++) { 1776 Activity t = owner.activities.get(i); 1777 if (targetActivity.equals(t.info.name)) { 1778 target = t; 1779 break; 1780 } 1781 } 1782 1783 if (target == null) { 1784 outError[0] = "<activity-alias> target activity " + targetActivity 1785 + " not found in manifest"; 1786 sa.recycle(); 1787 return null; 1788 } 1789 1790 ActivityInfo info = new ActivityInfo(); 1791 info.targetActivity = targetActivity; 1792 info.configChanges = target.info.configChanges; 1793 info.flags = target.info.flags; 1794 info.icon = target.info.icon; 1795 info.labelRes = target.info.labelRes; 1796 info.nonLocalizedLabel = target.info.nonLocalizedLabel; 1797 info.launchMode = target.info.launchMode; 1798 info.processName = target.info.processName; 1799 info.screenOrientation = target.info.screenOrientation; 1800 info.taskAffinity = target.info.taskAffinity; 1801 info.theme = target.info.theme; 1802 1803 Activity a = new Activity(mParseActivityAliasArgs, info); 1804 if (outError[0] != null) { 1805 sa.recycle(); 1806 return null; 1807 } 1808 1809 final boolean setExported = sa.hasValue( 1810 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported); 1811 if (setExported) { 1812 a.info.exported = sa.getBoolean( 1813 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false); 1814 } 1815 1816 String str; 1817 str = sa.getNonResourceString( 1818 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission); 1819 if (str != null) { 1820 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 1821 } 1822 1823 sa.recycle(); 1824 1825 if (outError[0] != null) { 1826 return null; 1827 } 1828 1829 int outerDepth = parser.getDepth(); 1830 int type; 1831 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 1832 && (type != XmlPullParser.END_TAG 1833 || parser.getDepth() > outerDepth)) { 1834 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1835 continue; 1836 } 1837 1838 if (parser.getName().equals("intent-filter")) { 1839 ActivityIntentInfo intent = new ActivityIntentInfo(a); 1840 if (!parseIntent(res, parser, attrs, flags, intent, outError, true)) { 1841 return null; 1842 } 1843 if (intent.countActions() == 0) { 1844 Log.w(TAG, "Intent filter for activity alias " + intent 1845 + " defines no actions"); 1846 } else { 1847 a.intents.add(intent); 1848 } 1849 } else if (parser.getName().equals("meta-data")) { 1850 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData, 1851 outError)) == null) { 1852 return null; 1853 } 1854 } else { 1855 if (!RIGID_PARSER) { 1856 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 1857 Log.w(TAG, "Unknown element under <activity-alias>: " + parser.getName()); 1858 XmlUtils.skipCurrentTag(parser); 1859 continue; 1860 } 1861 outError[0] = "Bad element under <activity-alias>: " + parser.getName(); 1862 return null; 1863 } 1864 } 1865 1866 if (!setExported) { 1867 a.info.exported = a.intents.size() > 0; 1868 } 1869 1870 return a; 1871 } 1872 1873 private Provider parseProvider(Package owner, Resources res, 1874 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 1875 throws XmlPullParserException, IOException { 1876 TypedArray sa = res.obtainAttributes(attrs, 1877 com.android.internal.R.styleable.AndroidManifestProvider); 1878 1879 if (mParseProviderArgs == null) { 1880 mParseProviderArgs = new ParseComponentArgs(owner, outError, 1881 com.android.internal.R.styleable.AndroidManifestProvider_name, 1882 com.android.internal.R.styleable.AndroidManifestProvider_label, 1883 com.android.internal.R.styleable.AndroidManifestProvider_icon, 1884 mSeparateProcesses, 1885 com.android.internal.R.styleable.AndroidManifestProvider_process, 1886 com.android.internal.R.styleable.AndroidManifestProvider_enabled); 1887 mParseProviderArgs.tag = "<provider>"; 1888 } 1889 1890 mParseProviderArgs.sa = sa; 1891 mParseProviderArgs.flags = flags; 1892 1893 Provider p = new Provider(mParseProviderArgs, new ProviderInfo()); 1894 if (outError[0] != null) { 1895 sa.recycle(); 1896 return null; 1897 } 1898 1899 p.info.exported = sa.getBoolean( 1900 com.android.internal.R.styleable.AndroidManifestProvider_exported, true); 1901 1902 String cpname = sa.getNonResourceString( 1903 com.android.internal.R.styleable.AndroidManifestProvider_authorities); 1904 1905 p.info.isSyncable = sa.getBoolean( 1906 com.android.internal.R.styleable.AndroidManifestProvider_syncable, 1907 false); 1908 1909 String permission = sa.getNonResourceString( 1910 com.android.internal.R.styleable.AndroidManifestProvider_permission); 1911 String str = sa.getNonResourceString( 1912 com.android.internal.R.styleable.AndroidManifestProvider_readPermission); 1913 if (str == null) { 1914 str = permission; 1915 } 1916 if (str == null) { 1917 p.info.readPermission = owner.applicationInfo.permission; 1918 } else { 1919 p.info.readPermission = 1920 str.length() > 0 ? str.toString().intern() : null; 1921 } 1922 str = sa.getNonResourceString( 1923 com.android.internal.R.styleable.AndroidManifestProvider_writePermission); 1924 if (str == null) { 1925 str = permission; 1926 } 1927 if (str == null) { 1928 p.info.writePermission = owner.applicationInfo.permission; 1929 } else { 1930 p.info.writePermission = 1931 str.length() > 0 ? str.toString().intern() : null; 1932 } 1933 1934 p.info.grantUriPermissions = sa.getBoolean( 1935 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions, 1936 false); 1937 1938 p.info.multiprocess = sa.getBoolean( 1939 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess, 1940 false); 1941 1942 p.info.initOrder = sa.getInt( 1943 com.android.internal.R.styleable.AndroidManifestProvider_initOrder, 1944 0); 1945 1946 sa.recycle(); 1947 1948 if (cpname == null) { 1949 outError[0] = "<provider> does not incude authorities attribute"; 1950 return null; 1951 } 1952 p.info.authority = cpname.intern(); 1953 1954 if (!parseProviderTags(res, parser, attrs, p, outError)) { 1955 return null; 1956 } 1957 1958 return p; 1959 } 1960 1961 private boolean parseProviderTags(Resources res, 1962 XmlPullParser parser, AttributeSet attrs, 1963 Provider outInfo, String[] outError) 1964 throws XmlPullParserException, IOException { 1965 int outerDepth = parser.getDepth(); 1966 int type; 1967 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 1968 && (type != XmlPullParser.END_TAG 1969 || parser.getDepth() > outerDepth)) { 1970 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1971 continue; 1972 } 1973 1974 if (parser.getName().equals("meta-data")) { 1975 if ((outInfo.metaData=parseMetaData(res, parser, attrs, 1976 outInfo.metaData, outError)) == null) { 1977 return false; 1978 } 1979 1980 } else if (parser.getName().equals("grant-uri-permission")) { 1981 TypedArray sa = res.obtainAttributes(attrs, 1982 com.android.internal.R.styleable.AndroidManifestGrantUriPermission); 1983 1984 PatternMatcher pa = null; 1985 1986 String str = sa.getNonResourceString( 1987 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path); 1988 if (str != null) { 1989 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); 1990 } 1991 1992 str = sa.getNonResourceString( 1993 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix); 1994 if (str != null) { 1995 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); 1996 } 1997 1998 str = sa.getNonResourceString( 1999 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern); 2000 if (str != null) { 2001 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 2002 } 2003 2004 sa.recycle(); 2005 2006 if (pa != null) { 2007 if (outInfo.info.uriPermissionPatterns == null) { 2008 outInfo.info.uriPermissionPatterns = new PatternMatcher[1]; 2009 outInfo.info.uriPermissionPatterns[0] = pa; 2010 } else { 2011 final int N = outInfo.info.uriPermissionPatterns.length; 2012 PatternMatcher[] newp = new PatternMatcher[N+1]; 2013 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N); 2014 newp[N] = pa; 2015 outInfo.info.uriPermissionPatterns = newp; 2016 } 2017 outInfo.info.grantUriPermissions = true; 2018 } else { 2019 if (!RIGID_PARSER) { 2020 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 2021 Log.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>"); 2022 XmlUtils.skipCurrentTag(parser); 2023 continue; 2024 } 2025 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 2026 return false; 2027 } 2028 XmlUtils.skipCurrentTag(parser); 2029 2030 } else if (parser.getName().equals("path-permission")) { 2031 TypedArray sa = res.obtainAttributes(attrs, 2032 com.android.internal.R.styleable.AndroidManifestPathPermission); 2033 2034 PathPermission pa = null; 2035 2036 String permission = sa.getNonResourceString( 2037 com.android.internal.R.styleable.AndroidManifestPathPermission_permission); 2038 String readPermission = sa.getNonResourceString( 2039 com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission); 2040 if (readPermission == null) { 2041 readPermission = permission; 2042 } 2043 String writePermission = sa.getNonResourceString( 2044 com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission); 2045 if (writePermission == null) { 2046 writePermission = permission; 2047 } 2048 2049 boolean havePerm = false; 2050 if (readPermission != null) { 2051 readPermission = readPermission.intern(); 2052 havePerm = true; 2053 } 2054 if (writePermission != null) { 2055 writePermission = readPermission.intern(); 2056 havePerm = true; 2057 } 2058 2059 if (!havePerm) { 2060 if (!RIGID_PARSER) { 2061 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 2062 Log.w(TAG, "No readPermission or writePermssion for <path-permission>"); 2063 XmlUtils.skipCurrentTag(parser); 2064 continue; 2065 } 2066 outError[0] = "No readPermission or writePermssion for <path-permission>"; 2067 return false; 2068 } 2069 2070 String path = sa.getNonResourceString( 2071 com.android.internal.R.styleable.AndroidManifestPathPermission_path); 2072 if (path != null) { 2073 pa = new PathPermission(path, 2074 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission); 2075 } 2076 2077 path = sa.getNonResourceString( 2078 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix); 2079 if (path != null) { 2080 pa = new PathPermission(path, 2081 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission); 2082 } 2083 2084 path = sa.getNonResourceString( 2085 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern); 2086 if (path != null) { 2087 pa = new PathPermission(path, 2088 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission); 2089 } 2090 2091 sa.recycle(); 2092 2093 if (pa != null) { 2094 if (outInfo.info.pathPermissions == null) { 2095 outInfo.info.pathPermissions = new PathPermission[1]; 2096 outInfo.info.pathPermissions[0] = pa; 2097 } else { 2098 final int N = outInfo.info.pathPermissions.length; 2099 PathPermission[] newp = new PathPermission[N+1]; 2100 System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N); 2101 newp[N] = pa; 2102 outInfo.info.pathPermissions = newp; 2103 } 2104 } else { 2105 if (!RIGID_PARSER) { 2106 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 2107 Log.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>"); 2108 XmlUtils.skipCurrentTag(parser); 2109 continue; 2110 } 2111 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 2112 return false; 2113 } 2114 XmlUtils.skipCurrentTag(parser); 2115 2116 } else { 2117 if (!RIGID_PARSER) { 2118 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 2119 Log.w(TAG, "Unknown element under <provider>: " 2120 + parser.getName()); 2121 XmlUtils.skipCurrentTag(parser); 2122 continue; 2123 } 2124 outError[0] = "Bad element under <provider>: " 2125 + parser.getName(); 2126 return false; 2127 } 2128 } 2129 return true; 2130 } 2131 2132 private Service parseService(Package owner, Resources res, 2133 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 2134 throws XmlPullParserException, IOException { 2135 TypedArray sa = res.obtainAttributes(attrs, 2136 com.android.internal.R.styleable.AndroidManifestService); 2137 2138 if (mParseServiceArgs == null) { 2139 mParseServiceArgs = new ParseComponentArgs(owner, outError, 2140 com.android.internal.R.styleable.AndroidManifestService_name, 2141 com.android.internal.R.styleable.AndroidManifestService_label, 2142 com.android.internal.R.styleable.AndroidManifestService_icon, 2143 mSeparateProcesses, 2144 com.android.internal.R.styleable.AndroidManifestService_process, 2145 com.android.internal.R.styleable.AndroidManifestService_enabled); 2146 mParseServiceArgs.tag = "<service>"; 2147 } 2148 2149 mParseServiceArgs.sa = sa; 2150 mParseServiceArgs.flags = flags; 2151 2152 Service s = new Service(mParseServiceArgs, new ServiceInfo()); 2153 if (outError[0] != null) { 2154 sa.recycle(); 2155 return null; 2156 } 2157 2158 final boolean setExported = sa.hasValue( 2159 com.android.internal.R.styleable.AndroidManifestService_exported); 2160 if (setExported) { 2161 s.info.exported = sa.getBoolean( 2162 com.android.internal.R.styleable.AndroidManifestService_exported, false); 2163 } 2164 2165 String str = sa.getNonResourceString( 2166 com.android.internal.R.styleable.AndroidManifestService_permission); 2167 if (str == null) { 2168 s.info.permission = owner.applicationInfo.permission; 2169 } else { 2170 s.info.permission = str.length() > 0 ? str.toString().intern() : null; 2171 } 2172 2173 sa.recycle(); 2174 2175 int outerDepth = parser.getDepth(); 2176 int type; 2177 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2178 && (type != XmlPullParser.END_TAG 2179 || parser.getDepth() > outerDepth)) { 2180 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2181 continue; 2182 } 2183 2184 if (parser.getName().equals("intent-filter")) { 2185 ServiceIntentInfo intent = new ServiceIntentInfo(s); 2186 if (!parseIntent(res, parser, attrs, flags, intent, outError, false)) { 2187 return null; 2188 } 2189 2190 s.intents.add(intent); 2191 } else if (parser.getName().equals("meta-data")) { 2192 if ((s.metaData=parseMetaData(res, parser, attrs, s.metaData, 2193 outError)) == null) { 2194 return null; 2195 } 2196 } else { 2197 if (!RIGID_PARSER) { 2198 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 2199 Log.w(TAG, "Unknown element under <service>: " 2200 + parser.getName()); 2201 XmlUtils.skipCurrentTag(parser); 2202 continue; 2203 } 2204 outError[0] = "Bad element under <service>: " 2205 + parser.getName(); 2206 return null; 2207 } 2208 } 2209 2210 if (!setExported) { 2211 s.info.exported = s.intents.size() > 0; 2212 } 2213 2214 return s; 2215 } 2216 2217 private boolean parseAllMetaData(Resources res, 2218 XmlPullParser parser, AttributeSet attrs, String tag, 2219 Component outInfo, String[] outError) 2220 throws XmlPullParserException, IOException { 2221 int outerDepth = parser.getDepth(); 2222 int type; 2223 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2224 && (type != XmlPullParser.END_TAG 2225 || parser.getDepth() > outerDepth)) { 2226 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2227 continue; 2228 } 2229 2230 if (parser.getName().equals("meta-data")) { 2231 if ((outInfo.metaData=parseMetaData(res, parser, attrs, 2232 outInfo.metaData, outError)) == null) { 2233 return false; 2234 } 2235 } else { 2236 if (!RIGID_PARSER) { 2237 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 2238 Log.w(TAG, "Unknown element under " + tag + ": " 2239 + parser.getName()); 2240 XmlUtils.skipCurrentTag(parser); 2241 continue; 2242 } 2243 outError[0] = "Bad element under " + tag + ": " 2244 + parser.getName(); 2245 return false; 2246 } 2247 } 2248 return true; 2249 } 2250 2251 private Bundle parseMetaData(Resources res, 2252 XmlPullParser parser, AttributeSet attrs, 2253 Bundle data, String[] outError) 2254 throws XmlPullParserException, IOException { 2255 2256 TypedArray sa = res.obtainAttributes(attrs, 2257 com.android.internal.R.styleable.AndroidManifestMetaData); 2258 2259 if (data == null) { 2260 data = new Bundle(); 2261 } 2262 2263 String name = sa.getNonResourceString( 2264 com.android.internal.R.styleable.AndroidManifestMetaData_name); 2265 if (name == null) { 2266 outError[0] = "<meta-data> requires an android:name attribute"; 2267 sa.recycle(); 2268 return null; 2269 } 2270 2271 name = name.intern(); 2272 2273 TypedValue v = sa.peekValue( 2274 com.android.internal.R.styleable.AndroidManifestMetaData_resource); 2275 if (v != null && v.resourceId != 0) { 2276 //Log.i(TAG, "Meta data ref " + name + ": " + v); 2277 data.putInt(name, v.resourceId); 2278 } else { 2279 v = sa.peekValue( 2280 com.android.internal.R.styleable.AndroidManifestMetaData_value); 2281 //Log.i(TAG, "Meta data " + name + ": " + v); 2282 if (v != null) { 2283 if (v.type == TypedValue.TYPE_STRING) { 2284 CharSequence cs = v.coerceToString(); 2285 data.putString(name, cs != null ? cs.toString().intern() : null); 2286 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { 2287 data.putBoolean(name, v.data != 0); 2288 } else if (v.type >= TypedValue.TYPE_FIRST_INT 2289 && v.type <= TypedValue.TYPE_LAST_INT) { 2290 data.putInt(name, v.data); 2291 } else if (v.type == TypedValue.TYPE_FLOAT) { 2292 data.putFloat(name, v.getFloat()); 2293 } else { 2294 if (!RIGID_PARSER) { 2295 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 2296 Log.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types"); 2297 } else { 2298 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types"; 2299 data = null; 2300 } 2301 } 2302 } else { 2303 outError[0] = "<meta-data> requires an android:value or android:resource attribute"; 2304 data = null; 2305 } 2306 } 2307 2308 sa.recycle(); 2309 2310 XmlUtils.skipCurrentTag(parser); 2311 2312 return data; 2313 } 2314 2315 private static final String ANDROID_RESOURCES 2316 = "http://schemas.android.com/apk/res/android"; 2317 2318 private boolean parseIntent(Resources res, 2319 XmlPullParser parser, AttributeSet attrs, int flags, 2320 IntentInfo outInfo, String[] outError, boolean isActivity) 2321 throws XmlPullParserException, IOException { 2322 2323 TypedArray sa = res.obtainAttributes(attrs, 2324 com.android.internal.R.styleable.AndroidManifestIntentFilter); 2325 2326 int priority = sa.getInt( 2327 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0); 2328 if (priority > 0 && isActivity && (flags&PARSE_IS_SYSTEM) == 0) { 2329 Log.w(TAG, "Activity with priority > 0, forcing to 0 at " 2330 + parser.getPositionDescription()); 2331 priority = 0; 2332 } 2333 outInfo.setPriority(priority); 2334 2335 TypedValue v = sa.peekValue( 2336 com.android.internal.R.styleable.AndroidManifestIntentFilter_label); 2337 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 2338 outInfo.nonLocalizedLabel = v.coerceToString(); 2339 } 2340 2341 outInfo.icon = sa.getResourceId( 2342 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0); 2343 2344 sa.recycle(); 2345 2346 int outerDepth = parser.getDepth(); 2347 int type; 2348 while ((type=parser.next()) != parser.END_DOCUMENT 2349 && (type != parser.END_TAG || parser.getDepth() > outerDepth)) { 2350 if (type == parser.END_TAG || type == parser.TEXT) { 2351 continue; 2352 } 2353 2354 String nodeName = parser.getName(); 2355 if (nodeName.equals("action")) { 2356 String value = attrs.getAttributeValue( 2357 ANDROID_RESOURCES, "name"); 2358 if (value == null || value == "") { 2359 outError[0] = "No value supplied for <android:name>"; 2360 return false; 2361 } 2362 XmlUtils.skipCurrentTag(parser); 2363 2364 outInfo.addAction(value); 2365 } else if (nodeName.equals("category")) { 2366 String value = attrs.getAttributeValue( 2367 ANDROID_RESOURCES, "name"); 2368 if (value == null || value == "") { 2369 outError[0] = "No value supplied for <android:name>"; 2370 return false; 2371 } 2372 XmlUtils.skipCurrentTag(parser); 2373 2374 outInfo.addCategory(value); 2375 2376 } else if (nodeName.equals("data")) { 2377 sa = res.obtainAttributes(attrs, 2378 com.android.internal.R.styleable.AndroidManifestData); 2379 2380 String str = sa.getNonResourceString( 2381 com.android.internal.R.styleable.AndroidManifestData_mimeType); 2382 if (str != null) { 2383 try { 2384 outInfo.addDataType(str); 2385 } catch (IntentFilter.MalformedMimeTypeException e) { 2386 outError[0] = e.toString(); 2387 sa.recycle(); 2388 return false; 2389 } 2390 } 2391 2392 str = sa.getNonResourceString( 2393 com.android.internal.R.styleable.AndroidManifestData_scheme); 2394 if (str != null) { 2395 outInfo.addDataScheme(str); 2396 } 2397 2398 String host = sa.getNonResourceString( 2399 com.android.internal.R.styleable.AndroidManifestData_host); 2400 String port = sa.getNonResourceString( 2401 com.android.internal.R.styleable.AndroidManifestData_port); 2402 if (host != null) { 2403 outInfo.addDataAuthority(host, port); 2404 } 2405 2406 str = sa.getNonResourceString( 2407 com.android.internal.R.styleable.AndroidManifestData_path); 2408 if (str != null) { 2409 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); 2410 } 2411 2412 str = sa.getNonResourceString( 2413 com.android.internal.R.styleable.AndroidManifestData_pathPrefix); 2414 if (str != null) { 2415 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); 2416 } 2417 2418 str = sa.getNonResourceString( 2419 com.android.internal.R.styleable.AndroidManifestData_pathPattern); 2420 if (str != null) { 2421 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 2422 } 2423 2424 sa.recycle(); 2425 XmlUtils.skipCurrentTag(parser); 2426 } else if (!RIGID_PARSER) { 2427 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 2428 Log.w(TAG, "Unknown element under <intent-filter>: " + parser.getName()); 2429 XmlUtils.skipCurrentTag(parser); 2430 } else { 2431 outError[0] = "Bad element under <intent-filter>: " + parser.getName(); 2432 return false; 2433 } 2434 } 2435 2436 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT); 2437 if (false) { 2438 String cats = ""; 2439 Iterator<String> it = outInfo.categoriesIterator(); 2440 while (it != null && it.hasNext()) { 2441 cats += " " + it.next(); 2442 } 2443 System.out.println("Intent d=" + 2444 outInfo.hasDefault + ", cat=" + cats); 2445 } 2446 2447 return true; 2448 } 2449 2450 public final static class Package { 2451 public final String packageName; 2452 2453 // For now we only support one application per package. 2454 public final ApplicationInfo applicationInfo = new ApplicationInfo(); 2455 2456 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0); 2457 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0); 2458 public final ArrayList<Activity> activities = new ArrayList<Activity>(0); 2459 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0); 2460 public final ArrayList<Provider> providers = new ArrayList<Provider>(0); 2461 public final ArrayList<Service> services = new ArrayList<Service>(0); 2462 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0); 2463 2464 public final ArrayList<String> requestedPermissions = new ArrayList<String>(); 2465 2466 public ArrayList<String> protectedBroadcasts; 2467 2468 public ArrayList<String> usesLibraries = null; 2469 public ArrayList<String> usesOptionalLibraries = null; 2470 public String[] usesLibraryFiles = null; 2471 2472 // We store the application meta-data independently to avoid multiple unwanted references 2473 public Bundle mAppMetaData = null; 2474 2475 // If this is a 3rd party app, this is the path of the zip file. 2476 public String mPath; 2477 2478 // The version code declared for this package. 2479 public int mVersionCode; 2480 2481 // The version name declared for this package. 2482 public String mVersionName; 2483 2484 // The shared user id that this package wants to use. 2485 public String mSharedUserId; 2486 2487 // The shared user label that this package wants to use. 2488 public int mSharedUserLabel; 2489 2490 // Signatures that were read from the package. 2491 public Signature mSignatures[]; 2492 2493 // For use by package manager service for quick lookup of 2494 // preferred up order. 2495 public int mPreferredOrder = 0; 2496 2497 // For use by package manager service to keep track of which apps 2498 // have been installed with forward locking. 2499 public boolean mForwardLocked; 2500 2501 // For use by the package manager to keep track of the path to the 2502 // file an app came from. 2503 public String mScanPath; 2504 2505 // For use by package manager to keep track of where it has done dexopt. 2506 public boolean mDidDexOpt; 2507 2508 // Additional data supplied by callers. 2509 public Object mExtras; 2510 2511 /* 2512 * Applications hardware preferences 2513 */ 2514 public final ArrayList<ConfigurationInfo> configPreferences = 2515 new ArrayList<ConfigurationInfo>(); 2516 2517 /* 2518 * Applications requested features 2519 */ 2520 public ArrayList<FeatureInfo> reqFeatures = null; 2521 2522 public Package(String _name) { 2523 packageName = _name; 2524 applicationInfo.packageName = _name; 2525 applicationInfo.uid = -1; 2526 } 2527 2528 public String toString() { 2529 return "Package{" 2530 + Integer.toHexString(System.identityHashCode(this)) 2531 + " " + packageName + "}"; 2532 } 2533 } 2534 2535 public static class Component<II extends IntentInfo> { 2536 public final Package owner; 2537 public final ArrayList<II> intents; 2538 public final ComponentName component; 2539 public final String componentShortName; 2540 public Bundle metaData; 2541 2542 public Component(Package _owner) { 2543 owner = _owner; 2544 intents = null; 2545 component = null; 2546 componentShortName = null; 2547 } 2548 2549 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) { 2550 owner = args.owner; 2551 intents = new ArrayList<II>(0); 2552 String name = args.sa.getNonResourceString(args.nameRes); 2553 if (name == null) { 2554 component = null; 2555 componentShortName = null; 2556 args.outError[0] = args.tag + " does not specify android:name"; 2557 return; 2558 } 2559 2560 outInfo.name 2561 = buildClassName(owner.applicationInfo.packageName, name, args.outError); 2562 if (outInfo.name == null) { 2563 component = null; 2564 componentShortName = null; 2565 args.outError[0] = args.tag + " does not have valid android:name"; 2566 return; 2567 } 2568 2569 component = new ComponentName(owner.applicationInfo.packageName, 2570 outInfo.name); 2571 componentShortName = component.flattenToShortString(); 2572 2573 int iconVal = args.sa.getResourceId(args.iconRes, 0); 2574 if (iconVal != 0) { 2575 outInfo.icon = iconVal; 2576 outInfo.nonLocalizedLabel = null; 2577 } 2578 2579 TypedValue v = args.sa.peekValue(args.labelRes); 2580 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 2581 outInfo.nonLocalizedLabel = v.coerceToString(); 2582 } 2583 2584 outInfo.packageName = owner.packageName; 2585 } 2586 2587 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) { 2588 this(args, (PackageItemInfo)outInfo); 2589 if (args.outError[0] != null) { 2590 return; 2591 } 2592 2593 if (args.processRes != 0) { 2594 outInfo.processName = buildProcessName(owner.applicationInfo.packageName, 2595 owner.applicationInfo.processName, args.sa.getNonResourceString(args.processRes), 2596 args.flags, args.sepProcesses, args.outError); 2597 } 2598 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true); 2599 } 2600 2601 public Component(Component<II> clone) { 2602 owner = clone.owner; 2603 intents = clone.intents; 2604 component = clone.component; 2605 componentShortName = clone.componentShortName; 2606 metaData = clone.metaData; 2607 } 2608 } 2609 2610 public final static class Permission extends Component<IntentInfo> { 2611 public final PermissionInfo info; 2612 public boolean tree; 2613 public PermissionGroup group; 2614 2615 public Permission(Package _owner) { 2616 super(_owner); 2617 info = new PermissionInfo(); 2618 } 2619 2620 public Permission(Package _owner, PermissionInfo _info) { 2621 super(_owner); 2622 info = _info; 2623 } 2624 2625 public String toString() { 2626 return "Permission{" 2627 + Integer.toHexString(System.identityHashCode(this)) 2628 + " " + info.name + "}"; 2629 } 2630 } 2631 2632 public final static class PermissionGroup extends Component<IntentInfo> { 2633 public final PermissionGroupInfo info; 2634 2635 public PermissionGroup(Package _owner) { 2636 super(_owner); 2637 info = new PermissionGroupInfo(); 2638 } 2639 2640 public PermissionGroup(Package _owner, PermissionGroupInfo _info) { 2641 super(_owner); 2642 info = _info; 2643 } 2644 2645 public String toString() { 2646 return "PermissionGroup{" 2647 + Integer.toHexString(System.identityHashCode(this)) 2648 + " " + info.name + "}"; 2649 } 2650 } 2651 2652 private static boolean copyNeeded(int flags, Package p, Bundle metaData) { 2653 if ((flags & PackageManager.GET_META_DATA) != 0 2654 && (metaData != null || p.mAppMetaData != null)) { 2655 return true; 2656 } 2657 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 2658 && p.usesLibraryFiles != null) { 2659 return true; 2660 } 2661 return false; 2662 } 2663 2664 public static ApplicationInfo generateApplicationInfo(Package p, int flags) { 2665 if (p == null) return null; 2666 if (!copyNeeded(flags, p, null)) { 2667 // CompatibilityMode is global state. It's safe to modify the instance 2668 // of the package. 2669 if (!sCompatibilityModeEnabled) { 2670 p.applicationInfo.disableCompatibilityMode(); 2671 } 2672 return p.applicationInfo; 2673 } 2674 2675 // Make shallow copy so we can store the metadata/libraries safely 2676 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo); 2677 if ((flags & PackageManager.GET_META_DATA) != 0) { 2678 ai.metaData = p.mAppMetaData; 2679 } 2680 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { 2681 ai.sharedLibraryFiles = p.usesLibraryFiles; 2682 } 2683 if (!sCompatibilityModeEnabled) { 2684 ai.disableCompatibilityMode(); 2685 } 2686 return ai; 2687 } 2688 2689 public static final PermissionInfo generatePermissionInfo( 2690 Permission p, int flags) { 2691 if (p == null) return null; 2692 if ((flags&PackageManager.GET_META_DATA) == 0) { 2693 return p.info; 2694 } 2695 PermissionInfo pi = new PermissionInfo(p.info); 2696 pi.metaData = p.metaData; 2697 return pi; 2698 } 2699 2700 public static final PermissionGroupInfo generatePermissionGroupInfo( 2701 PermissionGroup pg, int flags) { 2702 if (pg == null) return null; 2703 if ((flags&PackageManager.GET_META_DATA) == 0) { 2704 return pg.info; 2705 } 2706 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info); 2707 pgi.metaData = pg.metaData; 2708 return pgi; 2709 } 2710 2711 public final static class Activity extends Component<ActivityIntentInfo> { 2712 public final ActivityInfo info; 2713 2714 public Activity(final ParseComponentArgs args, final ActivityInfo _info) { 2715 super(args, _info); 2716 info = _info; 2717 info.applicationInfo = args.owner.applicationInfo; 2718 } 2719 2720 public String toString() { 2721 return "Activity{" 2722 + Integer.toHexString(System.identityHashCode(this)) 2723 + " " + component.flattenToString() + "}"; 2724 } 2725 } 2726 2727 public static final ActivityInfo generateActivityInfo(Activity a, 2728 int flags) { 2729 if (a == null) return null; 2730 if (!copyNeeded(flags, a.owner, a.metaData)) { 2731 return a.info; 2732 } 2733 // Make shallow copies so we can store the metadata safely 2734 ActivityInfo ai = new ActivityInfo(a.info); 2735 ai.metaData = a.metaData; 2736 ai.applicationInfo = generateApplicationInfo(a.owner, flags); 2737 return ai; 2738 } 2739 2740 public final static class Service extends Component<ServiceIntentInfo> { 2741 public final ServiceInfo info; 2742 2743 public Service(final ParseComponentArgs args, final ServiceInfo _info) { 2744 super(args, _info); 2745 info = _info; 2746 info.applicationInfo = args.owner.applicationInfo; 2747 } 2748 2749 public String toString() { 2750 return "Service{" 2751 + Integer.toHexString(System.identityHashCode(this)) 2752 + " " + component.flattenToString() + "}"; 2753 } 2754 } 2755 2756 public static final ServiceInfo generateServiceInfo(Service s, int flags) { 2757 if (s == null) return null; 2758 if (!copyNeeded(flags, s.owner, s.metaData)) { 2759 return s.info; 2760 } 2761 // Make shallow copies so we can store the metadata safely 2762 ServiceInfo si = new ServiceInfo(s.info); 2763 si.metaData = s.metaData; 2764 si.applicationInfo = generateApplicationInfo(s.owner, flags); 2765 return si; 2766 } 2767 2768 public final static class Provider extends Component { 2769 public final ProviderInfo info; 2770 public boolean syncable; 2771 2772 public Provider(final ParseComponentArgs args, final ProviderInfo _info) { 2773 super(args, _info); 2774 info = _info; 2775 info.applicationInfo = args.owner.applicationInfo; 2776 syncable = false; 2777 } 2778 2779 public Provider(Provider existingProvider) { 2780 super(existingProvider); 2781 this.info = existingProvider.info; 2782 this.syncable = existingProvider.syncable; 2783 } 2784 2785 public String toString() { 2786 return "Provider{" 2787 + Integer.toHexString(System.identityHashCode(this)) 2788 + " " + info.name + "}"; 2789 } 2790 } 2791 2792 public static final ProviderInfo generateProviderInfo(Provider p, 2793 int flags) { 2794 if (p == null) return null; 2795 if (!copyNeeded(flags, p.owner, p.metaData) 2796 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 2797 || p.info.uriPermissionPatterns == null)) { 2798 return p.info; 2799 } 2800 // Make shallow copies so we can store the metadata safely 2801 ProviderInfo pi = new ProviderInfo(p.info); 2802 pi.metaData = p.metaData; 2803 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { 2804 pi.uriPermissionPatterns = null; 2805 } 2806 pi.applicationInfo = generateApplicationInfo(p.owner, flags); 2807 return pi; 2808 } 2809 2810 public final static class Instrumentation extends Component { 2811 public final InstrumentationInfo info; 2812 2813 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) { 2814 super(args, _info); 2815 info = _info; 2816 } 2817 2818 public String toString() { 2819 return "Instrumentation{" 2820 + Integer.toHexString(System.identityHashCode(this)) 2821 + " " + component.flattenToString() + "}"; 2822 } 2823 } 2824 2825 public static final InstrumentationInfo generateInstrumentationInfo( 2826 Instrumentation i, int flags) { 2827 if (i == null) return null; 2828 if ((flags&PackageManager.GET_META_DATA) == 0) { 2829 return i.info; 2830 } 2831 InstrumentationInfo ii = new InstrumentationInfo(i.info); 2832 ii.metaData = i.metaData; 2833 return ii; 2834 } 2835 2836 public static class IntentInfo extends IntentFilter { 2837 public boolean hasDefault; 2838 public int labelRes; 2839 public CharSequence nonLocalizedLabel; 2840 public int icon; 2841 } 2842 2843 public final static class ActivityIntentInfo extends IntentInfo { 2844 public final Activity activity; 2845 2846 public ActivityIntentInfo(Activity _activity) { 2847 activity = _activity; 2848 } 2849 2850 public String toString() { 2851 return "ActivityIntentInfo{" 2852 + Integer.toHexString(System.identityHashCode(this)) 2853 + " " + activity.info.name + "}"; 2854 } 2855 } 2856 2857 public final static class ServiceIntentInfo extends IntentInfo { 2858 public final Service service; 2859 2860 public ServiceIntentInfo(Service _service) { 2861 service = _service; 2862 } 2863 2864 public String toString() { 2865 return "ServiceIntentInfo{" 2866 + Integer.toHexString(System.identityHashCode(this)) 2867 + " " + service.info.name + "}"; 2868 } 2869 } 2870 2871 /** 2872 * @hide 2873 */ 2874 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { 2875 sCompatibilityModeEnabled = compatibilityModeEnabled; 2876 } 2877} 2878