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