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