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