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