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