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