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