PackageParser.java revision 8472e6189cd4e0520c047bdb28457abc728b373f
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.content.pm; 18 19import android.content.ComponentName; 20import android.content.Intent; 21import android.content.IntentFilter; 22import android.content.res.AssetManager; 23import android.content.res.Configuration; 24import android.content.res.Resources; 25import android.content.res.TypedArray; 26import android.content.res.XmlResourceParser; 27import android.os.Build; 28import android.os.Bundle; 29import android.os.PatternMatcher; 30import android.os.UserHandle; 31import android.util.AttributeSet; 32import android.util.Base64; 33import android.util.DisplayMetrics; 34import android.util.Log; 35import android.util.Slog; 36import android.util.TypedValue; 37 38import java.io.BufferedInputStream; 39import java.io.File; 40import java.io.IOException; 41import java.io.InputStream; 42import java.io.PrintWriter; 43import java.lang.ref.WeakReference; 44import java.security.KeyFactory; 45import java.security.NoSuchAlgorithmException; 46import java.security.PublicKey; 47import java.security.cert.Certificate; 48import java.security.cert.CertificateEncodingException; 49import java.security.spec.EncodedKeySpec; 50import java.security.spec.InvalidKeySpecException; 51import java.security.spec.X509EncodedKeySpec; 52import java.util.ArrayList; 53import java.util.Enumeration; 54import java.util.HashMap; 55import java.util.HashSet; 56import java.util.Iterator; 57import java.util.List; 58import java.util.Map; 59import java.util.Set; 60import java.util.jar.JarEntry; 61import java.util.jar.StrictJarFile; 62import java.util.zip.ZipEntry; 63 64import com.android.internal.util.XmlUtils; 65 66import org.xmlpull.v1.XmlPullParser; 67import org.xmlpull.v1.XmlPullParserException; 68 69/** 70 * Package archive parsing 71 * 72 * {@hide} 73 */ 74public class PackageParser { 75 private static final boolean DEBUG_JAR = false; 76 private static final boolean DEBUG_PARSER = false; 77 private static final boolean DEBUG_BACKUP = false; 78 79 /** File name in an APK for the Android manifest. */ 80 private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; 81 82 /** @hide */ 83 public static class NewPermissionInfo { 84 public final String name; 85 public final int sdkVersion; 86 public final int fileVersion; 87 88 public NewPermissionInfo(String name, int sdkVersion, int fileVersion) { 89 this.name = name; 90 this.sdkVersion = sdkVersion; 91 this.fileVersion = fileVersion; 92 } 93 } 94 95 /** @hide */ 96 public static class SplitPermissionInfo { 97 public final String rootPerm; 98 public final String[] newPerms; 99 public final int targetSdk; 100 101 public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) { 102 this.rootPerm = rootPerm; 103 this.newPerms = newPerms; 104 this.targetSdk = targetSdk; 105 } 106 } 107 108 /** 109 * List of new permissions that have been added since 1.0. 110 * NOTE: These must be declared in SDK version order, with permissions 111 * added to older SDKs appearing before those added to newer SDKs. 112 * If sdkVersion is 0, then this is not a permission that we want to 113 * automatically add to older apps, but we do want to allow it to be 114 * granted during a platform update. 115 * @hide 116 */ 117 public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] = 118 new PackageParser.NewPermissionInfo[] { 119 new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 120 android.os.Build.VERSION_CODES.DONUT, 0), 121 new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE, 122 android.os.Build.VERSION_CODES.DONUT, 0) 123 }; 124 125 /** 126 * List of permissions that have been split into more granular or dependent 127 * permissions. 128 * @hide 129 */ 130 public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] = 131 new PackageParser.SplitPermissionInfo[] { 132 // READ_EXTERNAL_STORAGE is always required when an app requests 133 // WRITE_EXTERNAL_STORAGE, because we can't have an app that has 134 // write access without read access. The hack here with the target 135 // target SDK version ensures that this grant is always done. 136 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 137 new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE }, 138 android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1), 139 new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS, 140 new String[] { android.Manifest.permission.READ_CALL_LOG }, 141 android.os.Build.VERSION_CODES.JELLY_BEAN), 142 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS, 143 new String[] { android.Manifest.permission.WRITE_CALL_LOG }, 144 android.os.Build.VERSION_CODES.JELLY_BEAN) 145 }; 146 147 private String mArchiveSourcePath; 148 private String[] mSeparateProcesses; 149 private boolean mOnlyCoreApps; 150 private static final int SDK_VERSION = Build.VERSION.SDK_INT; 151 private static final String SDK_CODENAME = "REL".equals(Build.VERSION.CODENAME) 152 ? null : Build.VERSION.CODENAME; 153 154 private int mParseError = PackageManager.INSTALL_SUCCEEDED; 155 156 private static final Object mSync = new Object(); 157 private static WeakReference<byte[]> mReadBuffer; 158 159 private static boolean sCompatibilityModeEnabled = true; 160 private static final int PARSE_DEFAULT_INSTALL_LOCATION = 161 PackageInfo.INSTALL_LOCATION_UNSPECIFIED; 162 163 static class ParsePackageItemArgs { 164 final Package owner; 165 final String[] outError; 166 final int nameRes; 167 final int labelRes; 168 final int iconRes; 169 final int logoRes; 170 171 String tag; 172 TypedArray sa; 173 174 ParsePackageItemArgs(Package _owner, String[] _outError, 175 int _nameRes, int _labelRes, int _iconRes, int _logoRes) { 176 owner = _owner; 177 outError = _outError; 178 nameRes = _nameRes; 179 labelRes = _labelRes; 180 iconRes = _iconRes; 181 logoRes = _logoRes; 182 } 183 } 184 185 static class ParseComponentArgs extends ParsePackageItemArgs { 186 final String[] sepProcesses; 187 final int processRes; 188 final int descriptionRes; 189 final int enabledRes; 190 int flags; 191 192 ParseComponentArgs(Package _owner, String[] _outError, 193 int _nameRes, int _labelRes, int _iconRes, int _logoRes, 194 String[] _sepProcesses, int _processRes, 195 int _descriptionRes, int _enabledRes) { 196 super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes); 197 sepProcesses = _sepProcesses; 198 processRes = _processRes; 199 descriptionRes = _descriptionRes; 200 enabledRes = _enabledRes; 201 } 202 } 203 204 /* Light weight package info. 205 * @hide 206 */ 207 public static class PackageLite { 208 public final String packageName; 209 public final int versionCode; 210 public final int installLocation; 211 public final VerifierInfo[] verifiers; 212 213 public PackageLite(String packageName, int versionCode, 214 int installLocation, List<VerifierInfo> verifiers) { 215 this.packageName = packageName; 216 this.versionCode = versionCode; 217 this.installLocation = installLocation; 218 this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]); 219 } 220 } 221 222 private ParsePackageItemArgs mParseInstrumentationArgs; 223 private ParseComponentArgs mParseActivityArgs; 224 private ParseComponentArgs mParseActivityAliasArgs; 225 private ParseComponentArgs mParseServiceArgs; 226 private ParseComponentArgs mParseProviderArgs; 227 228 /** If set to true, we will only allow package files that exactly match 229 * the DTD. Otherwise, we try to get as much from the package as we 230 * can without failing. This should normally be set to false, to 231 * support extensions to the DTD in future versions. */ 232 private static final boolean RIGID_PARSER = false; 233 234 private static final String TAG = "PackageParser"; 235 236 public PackageParser(String archiveSourcePath) { 237 mArchiveSourcePath = archiveSourcePath; 238 } 239 240 public void setSeparateProcesses(String[] procs) { 241 mSeparateProcesses = procs; 242 } 243 244 public void setOnlyCoreApps(boolean onlyCoreApps) { 245 mOnlyCoreApps = onlyCoreApps; 246 } 247 248 private static final boolean isPackageFilename(String name) { 249 return name.endsWith(".apk"); 250 } 251 252 /* 253 public static PackageInfo generatePackageInfo(PackageParser.Package p, 254 int gids[], int flags, long firstInstallTime, long lastUpdateTime, 255 HashSet<String> grantedPermissions) { 256 PackageUserState state = new PackageUserState(); 257 return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, 258 grantedPermissions, state, UserHandle.getCallingUserId()); 259 } 260 */ 261 262 /** 263 * Generate and return the {@link PackageInfo} for a parsed package. 264 * 265 * @param p the parsed package. 266 * @param flags indicating which optional information is included. 267 */ 268 public static PackageInfo generatePackageInfo(PackageParser.Package p, 269 int gids[], int flags, long firstInstallTime, long lastUpdateTime, 270 HashSet<String> grantedPermissions, PackageUserState state) { 271 272 return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, 273 grantedPermissions, state, UserHandle.getCallingUserId()); 274 } 275 276 /** 277 * Returns true if the package is installed and not blocked, or if the caller 278 * explicitly wanted all uninstalled and blocked packages as well. 279 */ 280 private static boolean checkUseInstalledOrBlocked(int flags, PackageUserState state) { 281 return (state.installed && !state.blocked) 282 || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; 283 } 284 285 public static boolean isAvailable(PackageUserState state) { 286 return checkUseInstalledOrBlocked(0, state); 287 } 288 289 public static PackageInfo generatePackageInfo(PackageParser.Package p, 290 int gids[], int flags, long firstInstallTime, long lastUpdateTime, 291 HashSet<String> grantedPermissions, PackageUserState state, int userId) { 292 293 if (!checkUseInstalledOrBlocked(flags, state)) { 294 return null; 295 } 296 PackageInfo pi = new PackageInfo(); 297 pi.packageName = p.packageName; 298 pi.versionCode = p.mVersionCode; 299 pi.versionName = p.mVersionName; 300 pi.sharedUserId = p.mSharedUserId; 301 pi.sharedUserLabel = p.mSharedUserLabel; 302 pi.applicationInfo = generateApplicationInfo(p, flags, state, userId); 303 pi.installLocation = p.installLocation; 304 if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0 305 || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { 306 pi.requiredForAllUsers = p.mRequiredForAllUsers; 307 } 308 pi.restrictedAccountType = p.mRestrictedAccountType; 309 pi.requiredAccountType = p.mRequiredAccountType; 310 pi.firstInstallTime = firstInstallTime; 311 pi.lastUpdateTime = lastUpdateTime; 312 if ((flags&PackageManager.GET_GIDS) != 0) { 313 pi.gids = gids; 314 } 315 if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) { 316 int N = p.configPreferences.size(); 317 if (N > 0) { 318 pi.configPreferences = new ConfigurationInfo[N]; 319 p.configPreferences.toArray(pi.configPreferences); 320 } 321 N = p.reqFeatures != null ? p.reqFeatures.size() : 0; 322 if (N > 0) { 323 pi.reqFeatures = new FeatureInfo[N]; 324 p.reqFeatures.toArray(pi.reqFeatures); 325 } 326 } 327 if ((flags&PackageManager.GET_ACTIVITIES) != 0) { 328 int N = p.activities.size(); 329 if (N > 0) { 330 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 331 pi.activities = new ActivityInfo[N]; 332 } else { 333 int num = 0; 334 for (int i=0; i<N; i++) { 335 if (p.activities.get(i).info.enabled) num++; 336 } 337 pi.activities = new ActivityInfo[num]; 338 } 339 for (int i=0, j=0; i<N; i++) { 340 final Activity activity = p.activities.get(i); 341 if (activity.info.enabled 342 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 343 pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags, 344 state, userId); 345 } 346 } 347 } 348 } 349 if ((flags&PackageManager.GET_RECEIVERS) != 0) { 350 int N = p.receivers.size(); 351 if (N > 0) { 352 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 353 pi.receivers = new ActivityInfo[N]; 354 } else { 355 int num = 0; 356 for (int i=0; i<N; i++) { 357 if (p.receivers.get(i).info.enabled) num++; 358 } 359 pi.receivers = new ActivityInfo[num]; 360 } 361 for (int i=0, j=0; i<N; i++) { 362 final Activity activity = p.receivers.get(i); 363 if (activity.info.enabled 364 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 365 pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags, 366 state, userId); 367 } 368 } 369 } 370 } 371 if ((flags&PackageManager.GET_SERVICES) != 0) { 372 int N = p.services.size(); 373 if (N > 0) { 374 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 375 pi.services = new ServiceInfo[N]; 376 } else { 377 int num = 0; 378 for (int i=0; i<N; i++) { 379 if (p.services.get(i).info.enabled) num++; 380 } 381 pi.services = new ServiceInfo[num]; 382 } 383 for (int i=0, j=0; i<N; i++) { 384 final Service service = p.services.get(i); 385 if (service.info.enabled 386 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 387 pi.services[j++] = generateServiceInfo(p.services.get(i), flags, 388 state, userId); 389 } 390 } 391 } 392 } 393 if ((flags&PackageManager.GET_PROVIDERS) != 0) { 394 int N = p.providers.size(); 395 if (N > 0) { 396 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 397 pi.providers = new ProviderInfo[N]; 398 } else { 399 int num = 0; 400 for (int i=0; i<N; i++) { 401 if (p.providers.get(i).info.enabled) num++; 402 } 403 pi.providers = new ProviderInfo[num]; 404 } 405 for (int i=0, j=0; i<N; i++) { 406 final Provider provider = p.providers.get(i); 407 if (provider.info.enabled 408 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { 409 pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, 410 state, userId); 411 } 412 } 413 } 414 } 415 if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) { 416 int N = p.instrumentation.size(); 417 if (N > 0) { 418 pi.instrumentation = new InstrumentationInfo[N]; 419 for (int i=0; i<N; i++) { 420 pi.instrumentation[i] = generateInstrumentationInfo( 421 p.instrumentation.get(i), flags); 422 } 423 } 424 } 425 if ((flags&PackageManager.GET_PERMISSIONS) != 0) { 426 int N = p.permissions.size(); 427 if (N > 0) { 428 pi.permissions = new PermissionInfo[N]; 429 for (int i=0; i<N; i++) { 430 pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags); 431 } 432 } 433 N = p.requestedPermissions.size(); 434 if (N > 0) { 435 pi.requestedPermissions = new String[N]; 436 pi.requestedPermissionsFlags = new int[N]; 437 for (int i=0; i<N; i++) { 438 final String perm = p.requestedPermissions.get(i); 439 pi.requestedPermissions[i] = perm; 440 if (p.requestedPermissionsRequired.get(i)) { 441 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED; 442 } 443 if (grantedPermissions != null && grantedPermissions.contains(perm)) { 444 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED; 445 } 446 } 447 } 448 } 449 if ((flags&PackageManager.GET_SIGNATURES) != 0) { 450 int N = (p.mSignatures != null) ? p.mSignatures.length : 0; 451 if (N > 0) { 452 pi.signatures = new Signature[N]; 453 System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N); 454 } 455 } 456 return pi; 457 } 458 459 private Certificate[] loadCertificates(StrictJarFile jarFile, ZipEntry je, 460 byte[] readBuffer) { 461 try { 462 // We must read the stream for the JarEntry to retrieve 463 // its certificates. 464 InputStream is = new BufferedInputStream(jarFile.getInputStream(je)); 465 while (is.read(readBuffer, 0, readBuffer.length) != -1) { 466 // not using 467 } 468 is.close(); 469 return je != null ? jarFile.getCertificates(je) : null; 470 } catch (IOException e) { 471 Slog.w(TAG, "Exception reading " + je.getName() + " in " + jarFile, e); 472 } catch (RuntimeException e) { 473 Slog.w(TAG, "Exception reading " + je.getName() + " in " + jarFile, e); 474 } 475 return null; 476 } 477 478 public final static int PARSE_IS_SYSTEM = 1<<0; 479 public final static int PARSE_CHATTY = 1<<1; 480 public final static int PARSE_MUST_BE_APK = 1<<2; 481 public final static int PARSE_IGNORE_PROCESSES = 1<<3; 482 public final static int PARSE_FORWARD_LOCK = 1<<4; 483 public final static int PARSE_ON_SDCARD = 1<<5; 484 public final static int PARSE_IS_SYSTEM_DIR = 1<<6; 485 public final static int PARSE_IS_PRIVILEGED = 1<<7; 486 487 public int getParseError() { 488 return mParseError; 489 } 490 491 public Package parsePackage(File sourceFile, String destCodePath, 492 DisplayMetrics metrics, int flags) { 493 mParseError = PackageManager.INSTALL_SUCCEEDED; 494 495 mArchiveSourcePath = sourceFile.getPath(); 496 if (!sourceFile.isFile()) { 497 Slog.w(TAG, "Skipping dir: " + mArchiveSourcePath); 498 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; 499 return null; 500 } 501 if (!isPackageFilename(sourceFile.getName()) 502 && (flags&PARSE_MUST_BE_APK) != 0) { 503 if ((flags&PARSE_IS_SYSTEM) == 0) { 504 // We expect to have non-.apk files in the system dir, 505 // so don't warn about them. 506 Slog.w(TAG, "Skipping non-package file: " + mArchiveSourcePath); 507 } 508 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; 509 return null; 510 } 511 512 if (DEBUG_JAR) 513 Slog.d(TAG, "Scanning package: " + mArchiveSourcePath); 514 515 XmlResourceParser parser = null; 516 AssetManager assmgr = null; 517 Resources res = null; 518 boolean assetError = true; 519 try { 520 assmgr = new AssetManager(); 521 int cookie = assmgr.addAssetPath(mArchiveSourcePath); 522 if (cookie != 0) { 523 res = new Resources(assmgr, metrics, null); 524 assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 525 Build.VERSION.RESOURCES_SDK_INT); 526 parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 527 assetError = false; 528 } else { 529 Slog.w(TAG, "Failed adding asset path:"+mArchiveSourcePath); 530 } 531 } catch (Exception e) { 532 Slog.w(TAG, "Unable to read AndroidManifest.xml of " 533 + mArchiveSourcePath, e); 534 } 535 if (assetError) { 536 if (assmgr != null) assmgr.close(); 537 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; 538 return null; 539 } 540 String[] errorText = new String[1]; 541 Package pkg = null; 542 Exception errorException = null; 543 try { 544 // XXXX todo: need to figure out correct configuration. 545 pkg = parsePackage(res, parser, flags, errorText); 546 } catch (Exception e) { 547 errorException = e; 548 mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; 549 } 550 551 552 if (pkg == null) { 553 // If we are only parsing core apps, then a null with INSTALL_SUCCEEDED 554 // just means to skip this app so don't make a fuss about it. 555 if (!mOnlyCoreApps || mParseError != PackageManager.INSTALL_SUCCEEDED) { 556 if (errorException != null) { 557 Slog.w(TAG, mArchiveSourcePath, errorException); 558 } else { 559 Slog.w(TAG, mArchiveSourcePath + " (at " 560 + parser.getPositionDescription() 561 + "): " + errorText[0]); 562 } 563 if (mParseError == PackageManager.INSTALL_SUCCEEDED) { 564 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 565 } 566 } 567 parser.close(); 568 assmgr.close(); 569 return null; 570 } 571 572 parser.close(); 573 assmgr.close(); 574 575 // Set code and resource paths 576 pkg.mPath = destCodePath; 577 pkg.mScanPath = mArchiveSourcePath; 578 //pkg.applicationInfo.sourceDir = destCodePath; 579 //pkg.applicationInfo.publicSourceDir = destRes; 580 pkg.mSignatures = null; 581 582 return pkg; 583 } 584 585 /** 586 * Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the 587 * APK. If it successfully scanned the package and found the 588 * {@code AndroidManifest.xml}, {@code true} is returned. 589 */ 590 public boolean collectManifestDigest(Package pkg) { 591 try { 592 final StrictJarFile jarFile = new StrictJarFile(mArchiveSourcePath); 593 try { 594 final ZipEntry je = jarFile.findEntry(ANDROID_MANIFEST_FILENAME); 595 if (je != null) { 596 pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je)); 597 } 598 } finally { 599 jarFile.close(); 600 } 601 return true; 602 } catch (IOException e) { 603 return false; 604 } 605 } 606 607 public boolean collectCertificates(Package pkg, int flags) { 608 pkg.mSignatures = null; 609 610 WeakReference<byte[]> readBufferRef; 611 byte[] readBuffer = null; 612 synchronized (mSync) { 613 readBufferRef = mReadBuffer; 614 if (readBufferRef != null) { 615 mReadBuffer = null; 616 readBuffer = readBufferRef.get(); 617 } 618 if (readBuffer == null) { 619 readBuffer = new byte[8192]; 620 readBufferRef = new WeakReference<byte[]>(readBuffer); 621 } 622 } 623 624 try { 625 StrictJarFile jarFile = new StrictJarFile(mArchiveSourcePath); 626 627 Certificate[] certs = null; 628 629 if ((flags&PARSE_IS_SYSTEM) != 0) { 630 // If this package comes from the system image, then we 631 // can trust it... we'll just use the AndroidManifest.xml 632 // to retrieve its signatures, not validating all of the 633 // files. 634 ZipEntry jarEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME); 635 certs = loadCertificates(jarFile, jarEntry, readBuffer); 636 if (certs == null) { 637 Slog.e(TAG, "Package " + pkg.packageName 638 + " has no certificates at entry " 639 + jarEntry.getName() + "; ignoring!"); 640 jarFile.close(); 641 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; 642 return false; 643 } 644 if (DEBUG_JAR) { 645 Slog.i(TAG, "File " + mArchiveSourcePath + ": entry=" + jarEntry 646 + " certs=" + (certs != null ? certs.length : 0)); 647 if (certs != null) { 648 final int N = certs.length; 649 for (int i=0; i<N; i++) { 650 Slog.i(TAG, " Public key: " 651 + certs[i].getPublicKey().getEncoded() 652 + " " + certs[i].getPublicKey()); 653 } 654 } 655 } 656 } else { 657 Iterator<ZipEntry> entries = jarFile.iterator(); 658 while (entries.hasNext()) { 659 final ZipEntry je = entries.next(); 660 if (je.isDirectory()) continue; 661 662 final String name = je.getName(); 663 664 if (name.startsWith("META-INF/")) 665 continue; 666 667 if (ANDROID_MANIFEST_FILENAME.equals(name)) { 668 pkg.manifestDigest = 669 ManifestDigest.fromInputStream(jarFile.getInputStream(je)); 670 } 671 672 final Certificate[] localCerts = loadCertificates(jarFile, je, readBuffer); 673 if (DEBUG_JAR) { 674 Slog.i(TAG, "File " + mArchiveSourcePath + " entry " + je.getName() 675 + ": certs=" + certs + " (" 676 + (certs != null ? certs.length : 0) + ")"); 677 } 678 679 if (localCerts == null) { 680 Slog.e(TAG, "Package " + pkg.packageName 681 + " has no certificates at entry " 682 + je.getName() + "; ignoring!"); 683 jarFile.close(); 684 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; 685 return false; 686 } else if (certs == null) { 687 certs = localCerts; 688 } else { 689 // Ensure all certificates match. 690 for (int i=0; i<certs.length; i++) { 691 boolean found = false; 692 for (int j=0; j<localCerts.length; j++) { 693 if (certs[i] != null && 694 certs[i].equals(localCerts[j])) { 695 found = true; 696 break; 697 } 698 } 699 if (!found || certs.length != localCerts.length) { 700 Slog.e(TAG, "Package " + pkg.packageName 701 + " has mismatched certificates at entry " 702 + je.getName() + "; ignoring!"); 703 jarFile.close(); 704 mParseError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; 705 return false; 706 } 707 } 708 } 709 } 710 } 711 jarFile.close(); 712 713 synchronized (mSync) { 714 mReadBuffer = readBufferRef; 715 } 716 717 if (certs != null && certs.length > 0) { 718 final int N = certs.length; 719 pkg.mSignatures = new Signature[certs.length]; 720 for (int i=0; i<N; i++) { 721 pkg.mSignatures[i] = new Signature( 722 certs[i].getEncoded()); 723 } 724 } else { 725 Slog.e(TAG, "Package " + pkg.packageName 726 + " has no certificates; ignoring!"); 727 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; 728 return false; 729 } 730 731 // Add the signing KeySet to the system 732 pkg.mSigningKeys = new HashSet<PublicKey>(); 733 for (int i=0; i < certs.length; i++) { 734 pkg.mSigningKeys.add(certs[i].getPublicKey()); 735 } 736 737 } catch (CertificateEncodingException e) { 738 Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e); 739 mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; 740 return false; 741 } catch (IOException e) { 742 Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e); 743 mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; 744 return false; 745 } catch (SecurityException e) { 746 Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e); 747 mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; 748 return false; 749 } catch (RuntimeException e) { 750 Slog.w(TAG, "Exception reading " + mArchiveSourcePath, e); 751 mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; 752 return false; 753 } 754 755 return true; 756 } 757 758 /* 759 * Utility method that retrieves just the package name and install 760 * location from the apk location at the given file path. 761 * @param packageFilePath file location of the apk 762 * @param flags Special parse flags 763 * @return PackageLite object with package information or null on failure. 764 */ 765 public static PackageLite parsePackageLite(String packageFilePath, int flags) { 766 AssetManager assmgr = null; 767 final XmlResourceParser parser; 768 final Resources res; 769 try { 770 assmgr = new AssetManager(); 771 assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 772 Build.VERSION.RESOURCES_SDK_INT); 773 774 int cookie = assmgr.addAssetPath(packageFilePath); 775 if (cookie == 0) { 776 return null; 777 } 778 779 final DisplayMetrics metrics = new DisplayMetrics(); 780 metrics.setToDefaults(); 781 res = new Resources(assmgr, metrics, null); 782 parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 783 } catch (Exception e) { 784 if (assmgr != null) assmgr.close(); 785 Slog.w(TAG, "Unable to read AndroidManifest.xml of " 786 + packageFilePath, e); 787 return null; 788 } 789 790 final AttributeSet attrs = parser; 791 final String errors[] = new String[1]; 792 PackageLite packageLite = null; 793 try { 794 packageLite = parsePackageLite(res, parser, attrs, flags, errors); 795 } catch (IOException e) { 796 Slog.w(TAG, packageFilePath, e); 797 } catch (XmlPullParserException e) { 798 Slog.w(TAG, packageFilePath, e); 799 } finally { 800 if (parser != null) parser.close(); 801 if (assmgr != null) assmgr.close(); 802 } 803 if (packageLite == null) { 804 Slog.e(TAG, "parsePackageLite error: " + errors[0]); 805 return null; 806 } 807 return packageLite; 808 } 809 810 private static String validateName(String name, boolean requiresSeparator) { 811 final int N = name.length(); 812 boolean hasSep = false; 813 boolean front = true; 814 for (int i=0; i<N; i++) { 815 final char c = name.charAt(i); 816 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { 817 front = false; 818 continue; 819 } 820 if (!front) { 821 if ((c >= '0' && c <= '9') || c == '_') { 822 continue; 823 } 824 } 825 if (c == '.') { 826 hasSep = true; 827 front = true; 828 continue; 829 } 830 return "bad character '" + c + "'"; 831 } 832 return hasSep || !requiresSeparator 833 ? null : "must have at least one '.' separator"; 834 } 835 836 private static String parsePackageName(XmlPullParser parser, 837 AttributeSet attrs, int flags, String[] outError) 838 throws IOException, XmlPullParserException { 839 840 int type; 841 while ((type = parser.next()) != XmlPullParser.START_TAG 842 && type != XmlPullParser.END_DOCUMENT) { 843 ; 844 } 845 846 if (type != XmlPullParser.START_TAG) { 847 outError[0] = "No start tag found"; 848 return null; 849 } 850 if (DEBUG_PARSER) 851 Slog.v(TAG, "Root element name: '" + parser.getName() + "'"); 852 if (!parser.getName().equals("manifest")) { 853 outError[0] = "No <manifest> tag"; 854 return null; 855 } 856 String pkgName = attrs.getAttributeValue(null, "package"); 857 if (pkgName == null || pkgName.length() == 0) { 858 outError[0] = "<manifest> does not specify package"; 859 return null; 860 } 861 String nameError = validateName(pkgName, true); 862 if (nameError != null && !"android".equals(pkgName)) { 863 outError[0] = "<manifest> specifies bad package name \"" 864 + pkgName + "\": " + nameError; 865 return null; 866 } 867 868 return pkgName.intern(); 869 } 870 871 private static PackageLite parsePackageLite(Resources res, XmlPullParser parser, 872 AttributeSet attrs, int flags, String[] outError) throws IOException, 873 XmlPullParserException { 874 875 int type; 876 while ((type = parser.next()) != XmlPullParser.START_TAG 877 && type != XmlPullParser.END_DOCUMENT) { 878 ; 879 } 880 881 if (type != XmlPullParser.START_TAG) { 882 outError[0] = "No start tag found"; 883 return null; 884 } 885 if (DEBUG_PARSER) 886 Slog.v(TAG, "Root element name: '" + parser.getName() + "'"); 887 if (!parser.getName().equals("manifest")) { 888 outError[0] = "No <manifest> tag"; 889 return null; 890 } 891 String pkgName = attrs.getAttributeValue(null, "package"); 892 if (pkgName == null || pkgName.length() == 0) { 893 outError[0] = "<manifest> does not specify package"; 894 return null; 895 } 896 String nameError = validateName(pkgName, true); 897 if (nameError != null && !"android".equals(pkgName)) { 898 outError[0] = "<manifest> specifies bad package name \"" 899 + pkgName + "\": " + nameError; 900 return null; 901 } 902 int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; 903 int versionCode = 0; 904 int numFound = 0; 905 for (int i = 0; i < attrs.getAttributeCount(); i++) { 906 String attr = attrs.getAttributeName(i); 907 if (attr.equals("installLocation")) { 908 installLocation = attrs.getAttributeIntValue(i, 909 PARSE_DEFAULT_INSTALL_LOCATION); 910 numFound++; 911 } else if (attr.equals("versionCode")) { 912 versionCode = attrs.getAttributeIntValue(i, 0); 913 numFound++; 914 } 915 if (numFound >= 2) { 916 break; 917 } 918 } 919 920 // Only search the tree when the tag is directly below <manifest> 921 final int searchDepth = parser.getDepth() + 1; 922 923 final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>(); 924 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 925 && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) { 926 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 927 continue; 928 } 929 930 if (parser.getDepth() == searchDepth && "package-verifier".equals(parser.getName())) { 931 final VerifierInfo verifier = parseVerifier(res, parser, attrs, flags, outError); 932 if (verifier != null) { 933 verifiers.add(verifier); 934 } 935 } 936 } 937 938 return new PackageLite(pkgName.intern(), versionCode, installLocation, verifiers); 939 } 940 941 /** 942 * Temporary. 943 */ 944 static public Signature stringToSignature(String str) { 945 final int N = str.length(); 946 byte[] sig = new byte[N]; 947 for (int i=0; i<N; i++) { 948 sig[i] = (byte)str.charAt(i); 949 } 950 return new Signature(sig); 951 } 952 953 private Package parsePackage( 954 Resources res, XmlResourceParser parser, int flags, String[] outError) 955 throws XmlPullParserException, IOException { 956 AttributeSet attrs = parser; 957 958 mParseInstrumentationArgs = null; 959 mParseActivityArgs = null; 960 mParseServiceArgs = null; 961 mParseProviderArgs = null; 962 963 String pkgName = parsePackageName(parser, attrs, flags, outError); 964 if (pkgName == null) { 965 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 966 return null; 967 } 968 int type; 969 970 if (mOnlyCoreApps) { 971 boolean core = attrs.getAttributeBooleanValue(null, "coreApp", false); 972 if (!core) { 973 mParseError = PackageManager.INSTALL_SUCCEEDED; 974 return null; 975 } 976 } 977 978 final Package pkg = new Package(pkgName); 979 boolean foundApp = false; 980 981 TypedArray sa = res.obtainAttributes(attrs, 982 com.android.internal.R.styleable.AndroidManifest); 983 pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger( 984 com.android.internal.R.styleable.AndroidManifest_versionCode, 0); 985 pkg.mVersionName = sa.getNonConfigurationString( 986 com.android.internal.R.styleable.AndroidManifest_versionName, 0); 987 if (pkg.mVersionName != null) { 988 pkg.mVersionName = pkg.mVersionName.intern(); 989 } 990 String str = sa.getNonConfigurationString( 991 com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); 992 if (str != null && str.length() > 0) { 993 String nameError = validateName(str, true); 994 if (nameError != null && !"android".equals(pkgName)) { 995 outError[0] = "<manifest> specifies bad sharedUserId name \"" 996 + str + "\": " + nameError; 997 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; 998 return null; 999 } 1000 pkg.mSharedUserId = str.intern(); 1001 pkg.mSharedUserLabel = sa.getResourceId( 1002 com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0); 1003 } 1004 sa.recycle(); 1005 1006 pkg.installLocation = sa.getInteger( 1007 com.android.internal.R.styleable.AndroidManifest_installLocation, 1008 PARSE_DEFAULT_INSTALL_LOCATION); 1009 pkg.applicationInfo.installLocation = pkg.installLocation; 1010 1011 /* Set the global "forward lock" flag */ 1012 if ((flags & PARSE_FORWARD_LOCK) != 0) { 1013 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK; 1014 } 1015 1016 /* Set the global "on SD card" flag */ 1017 if ((flags & PARSE_ON_SDCARD) != 0) { 1018 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; 1019 } 1020 1021 // Resource boolean are -1, so 1 means we don't know the value. 1022 int supportsSmallScreens = 1; 1023 int supportsNormalScreens = 1; 1024 int supportsLargeScreens = 1; 1025 int supportsXLargeScreens = 1; 1026 int resizeable = 1; 1027 int anyDensity = 1; 1028 1029 int outerDepth = parser.getDepth(); 1030 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1031 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1032 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1033 continue; 1034 } 1035 1036 String tagName = parser.getName(); 1037 if (tagName.equals("application")) { 1038 if (foundApp) { 1039 if (RIGID_PARSER) { 1040 outError[0] = "<manifest> has more than one <application>"; 1041 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1042 return null; 1043 } else { 1044 Slog.w(TAG, "<manifest> has more than one <application>"); 1045 XmlUtils.skipCurrentTag(parser); 1046 continue; 1047 } 1048 } 1049 1050 foundApp = true; 1051 if (!parseApplication(pkg, res, parser, attrs, flags, outError)) { 1052 return null; 1053 } 1054 } else if (tagName.equals("keys")) { 1055 if (!parseKeys(pkg, res, parser, attrs, outError)) { 1056 return null; 1057 } 1058 } else if (tagName.equals("permission-group")) { 1059 if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) { 1060 return null; 1061 } 1062 } else if (tagName.equals("permission")) { 1063 if (parsePermission(pkg, res, parser, attrs, outError) == null) { 1064 return null; 1065 } 1066 } else if (tagName.equals("permission-tree")) { 1067 if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) { 1068 return null; 1069 } 1070 } else if (tagName.equals("uses-permission")) { 1071 if (!parseUsesPermission(pkg, res, parser, attrs, outError)) { 1072 return null; 1073 } 1074 1075 } else if (tagName.equals("uses-configuration")) { 1076 ConfigurationInfo cPref = new ConfigurationInfo(); 1077 sa = res.obtainAttributes(attrs, 1078 com.android.internal.R.styleable.AndroidManifestUsesConfiguration); 1079 cPref.reqTouchScreen = sa.getInt( 1080 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, 1081 Configuration.TOUCHSCREEN_UNDEFINED); 1082 cPref.reqKeyboardType = sa.getInt( 1083 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, 1084 Configuration.KEYBOARD_UNDEFINED); 1085 if (sa.getBoolean( 1086 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, 1087 false)) { 1088 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; 1089 } 1090 cPref.reqNavigation = sa.getInt( 1091 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation, 1092 Configuration.NAVIGATION_UNDEFINED); 1093 if (sa.getBoolean( 1094 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, 1095 false)) { 1096 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; 1097 } 1098 sa.recycle(); 1099 pkg.configPreferences.add(cPref); 1100 1101 XmlUtils.skipCurrentTag(parser); 1102 1103 } else if (tagName.equals("uses-feature")) { 1104 FeatureInfo fi = new FeatureInfo(); 1105 sa = res.obtainAttributes(attrs, 1106 com.android.internal.R.styleable.AndroidManifestUsesFeature); 1107 // Note: don't allow this value to be a reference to a resource 1108 // that may change. 1109 fi.name = sa.getNonResourceString( 1110 com.android.internal.R.styleable.AndroidManifestUsesFeature_name); 1111 if (fi.name == null) { 1112 fi.reqGlEsVersion = sa.getInt( 1113 com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion, 1114 FeatureInfo.GL_ES_VERSION_UNDEFINED); 1115 } 1116 if (sa.getBoolean( 1117 com.android.internal.R.styleable.AndroidManifestUsesFeature_required, 1118 true)) { 1119 fi.flags |= FeatureInfo.FLAG_REQUIRED; 1120 } 1121 sa.recycle(); 1122 if (pkg.reqFeatures == null) { 1123 pkg.reqFeatures = new ArrayList<FeatureInfo>(); 1124 } 1125 pkg.reqFeatures.add(fi); 1126 1127 if (fi.name == null) { 1128 ConfigurationInfo cPref = new ConfigurationInfo(); 1129 cPref.reqGlEsVersion = fi.reqGlEsVersion; 1130 pkg.configPreferences.add(cPref); 1131 } 1132 1133 XmlUtils.skipCurrentTag(parser); 1134 1135 } else if (tagName.equals("uses-sdk")) { 1136 if (SDK_VERSION > 0) { 1137 sa = res.obtainAttributes(attrs, 1138 com.android.internal.R.styleable.AndroidManifestUsesSdk); 1139 1140 int minVers = 0; 1141 String minCode = null; 1142 int targetVers = 0; 1143 String targetCode = null; 1144 1145 TypedValue val = sa.peekValue( 1146 com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); 1147 if (val != null) { 1148 if (val.type == TypedValue.TYPE_STRING && val.string != null) { 1149 targetCode = minCode = val.string.toString(); 1150 } else { 1151 // If it's not a string, it's an integer. 1152 targetVers = minVers = val.data; 1153 } 1154 } 1155 1156 val = sa.peekValue( 1157 com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); 1158 if (val != null) { 1159 if (val.type == TypedValue.TYPE_STRING && val.string != null) { 1160 targetCode = minCode = val.string.toString(); 1161 } else { 1162 // If it's not a string, it's an integer. 1163 targetVers = val.data; 1164 } 1165 } 1166 1167 sa.recycle(); 1168 1169 if (minCode != null) { 1170 if (!minCode.equals(SDK_CODENAME)) { 1171 if (SDK_CODENAME != null) { 1172 outError[0] = "Requires development platform " + minCode 1173 + " (current platform is " + SDK_CODENAME + ")"; 1174 } else { 1175 outError[0] = "Requires development platform " + minCode 1176 + " but this is a release platform."; 1177 } 1178 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1179 return null; 1180 } 1181 } else if (minVers > SDK_VERSION) { 1182 outError[0] = "Requires newer sdk version #" + minVers 1183 + " (current version is #" + SDK_VERSION + ")"; 1184 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1185 return null; 1186 } 1187 1188 if (targetCode != null) { 1189 if (!targetCode.equals(SDK_CODENAME)) { 1190 if (SDK_CODENAME != null) { 1191 outError[0] = "Requires development platform " + targetCode 1192 + " (current platform is " + SDK_CODENAME + ")"; 1193 } else { 1194 outError[0] = "Requires development platform " + targetCode 1195 + " but this is a release platform."; 1196 } 1197 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1198 return null; 1199 } 1200 // If the code matches, it definitely targets this SDK. 1201 pkg.applicationInfo.targetSdkVersion 1202 = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; 1203 } else { 1204 pkg.applicationInfo.targetSdkVersion = targetVers; 1205 } 1206 } 1207 1208 XmlUtils.skipCurrentTag(parser); 1209 1210 } else if (tagName.equals("supports-screens")) { 1211 sa = res.obtainAttributes(attrs, 1212 com.android.internal.R.styleable.AndroidManifestSupportsScreens); 1213 1214 pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger( 1215 com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, 1216 0); 1217 pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger( 1218 com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, 1219 0); 1220 pkg.applicationInfo.largestWidthLimitDp = sa.getInteger( 1221 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, 1222 0); 1223 1224 // This is a trick to get a boolean and still able to detect 1225 // if a value was actually set. 1226 supportsSmallScreens = sa.getInteger( 1227 com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens, 1228 supportsSmallScreens); 1229 supportsNormalScreens = sa.getInteger( 1230 com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens, 1231 supportsNormalScreens); 1232 supportsLargeScreens = sa.getInteger( 1233 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens, 1234 supportsLargeScreens); 1235 supportsXLargeScreens = sa.getInteger( 1236 com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1237 supportsXLargeScreens); 1238 resizeable = sa.getInteger( 1239 com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable, 1240 resizeable); 1241 anyDensity = sa.getInteger( 1242 com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity, 1243 anyDensity); 1244 1245 sa.recycle(); 1246 1247 XmlUtils.skipCurrentTag(parser); 1248 1249 } else if (tagName.equals("protected-broadcast")) { 1250 sa = res.obtainAttributes(attrs, 1251 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast); 1252 1253 // Note: don't allow this value to be a reference to a resource 1254 // that may change. 1255 String name = sa.getNonResourceString( 1256 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name); 1257 1258 sa.recycle(); 1259 1260 if (name != null && (flags&PARSE_IS_SYSTEM) != 0) { 1261 if (pkg.protectedBroadcasts == null) { 1262 pkg.protectedBroadcasts = new ArrayList<String>(); 1263 } 1264 if (!pkg.protectedBroadcasts.contains(name)) { 1265 pkg.protectedBroadcasts.add(name.intern()); 1266 } 1267 } 1268 1269 XmlUtils.skipCurrentTag(parser); 1270 1271 } else if (tagName.equals("instrumentation")) { 1272 if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) { 1273 return null; 1274 } 1275 1276 } else if (tagName.equals("original-package")) { 1277 sa = res.obtainAttributes(attrs, 1278 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 1279 1280 String orig =sa.getNonConfigurationString( 1281 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 1282 if (!pkg.packageName.equals(orig)) { 1283 if (pkg.mOriginalPackages == null) { 1284 pkg.mOriginalPackages = new ArrayList<String>(); 1285 pkg.mRealPackage = pkg.packageName; 1286 } 1287 pkg.mOriginalPackages.add(orig); 1288 } 1289 1290 sa.recycle(); 1291 1292 XmlUtils.skipCurrentTag(parser); 1293 1294 } else if (tagName.equals("adopt-permissions")) { 1295 sa = res.obtainAttributes(attrs, 1296 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 1297 1298 String name = sa.getNonConfigurationString( 1299 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 1300 1301 sa.recycle(); 1302 1303 if (name != null) { 1304 if (pkg.mAdoptPermissions == null) { 1305 pkg.mAdoptPermissions = new ArrayList<String>(); 1306 } 1307 pkg.mAdoptPermissions.add(name); 1308 } 1309 1310 XmlUtils.skipCurrentTag(parser); 1311 1312 } else if (tagName.equals("uses-gl-texture")) { 1313 // Just skip this tag 1314 XmlUtils.skipCurrentTag(parser); 1315 continue; 1316 1317 } else if (tagName.equals("compatible-screens")) { 1318 // Just skip this tag 1319 XmlUtils.skipCurrentTag(parser); 1320 continue; 1321 } else if (tagName.equals("supports-input")) { 1322 XmlUtils.skipCurrentTag(parser); 1323 continue; 1324 1325 } else if (tagName.equals("eat-comment")) { 1326 // Just skip this tag 1327 XmlUtils.skipCurrentTag(parser); 1328 continue; 1329 1330 } else if (RIGID_PARSER) { 1331 outError[0] = "Bad element under <manifest>: " 1332 + parser.getName(); 1333 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1334 return null; 1335 1336 } else { 1337 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() 1338 + " at " + mArchiveSourcePath + " " 1339 + parser.getPositionDescription()); 1340 XmlUtils.skipCurrentTag(parser); 1341 continue; 1342 } 1343 } 1344 1345 if (!foundApp && pkg.instrumentation.size() == 0) { 1346 outError[0] = "<manifest> does not contain an <application> or <instrumentation>"; 1347 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; 1348 } 1349 1350 final int NP = PackageParser.NEW_PERMISSIONS.length; 1351 StringBuilder implicitPerms = null; 1352 for (int ip=0; ip<NP; ip++) { 1353 final PackageParser.NewPermissionInfo npi 1354 = PackageParser.NEW_PERMISSIONS[ip]; 1355 if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) { 1356 break; 1357 } 1358 if (!pkg.requestedPermissions.contains(npi.name)) { 1359 if (implicitPerms == null) { 1360 implicitPerms = new StringBuilder(128); 1361 implicitPerms.append(pkg.packageName); 1362 implicitPerms.append(": compat added "); 1363 } else { 1364 implicitPerms.append(' '); 1365 } 1366 implicitPerms.append(npi.name); 1367 pkg.requestedPermissions.add(npi.name); 1368 pkg.requestedPermissionsRequired.add(Boolean.TRUE); 1369 } 1370 } 1371 if (implicitPerms != null) { 1372 Slog.i(TAG, implicitPerms.toString()); 1373 } 1374 1375 final int NS = PackageParser.SPLIT_PERMISSIONS.length; 1376 for (int is=0; is<NS; is++) { 1377 final PackageParser.SplitPermissionInfo spi 1378 = PackageParser.SPLIT_PERMISSIONS[is]; 1379 if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk 1380 || !pkg.requestedPermissions.contains(spi.rootPerm)) { 1381 continue; 1382 } 1383 for (int in=0; in<spi.newPerms.length; in++) { 1384 final String perm = spi.newPerms[in]; 1385 if (!pkg.requestedPermissions.contains(perm)) { 1386 pkg.requestedPermissions.add(perm); 1387 pkg.requestedPermissionsRequired.add(Boolean.TRUE); 1388 } 1389 } 1390 } 1391 1392 if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 1393 && pkg.applicationInfo.targetSdkVersion 1394 >= android.os.Build.VERSION_CODES.DONUT)) { 1395 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; 1396 } 1397 if (supportsNormalScreens != 0) { 1398 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; 1399 } 1400 if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 1401 && pkg.applicationInfo.targetSdkVersion 1402 >= android.os.Build.VERSION_CODES.DONUT)) { 1403 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; 1404 } 1405 if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 1406 && pkg.applicationInfo.targetSdkVersion 1407 >= android.os.Build.VERSION_CODES.GINGERBREAD)) { 1408 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; 1409 } 1410 if (resizeable < 0 || (resizeable > 0 1411 && pkg.applicationInfo.targetSdkVersion 1412 >= android.os.Build.VERSION_CODES.DONUT)) { 1413 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; 1414 } 1415 if (anyDensity < 0 || (anyDensity > 0 1416 && pkg.applicationInfo.targetSdkVersion 1417 >= android.os.Build.VERSION_CODES.DONUT)) { 1418 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; 1419 } 1420 1421 /* 1422 * b/8528162: Ignore the <uses-permission android:required> attribute if 1423 * targetSdkVersion < JELLY_BEAN_MR2. There are lots of apps in the wild 1424 * which are improperly using this attribute, even though it never worked. 1425 */ 1426 if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) { 1427 for (int i = 0; i < pkg.requestedPermissionsRequired.size(); i++) { 1428 pkg.requestedPermissionsRequired.set(i, Boolean.TRUE); 1429 } 1430 } 1431 1432 return pkg; 1433 } 1434 1435 private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser, 1436 AttributeSet attrs, String[] outError) 1437 throws XmlPullParserException, IOException { 1438 TypedArray sa = res.obtainAttributes(attrs, 1439 com.android.internal.R.styleable.AndroidManifestUsesPermission); 1440 1441 // Note: don't allow this value to be a reference to a resource 1442 // that may change. 1443 String name = sa.getNonResourceString( 1444 com.android.internal.R.styleable.AndroidManifestUsesPermission_name); 1445/* 1446 boolean required = sa.getBoolean( 1447 com.android.internal.R.styleable.AndroidManifestUsesPermission_required, true); 1448*/ 1449 boolean required = true; // Optional <uses-permission> not supported 1450 1451 int maxSdkVersion = 0; 1452 TypedValue val = sa.peekValue( 1453 com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion); 1454 if (val != null) { 1455 if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) { 1456 maxSdkVersion = val.data; 1457 } 1458 } 1459 1460 sa.recycle(); 1461 1462 if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) { 1463 if (name != null) { 1464 int index = pkg.requestedPermissions.indexOf(name); 1465 if (index == -1) { 1466 pkg.requestedPermissions.add(name.intern()); 1467 pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE); 1468 } else { 1469 if (pkg.requestedPermissionsRequired.get(index) != required) { 1470 outError[0] = "conflicting <uses-permission> entries"; 1471 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1472 return false; 1473 } 1474 } 1475 } 1476 } 1477 1478 XmlUtils.skipCurrentTag(parser); 1479 return true; 1480 } 1481 1482 private static String buildClassName(String pkg, CharSequence clsSeq, 1483 String[] outError) { 1484 if (clsSeq == null || clsSeq.length() <= 0) { 1485 outError[0] = "Empty class name in package " + pkg; 1486 return null; 1487 } 1488 String cls = clsSeq.toString(); 1489 char c = cls.charAt(0); 1490 if (c == '.') { 1491 return (pkg + cls).intern(); 1492 } 1493 if (cls.indexOf('.') < 0) { 1494 StringBuilder b = new StringBuilder(pkg); 1495 b.append('.'); 1496 b.append(cls); 1497 return b.toString().intern(); 1498 } 1499 if (c >= 'a' && c <= 'z') { 1500 return cls.intern(); 1501 } 1502 outError[0] = "Bad class name " + cls + " in package " + pkg; 1503 return null; 1504 } 1505 1506 private static String buildCompoundName(String pkg, 1507 CharSequence procSeq, String type, String[] outError) { 1508 String proc = procSeq.toString(); 1509 char c = proc.charAt(0); 1510 if (pkg != null && c == ':') { 1511 if (proc.length() < 2) { 1512 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg 1513 + ": must be at least two characters"; 1514 return null; 1515 } 1516 String subName = proc.substring(1); 1517 String nameError = validateName(subName, false); 1518 if (nameError != null) { 1519 outError[0] = "Invalid " + type + " name " + proc + " in package " 1520 + pkg + ": " + nameError; 1521 return null; 1522 } 1523 return (pkg + proc).intern(); 1524 } 1525 String nameError = validateName(proc, true); 1526 if (nameError != null && !"system".equals(proc)) { 1527 outError[0] = "Invalid " + type + " name " + proc + " in package " 1528 + pkg + ": " + nameError; 1529 return null; 1530 } 1531 return proc.intern(); 1532 } 1533 1534 private static String buildProcessName(String pkg, String defProc, 1535 CharSequence procSeq, int flags, String[] separateProcesses, 1536 String[] outError) { 1537 if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) { 1538 return defProc != null ? defProc : pkg; 1539 } 1540 if (separateProcesses != null) { 1541 for (int i=separateProcesses.length-1; i>=0; i--) { 1542 String sp = separateProcesses[i]; 1543 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) { 1544 return pkg; 1545 } 1546 } 1547 } 1548 if (procSeq == null || procSeq.length() <= 0) { 1549 return defProc; 1550 } 1551 return buildCompoundName(pkg, procSeq, "process", outError); 1552 } 1553 1554 private static String buildTaskAffinityName(String pkg, String defProc, 1555 CharSequence procSeq, String[] outError) { 1556 if (procSeq == null) { 1557 return defProc; 1558 } 1559 if (procSeq.length() <= 0) { 1560 return null; 1561 } 1562 return buildCompoundName(pkg, procSeq, "taskAffinity", outError); 1563 } 1564 1565 private boolean parseKeys(Package owner, Resources res, 1566 XmlPullParser parser, AttributeSet attrs, String[] outError) 1567 throws XmlPullParserException, IOException { 1568 // we've encountered the 'keys' tag 1569 // all the keys and keysets that we want must be defined here 1570 // so we're going to iterate over the parser and pull out the things we want 1571 int outerDepth = parser.getDepth(); 1572 1573 int type; 1574 PublicKey currentKey = null; 1575 int currentKeyDepth = -1; 1576 Map<PublicKey, Set<String>> definedKeySets = new HashMap<PublicKey, Set<String>>(); 1577 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1578 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1579 if (type == XmlPullParser.END_TAG) { 1580 if (parser.getDepth() == currentKeyDepth) { 1581 currentKey = null; 1582 currentKeyDepth = -1; 1583 } 1584 continue; 1585 } 1586 String tagname = parser.getName(); 1587 if (tagname.equals("publicKey")) { 1588 final TypedArray sa = res.obtainAttributes(attrs, 1589 com.android.internal.R.styleable.PublicKey); 1590 final String encodedKey = sa.getNonResourceString( 1591 com.android.internal.R.styleable.PublicKey_value); 1592 currentKey = parsePublicKey(encodedKey); 1593 if (currentKey == null) { 1594 Slog.w(TAG, "No valid key in 'publicKey' tag at " 1595 + parser.getPositionDescription()); 1596 sa.recycle(); 1597 continue; 1598 } 1599 currentKeyDepth = parser.getDepth(); 1600 definedKeySets.put(currentKey, new HashSet<String>()); 1601 sa.recycle(); 1602 } else if (tagname.equals("keyset")) { 1603 if (currentKey == null) { 1604 Slog.i(TAG, "'keyset' not in 'publicKey' tag at " 1605 + parser.getPositionDescription()); 1606 continue; 1607 } 1608 final TypedArray sa = res.obtainAttributes(attrs, 1609 com.android.internal.R.styleable.KeySet); 1610 final String name = sa.getNonResourceString( 1611 com.android.internal.R.styleable.KeySet_name); 1612 definedKeySets.get(currentKey).add(name); 1613 sa.recycle(); 1614 } else if (RIGID_PARSER) { 1615 Slog.w(TAG, "Bad element under <keys>: " + parser.getName() 1616 + " at " + mArchiveSourcePath + " " 1617 + parser.getPositionDescription()); 1618 return false; 1619 } else { 1620 Slog.w(TAG, "Unknown element under <keys>: " + parser.getName() 1621 + " at " + mArchiveSourcePath + " " 1622 + parser.getPositionDescription()); 1623 XmlUtils.skipCurrentTag(parser); 1624 continue; 1625 } 1626 } 1627 1628 owner.mKeySetMapping = new HashMap<String, Set<PublicKey>>(); 1629 for (Map.Entry<PublicKey, Set<String>> e : definedKeySets.entrySet()) { 1630 PublicKey key = e.getKey(); 1631 Set<String> keySetNames = e.getValue(); 1632 for (String alias : keySetNames) { 1633 if (owner.mKeySetMapping.containsKey(alias)) { 1634 owner.mKeySetMapping.get(alias).add(key); 1635 } else { 1636 Set<PublicKey> keys = new HashSet<PublicKey>(); 1637 keys.add(key); 1638 owner.mKeySetMapping.put(alias, keys); 1639 } 1640 } 1641 } 1642 1643 return true; 1644 } 1645 1646 private PermissionGroup parsePermissionGroup(Package owner, int flags, Resources res, 1647 XmlPullParser parser, AttributeSet attrs, String[] outError) 1648 throws XmlPullParserException, IOException { 1649 PermissionGroup perm = new PermissionGroup(owner); 1650 1651 TypedArray sa = res.obtainAttributes(attrs, 1652 com.android.internal.R.styleable.AndroidManifestPermissionGroup); 1653 1654 if (!parsePackageItemInfo(owner, perm.info, outError, 1655 "<permission-group>", sa, 1656 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name, 1657 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label, 1658 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon, 1659 com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo)) { 1660 sa.recycle(); 1661 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1662 return null; 1663 } 1664 1665 perm.info.descriptionRes = sa.getResourceId( 1666 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description, 1667 0); 1668 perm.info.flags = sa.getInt( 1669 com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0); 1670 perm.info.priority = sa.getInt( 1671 com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0); 1672 if (perm.info.priority > 0 && (flags&PARSE_IS_SYSTEM) == 0) { 1673 perm.info.priority = 0; 1674 } 1675 1676 sa.recycle(); 1677 1678 if (!parseAllMetaData(res, parser, attrs, "<permission-group>", perm, 1679 outError)) { 1680 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1681 return null; 1682 } 1683 1684 owner.permissionGroups.add(perm); 1685 1686 return perm; 1687 } 1688 1689 private Permission parsePermission(Package owner, Resources res, 1690 XmlPullParser parser, AttributeSet attrs, String[] outError) 1691 throws XmlPullParserException, IOException { 1692 Permission perm = new Permission(owner); 1693 1694 TypedArray sa = res.obtainAttributes(attrs, 1695 com.android.internal.R.styleable.AndroidManifestPermission); 1696 1697 if (!parsePackageItemInfo(owner, perm.info, outError, 1698 "<permission>", sa, 1699 com.android.internal.R.styleable.AndroidManifestPermission_name, 1700 com.android.internal.R.styleable.AndroidManifestPermission_label, 1701 com.android.internal.R.styleable.AndroidManifestPermission_icon, 1702 com.android.internal.R.styleable.AndroidManifestPermission_logo)) { 1703 sa.recycle(); 1704 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1705 return null; 1706 } 1707 1708 // Note: don't allow this value to be a reference to a resource 1709 // that may change. 1710 perm.info.group = sa.getNonResourceString( 1711 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup); 1712 if (perm.info.group != null) { 1713 perm.info.group = perm.info.group.intern(); 1714 } 1715 1716 perm.info.descriptionRes = sa.getResourceId( 1717 com.android.internal.R.styleable.AndroidManifestPermission_description, 1718 0); 1719 1720 perm.info.protectionLevel = sa.getInt( 1721 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel, 1722 PermissionInfo.PROTECTION_NORMAL); 1723 1724 perm.info.flags = sa.getInt( 1725 com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0); 1726 1727 sa.recycle(); 1728 1729 if (perm.info.protectionLevel == -1) { 1730 outError[0] = "<permission> does not specify protectionLevel"; 1731 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1732 return null; 1733 } 1734 1735 perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel); 1736 1737 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) { 1738 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) != 1739 PermissionInfo.PROTECTION_SIGNATURE) { 1740 outError[0] = "<permission> protectionLevel specifies a flag but is " 1741 + "not based on signature type"; 1742 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1743 return null; 1744 } 1745 } 1746 1747 if (!parseAllMetaData(res, parser, attrs, "<permission>", perm, 1748 outError)) { 1749 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1750 return null; 1751 } 1752 1753 owner.permissions.add(perm); 1754 1755 return perm; 1756 } 1757 1758 private Permission parsePermissionTree(Package owner, Resources res, 1759 XmlPullParser parser, AttributeSet attrs, String[] outError) 1760 throws XmlPullParserException, IOException { 1761 Permission perm = new Permission(owner); 1762 1763 TypedArray sa = res.obtainAttributes(attrs, 1764 com.android.internal.R.styleable.AndroidManifestPermissionTree); 1765 1766 if (!parsePackageItemInfo(owner, perm.info, outError, 1767 "<permission-tree>", sa, 1768 com.android.internal.R.styleable.AndroidManifestPermissionTree_name, 1769 com.android.internal.R.styleable.AndroidManifestPermissionTree_label, 1770 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon, 1771 com.android.internal.R.styleable.AndroidManifestPermissionTree_logo)) { 1772 sa.recycle(); 1773 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1774 return null; 1775 } 1776 1777 sa.recycle(); 1778 1779 int index = perm.info.name.indexOf('.'); 1780 if (index > 0) { 1781 index = perm.info.name.indexOf('.', index+1); 1782 } 1783 if (index < 0) { 1784 outError[0] = "<permission-tree> name has less than three segments: " 1785 + perm.info.name; 1786 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1787 return null; 1788 } 1789 1790 perm.info.descriptionRes = 0; 1791 perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL; 1792 perm.tree = true; 1793 1794 if (!parseAllMetaData(res, parser, attrs, "<permission-tree>", perm, 1795 outError)) { 1796 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1797 return null; 1798 } 1799 1800 owner.permissions.add(perm); 1801 1802 return perm; 1803 } 1804 1805 private Instrumentation parseInstrumentation(Package owner, Resources res, 1806 XmlPullParser parser, AttributeSet attrs, String[] outError) 1807 throws XmlPullParserException, IOException { 1808 TypedArray sa = res.obtainAttributes(attrs, 1809 com.android.internal.R.styleable.AndroidManifestInstrumentation); 1810 1811 if (mParseInstrumentationArgs == null) { 1812 mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError, 1813 com.android.internal.R.styleable.AndroidManifestInstrumentation_name, 1814 com.android.internal.R.styleable.AndroidManifestInstrumentation_label, 1815 com.android.internal.R.styleable.AndroidManifestInstrumentation_icon, 1816 com.android.internal.R.styleable.AndroidManifestInstrumentation_logo); 1817 mParseInstrumentationArgs.tag = "<instrumentation>"; 1818 } 1819 1820 mParseInstrumentationArgs.sa = sa; 1821 1822 Instrumentation a = new Instrumentation(mParseInstrumentationArgs, 1823 new InstrumentationInfo()); 1824 if (outError[0] != null) { 1825 sa.recycle(); 1826 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1827 return null; 1828 } 1829 1830 String str; 1831 // Note: don't allow this value to be a reference to a resource 1832 // that may change. 1833 str = sa.getNonResourceString( 1834 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage); 1835 a.info.targetPackage = str != null ? str.intern() : null; 1836 1837 a.info.handleProfiling = sa.getBoolean( 1838 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling, 1839 false); 1840 1841 a.info.functionalTest = sa.getBoolean( 1842 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest, 1843 false); 1844 1845 sa.recycle(); 1846 1847 if (a.info.targetPackage == null) { 1848 outError[0] = "<instrumentation> does not specify targetPackage"; 1849 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1850 return null; 1851 } 1852 1853 if (!parseAllMetaData(res, parser, attrs, "<instrumentation>", a, 1854 outError)) { 1855 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1856 return null; 1857 } 1858 1859 owner.instrumentation.add(a); 1860 1861 return a; 1862 } 1863 1864 private boolean parseApplication(Package owner, Resources res, 1865 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 1866 throws XmlPullParserException, IOException { 1867 final ApplicationInfo ai = owner.applicationInfo; 1868 final String pkgName = owner.applicationInfo.packageName; 1869 1870 TypedArray sa = res.obtainAttributes(attrs, 1871 com.android.internal.R.styleable.AndroidManifestApplication); 1872 1873 String name = sa.getNonConfigurationString( 1874 com.android.internal.R.styleable.AndroidManifestApplication_name, 0); 1875 if (name != null) { 1876 ai.className = buildClassName(pkgName, name, outError); 1877 if (ai.className == null) { 1878 sa.recycle(); 1879 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1880 return false; 1881 } 1882 } 1883 1884 String manageSpaceActivity = sa.getNonConfigurationString( 1885 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity, 1886 Configuration.NATIVE_CONFIG_VERSION); 1887 if (manageSpaceActivity != null) { 1888 ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity, 1889 outError); 1890 } 1891 1892 boolean allowBackup = sa.getBoolean( 1893 com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true); 1894 if (allowBackup) { 1895 ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; 1896 1897 // backupAgent, killAfterRestore, and restoreAnyVersion are only relevant 1898 // if backup is possible for the given application. 1899 String backupAgent = sa.getNonConfigurationString( 1900 com.android.internal.R.styleable.AndroidManifestApplication_backupAgent, 1901 Configuration.NATIVE_CONFIG_VERSION); 1902 if (backupAgent != null) { 1903 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError); 1904 if (DEBUG_BACKUP) { 1905 Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName 1906 + " from " + pkgName + "+" + backupAgent); 1907 } 1908 1909 if (sa.getBoolean( 1910 com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore, 1911 true)) { 1912 ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE; 1913 } 1914 if (sa.getBoolean( 1915 com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion, 1916 false)) { 1917 ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION; 1918 } 1919 } 1920 } 1921 1922 TypedValue v = sa.peekValue( 1923 com.android.internal.R.styleable.AndroidManifestApplication_label); 1924 if (v != null && (ai.labelRes=v.resourceId) == 0) { 1925 ai.nonLocalizedLabel = v.coerceToString(); 1926 } 1927 1928 ai.icon = sa.getResourceId( 1929 com.android.internal.R.styleable.AndroidManifestApplication_icon, 0); 1930 ai.logo = sa.getResourceId( 1931 com.android.internal.R.styleable.AndroidManifestApplication_logo, 0); 1932 ai.theme = sa.getResourceId( 1933 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); 1934 ai.descriptionRes = sa.getResourceId( 1935 com.android.internal.R.styleable.AndroidManifestApplication_description, 0); 1936 1937 if ((flags&PARSE_IS_SYSTEM) != 0) { 1938 if (sa.getBoolean( 1939 com.android.internal.R.styleable.AndroidManifestApplication_persistent, 1940 false)) { 1941 ai.flags |= ApplicationInfo.FLAG_PERSISTENT; 1942 } 1943 } 1944 1945 if (sa.getBoolean( 1946 com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers, 1947 false)) { 1948 owner.mRequiredForAllUsers = true; 1949 } 1950 1951 String restrictedAccountType = sa.getString(com.android.internal.R.styleable 1952 .AndroidManifestApplication_restrictedAccountType); 1953 if (restrictedAccountType != null && restrictedAccountType.length() > 0) { 1954 owner.mRestrictedAccountType = restrictedAccountType; 1955 } 1956 1957 String requiredAccountType = sa.getString(com.android.internal.R.styleable 1958 .AndroidManifestApplication_requiredAccountType); 1959 if (requiredAccountType != null && requiredAccountType.length() > 0) { 1960 owner.mRequiredAccountType = requiredAccountType; 1961 } 1962 1963 if (sa.getBoolean( 1964 com.android.internal.R.styleable.AndroidManifestApplication_debuggable, 1965 false)) { 1966 ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE; 1967 } 1968 1969 if (sa.getBoolean( 1970 com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode, 1971 false)) { 1972 ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE; 1973 } 1974 1975 boolean hardwareAccelerated = sa.getBoolean( 1976 com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated, 1977 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH); 1978 1979 if (sa.getBoolean( 1980 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, 1981 true)) { 1982 ai.flags |= ApplicationInfo.FLAG_HAS_CODE; 1983 } 1984 1985 if (sa.getBoolean( 1986 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting, 1987 false)) { 1988 ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; 1989 } 1990 1991 if (sa.getBoolean( 1992 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData, 1993 true)) { 1994 ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; 1995 } 1996 1997 if (sa.getBoolean( 1998 com.android.internal.R.styleable.AndroidManifestApplication_testOnly, 1999 false)) { 2000 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY; 2001 } 2002 2003 if (sa.getBoolean( 2004 com.android.internal.R.styleable.AndroidManifestApplication_largeHeap, 2005 false)) { 2006 ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP; 2007 } 2008 2009 if (sa.getBoolean( 2010 com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl, 2011 false /* default is no RTL support*/)) { 2012 ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL; 2013 } 2014 2015 String str; 2016 str = sa.getNonConfigurationString( 2017 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0); 2018 ai.permission = (str != null && str.length() > 0) ? str.intern() : null; 2019 2020 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 2021 str = sa.getNonConfigurationString( 2022 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, 2023 Configuration.NATIVE_CONFIG_VERSION); 2024 } else { 2025 // Some older apps have been seen to use a resource reference 2026 // here that on older builds was ignored (with a warning). We 2027 // need to continue to do this for them so they don't break. 2028 str = sa.getNonResourceString( 2029 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity); 2030 } 2031 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName, 2032 str, outError); 2033 2034 if (outError[0] == null) { 2035 CharSequence pname; 2036 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 2037 pname = sa.getNonConfigurationString( 2038 com.android.internal.R.styleable.AndroidManifestApplication_process, 2039 Configuration.NATIVE_CONFIG_VERSION); 2040 } else { 2041 // Some older apps have been seen to use a resource reference 2042 // here that on older builds was ignored (with a warning). We 2043 // need to continue to do this for them so they don't break. 2044 pname = sa.getNonResourceString( 2045 com.android.internal.R.styleable.AndroidManifestApplication_process); 2046 } 2047 ai.processName = buildProcessName(ai.packageName, null, pname, 2048 flags, mSeparateProcesses, outError); 2049 2050 ai.enabled = sa.getBoolean( 2051 com.android.internal.R.styleable.AndroidManifestApplication_enabled, true); 2052 2053 if (false) { 2054 if (sa.getBoolean( 2055 com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState, 2056 false)) { 2057 ai.flags |= ApplicationInfo.FLAG_CANT_SAVE_STATE; 2058 2059 // A heavy-weight application can not be in a custom process. 2060 // We can do direct compare because we intern all strings. 2061 if (ai.processName != null && ai.processName != ai.packageName) { 2062 outError[0] = "cantSaveState applications can not use custom processes"; 2063 } 2064 } 2065 } 2066 } 2067 2068 ai.uiOptions = sa.getInt( 2069 com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0); 2070 2071 sa.recycle(); 2072 2073 if (outError[0] != null) { 2074 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2075 return false; 2076 } 2077 2078 final int innerDepth = parser.getDepth(); 2079 2080 int type; 2081 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 2082 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 2083 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2084 continue; 2085 } 2086 2087 String tagName = parser.getName(); 2088 if (tagName.equals("activity")) { 2089 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false, 2090 hardwareAccelerated); 2091 if (a == null) { 2092 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2093 return false; 2094 } 2095 2096 owner.activities.add(a); 2097 2098 } else if (tagName.equals("receiver")) { 2099 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false); 2100 if (a == null) { 2101 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2102 return false; 2103 } 2104 2105 owner.receivers.add(a); 2106 2107 } else if (tagName.equals("service")) { 2108 Service s = parseService(owner, res, parser, attrs, flags, outError); 2109 if (s == null) { 2110 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2111 return false; 2112 } 2113 2114 owner.services.add(s); 2115 2116 } else if (tagName.equals("provider")) { 2117 Provider p = parseProvider(owner, res, parser, attrs, flags, outError); 2118 if (p == null) { 2119 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2120 return false; 2121 } 2122 2123 owner.providers.add(p); 2124 2125 } else if (tagName.equals("activity-alias")) { 2126 Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError); 2127 if (a == null) { 2128 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2129 return false; 2130 } 2131 2132 owner.activities.add(a); 2133 2134 } else if (parser.getName().equals("meta-data")) { 2135 // note: application meta-data is stored off to the side, so it can 2136 // remain null in the primary copy (we like to avoid extra copies because 2137 // it can be large) 2138 if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData, 2139 outError)) == null) { 2140 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2141 return false; 2142 } 2143 2144 } else if (tagName.equals("library")) { 2145 sa = res.obtainAttributes(attrs, 2146 com.android.internal.R.styleable.AndroidManifestLibrary); 2147 2148 // Note: don't allow this value to be a reference to a resource 2149 // that may change. 2150 String lname = sa.getNonResourceString( 2151 com.android.internal.R.styleable.AndroidManifestLibrary_name); 2152 2153 sa.recycle(); 2154 2155 if (lname != null) { 2156 if (owner.libraryNames == null) { 2157 owner.libraryNames = new ArrayList<String>(); 2158 } 2159 if (!owner.libraryNames.contains(lname)) { 2160 owner.libraryNames.add(lname.intern()); 2161 } 2162 } 2163 2164 XmlUtils.skipCurrentTag(parser); 2165 2166 } else if (tagName.equals("uses-library")) { 2167 sa = res.obtainAttributes(attrs, 2168 com.android.internal.R.styleable.AndroidManifestUsesLibrary); 2169 2170 // Note: don't allow this value to be a reference to a resource 2171 // that may change. 2172 String lname = sa.getNonResourceString( 2173 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 2174 boolean req = sa.getBoolean( 2175 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, 2176 true); 2177 2178 sa.recycle(); 2179 2180 if (lname != null) { 2181 if (req) { 2182 if (owner.usesLibraries == null) { 2183 owner.usesLibraries = new ArrayList<String>(); 2184 } 2185 if (!owner.usesLibraries.contains(lname)) { 2186 owner.usesLibraries.add(lname.intern()); 2187 } 2188 } else { 2189 if (owner.usesOptionalLibraries == null) { 2190 owner.usesOptionalLibraries = new ArrayList<String>(); 2191 } 2192 if (!owner.usesOptionalLibraries.contains(lname)) { 2193 owner.usesOptionalLibraries.add(lname.intern()); 2194 } 2195 } 2196 } 2197 2198 XmlUtils.skipCurrentTag(parser); 2199 2200 } else if (tagName.equals("uses-package")) { 2201 // Dependencies for app installers; we don't currently try to 2202 // enforce this. 2203 XmlUtils.skipCurrentTag(parser); 2204 2205 } else { 2206 if (!RIGID_PARSER) { 2207 Slog.w(TAG, "Unknown element under <application>: " + tagName 2208 + " at " + mArchiveSourcePath + " " 2209 + parser.getPositionDescription()); 2210 XmlUtils.skipCurrentTag(parser); 2211 continue; 2212 } else { 2213 outError[0] = "Bad element under <application>: " + tagName; 2214 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2215 return false; 2216 } 2217 } 2218 } 2219 2220 return true; 2221 } 2222 2223 private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo, 2224 String[] outError, String tag, TypedArray sa, 2225 int nameRes, int labelRes, int iconRes, int logoRes) { 2226 String name = sa.getNonConfigurationString(nameRes, 0); 2227 if (name == null) { 2228 outError[0] = tag + " does not specify android:name"; 2229 return false; 2230 } 2231 2232 outInfo.name 2233 = buildClassName(owner.applicationInfo.packageName, name, outError); 2234 if (outInfo.name == null) { 2235 return false; 2236 } 2237 2238 int iconVal = sa.getResourceId(iconRes, 0); 2239 if (iconVal != 0) { 2240 outInfo.icon = iconVal; 2241 outInfo.nonLocalizedLabel = null; 2242 } 2243 2244 int logoVal = sa.getResourceId(logoRes, 0); 2245 if (logoVal != 0) { 2246 outInfo.logo = logoVal; 2247 } 2248 2249 TypedValue v = sa.peekValue(labelRes); 2250 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 2251 outInfo.nonLocalizedLabel = v.coerceToString(); 2252 } 2253 2254 outInfo.packageName = owner.packageName; 2255 2256 return true; 2257 } 2258 2259 private Activity parseActivity(Package owner, Resources res, 2260 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError, 2261 boolean receiver, boolean hardwareAccelerated) 2262 throws XmlPullParserException, IOException { 2263 TypedArray sa = res.obtainAttributes(attrs, 2264 com.android.internal.R.styleable.AndroidManifestActivity); 2265 2266 if (mParseActivityArgs == null) { 2267 mParseActivityArgs = new ParseComponentArgs(owner, outError, 2268 com.android.internal.R.styleable.AndroidManifestActivity_name, 2269 com.android.internal.R.styleable.AndroidManifestActivity_label, 2270 com.android.internal.R.styleable.AndroidManifestActivity_icon, 2271 com.android.internal.R.styleable.AndroidManifestActivity_logo, 2272 mSeparateProcesses, 2273 com.android.internal.R.styleable.AndroidManifestActivity_process, 2274 com.android.internal.R.styleable.AndroidManifestActivity_description, 2275 com.android.internal.R.styleable.AndroidManifestActivity_enabled); 2276 } 2277 2278 mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>"; 2279 mParseActivityArgs.sa = sa; 2280 mParseActivityArgs.flags = flags; 2281 2282 Activity a = new Activity(mParseActivityArgs, new ActivityInfo()); 2283 if (outError[0] != null) { 2284 sa.recycle(); 2285 return null; 2286 } 2287 2288 boolean setExported = sa.hasValue( 2289 com.android.internal.R.styleable.AndroidManifestActivity_exported); 2290 if (setExported) { 2291 a.info.exported = sa.getBoolean( 2292 com.android.internal.R.styleable.AndroidManifestActivity_exported, false); 2293 } 2294 2295 a.info.theme = sa.getResourceId( 2296 com.android.internal.R.styleable.AndroidManifestActivity_theme, 0); 2297 2298 a.info.uiOptions = sa.getInt( 2299 com.android.internal.R.styleable.AndroidManifestActivity_uiOptions, 2300 a.info.applicationInfo.uiOptions); 2301 2302 String parentName = sa.getNonConfigurationString( 2303 com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName, 2304 Configuration.NATIVE_CONFIG_VERSION); 2305 if (parentName != null) { 2306 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 2307 if (outError[0] == null) { 2308 a.info.parentActivityName = parentClassName; 2309 } else { 2310 Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " + 2311 parentName); 2312 outError[0] = null; 2313 } 2314 } 2315 2316 String str; 2317 str = sa.getNonConfigurationString( 2318 com.android.internal.R.styleable.AndroidManifestActivity_permission, 0); 2319 if (str == null) { 2320 a.info.permission = owner.applicationInfo.permission; 2321 } else { 2322 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 2323 } 2324 2325 str = sa.getNonConfigurationString( 2326 com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity, 2327 Configuration.NATIVE_CONFIG_VERSION); 2328 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName, 2329 owner.applicationInfo.taskAffinity, str, outError); 2330 2331 a.info.flags = 0; 2332 if (sa.getBoolean( 2333 com.android.internal.R.styleable.AndroidManifestActivity_multiprocess, 2334 false)) { 2335 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS; 2336 } 2337 2338 if (sa.getBoolean( 2339 com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch, 2340 false)) { 2341 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; 2342 } 2343 2344 if (sa.getBoolean( 2345 com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch, 2346 false)) { 2347 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; 2348 } 2349 2350 if (sa.getBoolean( 2351 com.android.internal.R.styleable.AndroidManifestActivity_noHistory, 2352 false)) { 2353 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY; 2354 } 2355 2356 if (sa.getBoolean( 2357 com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState, 2358 false)) { 2359 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; 2360 } 2361 2362 if (sa.getBoolean( 2363 com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded, 2364 false)) { 2365 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; 2366 } 2367 2368 if (sa.getBoolean( 2369 com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents, 2370 false)) { 2371 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; 2372 } 2373 2374 if (sa.getBoolean( 2375 com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting, 2376 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) { 2377 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; 2378 } 2379 2380 if (sa.getBoolean( 2381 com.android.internal.R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, 2382 false)) { 2383 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; 2384 } 2385 2386 if (sa.getBoolean( 2387 com.android.internal.R.styleable.AndroidManifestActivity_showOnLockScreen, 2388 false)) { 2389 a.info.flags |= ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN; 2390 } 2391 2392 if (sa.getBoolean( 2393 com.android.internal.R.styleable.AndroidManifestActivity_immersive, 2394 false)) { 2395 a.info.flags |= ActivityInfo.FLAG_IMMERSIVE; 2396 } 2397 2398 if (!receiver) { 2399 if (sa.getBoolean( 2400 com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated, 2401 hardwareAccelerated)) { 2402 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; 2403 } 2404 2405 a.info.launchMode = sa.getInt( 2406 com.android.internal.R.styleable.AndroidManifestActivity_launchMode, 2407 ActivityInfo.LAUNCH_MULTIPLE); 2408 a.info.screenOrientation = sa.getInt( 2409 com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation, 2410 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 2411 a.info.configChanges = sa.getInt( 2412 com.android.internal.R.styleable.AndroidManifestActivity_configChanges, 2413 0); 2414 a.info.softInputMode = sa.getInt( 2415 com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode, 2416 0); 2417 } else { 2418 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; 2419 a.info.configChanges = 0; 2420 } 2421 2422 if (receiver) { 2423 if (sa.getBoolean( 2424 com.android.internal.R.styleable.AndroidManifestActivity_singleUser, 2425 false)) { 2426 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER; 2427 if (a.info.exported) { 2428 Slog.w(TAG, "Activity exported request ignored due to singleUser: " 2429 + a.className + " at " + mArchiveSourcePath + " " 2430 + parser.getPositionDescription()); 2431 a.info.exported = false; 2432 } 2433 setExported = true; 2434 } 2435 if (sa.getBoolean( 2436 com.android.internal.R.styleable.AndroidManifestActivity_primaryUserOnly, 2437 false)) { 2438 a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY; 2439 } 2440 } 2441 2442 sa.recycle(); 2443 2444 if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { 2445 // A heavy-weight application can not have receives in its main process 2446 // We can do direct compare because we intern all strings. 2447 if (a.info.processName == owner.packageName) { 2448 outError[0] = "Heavy-weight applications can not have receivers in main process"; 2449 } 2450 } 2451 2452 if (outError[0] != null) { 2453 return null; 2454 } 2455 2456 int outerDepth = parser.getDepth(); 2457 int type; 2458 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2459 && (type != XmlPullParser.END_TAG 2460 || parser.getDepth() > outerDepth)) { 2461 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2462 continue; 2463 } 2464 2465 if (parser.getName().equals("intent-filter")) { 2466 ActivityIntentInfo intent = new ActivityIntentInfo(a); 2467 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 2468 return null; 2469 } 2470 if (intent.countActions() == 0) { 2471 Slog.w(TAG, "No actions in intent filter at " 2472 + mArchiveSourcePath + " " 2473 + parser.getPositionDescription()); 2474 } else { 2475 a.intents.add(intent); 2476 } 2477 } else if (!receiver && parser.getName().equals("preferred")) { 2478 ActivityIntentInfo intent = new ActivityIntentInfo(a); 2479 if (!parseIntent(res, parser, attrs, false, intent, outError)) { 2480 return null; 2481 } 2482 if (intent.countActions() == 0) { 2483 Slog.w(TAG, "No actions in preferred at " 2484 + mArchiveSourcePath + " " 2485 + parser.getPositionDescription()); 2486 } else { 2487 if (owner.preferredActivityFilters == null) { 2488 owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>(); 2489 } 2490 owner.preferredActivityFilters.add(intent); 2491 } 2492 } else if (parser.getName().equals("meta-data")) { 2493 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData, 2494 outError)) == null) { 2495 return null; 2496 } 2497 } else { 2498 if (!RIGID_PARSER) { 2499 Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 2500 if (receiver) { 2501 Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName() 2502 + " at " + mArchiveSourcePath + " " 2503 + parser.getPositionDescription()); 2504 } else { 2505 Slog.w(TAG, "Unknown element under <activity>: " + parser.getName() 2506 + " at " + mArchiveSourcePath + " " 2507 + parser.getPositionDescription()); 2508 } 2509 XmlUtils.skipCurrentTag(parser); 2510 continue; 2511 } else { 2512 if (receiver) { 2513 outError[0] = "Bad element under <receiver>: " + parser.getName(); 2514 } else { 2515 outError[0] = "Bad element under <activity>: " + parser.getName(); 2516 } 2517 return null; 2518 } 2519 } 2520 } 2521 2522 if (!setExported) { 2523 a.info.exported = a.intents.size() > 0; 2524 } 2525 2526 return a; 2527 } 2528 2529 private Activity parseActivityAlias(Package owner, Resources res, 2530 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 2531 throws XmlPullParserException, IOException { 2532 TypedArray sa = res.obtainAttributes(attrs, 2533 com.android.internal.R.styleable.AndroidManifestActivityAlias); 2534 2535 String targetActivity = sa.getNonConfigurationString( 2536 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity, 2537 Configuration.NATIVE_CONFIG_VERSION); 2538 if (targetActivity == null) { 2539 outError[0] = "<activity-alias> does not specify android:targetActivity"; 2540 sa.recycle(); 2541 return null; 2542 } 2543 2544 targetActivity = buildClassName(owner.applicationInfo.packageName, 2545 targetActivity, outError); 2546 if (targetActivity == null) { 2547 sa.recycle(); 2548 return null; 2549 } 2550 2551 if (mParseActivityAliasArgs == null) { 2552 mParseActivityAliasArgs = new ParseComponentArgs(owner, outError, 2553 com.android.internal.R.styleable.AndroidManifestActivityAlias_name, 2554 com.android.internal.R.styleable.AndroidManifestActivityAlias_label, 2555 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, 2556 com.android.internal.R.styleable.AndroidManifestActivityAlias_logo, 2557 mSeparateProcesses, 2558 0, 2559 com.android.internal.R.styleable.AndroidManifestActivityAlias_description, 2560 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled); 2561 mParseActivityAliasArgs.tag = "<activity-alias>"; 2562 } 2563 2564 mParseActivityAliasArgs.sa = sa; 2565 mParseActivityAliasArgs.flags = flags; 2566 2567 Activity target = null; 2568 2569 final int NA = owner.activities.size(); 2570 for (int i=0; i<NA; i++) { 2571 Activity t = owner.activities.get(i); 2572 if (targetActivity.equals(t.info.name)) { 2573 target = t; 2574 break; 2575 } 2576 } 2577 2578 if (target == null) { 2579 outError[0] = "<activity-alias> target activity " + targetActivity 2580 + " not found in manifest"; 2581 sa.recycle(); 2582 return null; 2583 } 2584 2585 ActivityInfo info = new ActivityInfo(); 2586 info.targetActivity = targetActivity; 2587 info.configChanges = target.info.configChanges; 2588 info.flags = target.info.flags; 2589 info.icon = target.info.icon; 2590 info.logo = target.info.logo; 2591 info.labelRes = target.info.labelRes; 2592 info.nonLocalizedLabel = target.info.nonLocalizedLabel; 2593 info.launchMode = target.info.launchMode; 2594 info.processName = target.info.processName; 2595 if (info.descriptionRes == 0) { 2596 info.descriptionRes = target.info.descriptionRes; 2597 } 2598 info.screenOrientation = target.info.screenOrientation; 2599 info.taskAffinity = target.info.taskAffinity; 2600 info.theme = target.info.theme; 2601 info.softInputMode = target.info.softInputMode; 2602 info.uiOptions = target.info.uiOptions; 2603 info.parentActivityName = target.info.parentActivityName; 2604 2605 Activity a = new Activity(mParseActivityAliasArgs, info); 2606 if (outError[0] != null) { 2607 sa.recycle(); 2608 return null; 2609 } 2610 2611 final boolean setExported = sa.hasValue( 2612 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported); 2613 if (setExported) { 2614 a.info.exported = sa.getBoolean( 2615 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false); 2616 } 2617 2618 String str; 2619 str = sa.getNonConfigurationString( 2620 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0); 2621 if (str != null) { 2622 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 2623 } 2624 2625 String parentName = sa.getNonConfigurationString( 2626 com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName, 2627 Configuration.NATIVE_CONFIG_VERSION); 2628 if (parentName != null) { 2629 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 2630 if (outError[0] == null) { 2631 a.info.parentActivityName = parentClassName; 2632 } else { 2633 Log.e(TAG, "Activity alias " + a.info.name + 2634 " specified invalid parentActivityName " + parentName); 2635 outError[0] = null; 2636 } 2637 } 2638 2639 sa.recycle(); 2640 2641 if (outError[0] != null) { 2642 return null; 2643 } 2644 2645 int outerDepth = parser.getDepth(); 2646 int type; 2647 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2648 && (type != XmlPullParser.END_TAG 2649 || parser.getDepth() > outerDepth)) { 2650 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2651 continue; 2652 } 2653 2654 if (parser.getName().equals("intent-filter")) { 2655 ActivityIntentInfo intent = new ActivityIntentInfo(a); 2656 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 2657 return null; 2658 } 2659 if (intent.countActions() == 0) { 2660 Slog.w(TAG, "No actions in intent filter at " 2661 + mArchiveSourcePath + " " 2662 + parser.getPositionDescription()); 2663 } else { 2664 a.intents.add(intent); 2665 } 2666 } else if (parser.getName().equals("meta-data")) { 2667 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData, 2668 outError)) == null) { 2669 return null; 2670 } 2671 } else { 2672 if (!RIGID_PARSER) { 2673 Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName() 2674 + " at " + mArchiveSourcePath + " " 2675 + parser.getPositionDescription()); 2676 XmlUtils.skipCurrentTag(parser); 2677 continue; 2678 } else { 2679 outError[0] = "Bad element under <activity-alias>: " + parser.getName(); 2680 return null; 2681 } 2682 } 2683 } 2684 2685 if (!setExported) { 2686 a.info.exported = a.intents.size() > 0; 2687 } 2688 2689 return a; 2690 } 2691 2692 private Provider parseProvider(Package owner, Resources res, 2693 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 2694 throws XmlPullParserException, IOException { 2695 TypedArray sa = res.obtainAttributes(attrs, 2696 com.android.internal.R.styleable.AndroidManifestProvider); 2697 2698 if (mParseProviderArgs == null) { 2699 mParseProviderArgs = new ParseComponentArgs(owner, outError, 2700 com.android.internal.R.styleable.AndroidManifestProvider_name, 2701 com.android.internal.R.styleable.AndroidManifestProvider_label, 2702 com.android.internal.R.styleable.AndroidManifestProvider_icon, 2703 com.android.internal.R.styleable.AndroidManifestProvider_logo, 2704 mSeparateProcesses, 2705 com.android.internal.R.styleable.AndroidManifestProvider_process, 2706 com.android.internal.R.styleable.AndroidManifestProvider_description, 2707 com.android.internal.R.styleable.AndroidManifestProvider_enabled); 2708 mParseProviderArgs.tag = "<provider>"; 2709 } 2710 2711 mParseProviderArgs.sa = sa; 2712 mParseProviderArgs.flags = flags; 2713 2714 Provider p = new Provider(mParseProviderArgs, new ProviderInfo()); 2715 if (outError[0] != null) { 2716 sa.recycle(); 2717 return null; 2718 } 2719 2720 boolean providerExportedDefault = false; 2721 2722 if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 2723 // For compatibility, applications targeting API level 16 or lower 2724 // should have their content providers exported by default, unless they 2725 // specify otherwise. 2726 providerExportedDefault = true; 2727 } 2728 2729 p.info.exported = sa.getBoolean( 2730 com.android.internal.R.styleable.AndroidManifestProvider_exported, 2731 providerExportedDefault); 2732 2733 String cpname = sa.getNonConfigurationString( 2734 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0); 2735 2736 p.info.isSyncable = sa.getBoolean( 2737 com.android.internal.R.styleable.AndroidManifestProvider_syncable, 2738 false); 2739 2740 String permission = sa.getNonConfigurationString( 2741 com.android.internal.R.styleable.AndroidManifestProvider_permission, 0); 2742 String str = sa.getNonConfigurationString( 2743 com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0); 2744 if (str == null) { 2745 str = permission; 2746 } 2747 if (str == null) { 2748 p.info.readPermission = owner.applicationInfo.permission; 2749 } else { 2750 p.info.readPermission = 2751 str.length() > 0 ? str.toString().intern() : null; 2752 } 2753 str = sa.getNonConfigurationString( 2754 com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0); 2755 if (str == null) { 2756 str = permission; 2757 } 2758 if (str == null) { 2759 p.info.writePermission = owner.applicationInfo.permission; 2760 } else { 2761 p.info.writePermission = 2762 str.length() > 0 ? str.toString().intern() : null; 2763 } 2764 2765 p.info.grantUriPermissions = sa.getBoolean( 2766 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions, 2767 false); 2768 2769 p.info.multiprocess = sa.getBoolean( 2770 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess, 2771 false); 2772 2773 p.info.initOrder = sa.getInt( 2774 com.android.internal.R.styleable.AndroidManifestProvider_initOrder, 2775 0); 2776 2777 p.info.flags = 0; 2778 2779 if (sa.getBoolean( 2780 com.android.internal.R.styleable.AndroidManifestProvider_singleUser, 2781 false)) { 2782 p.info.flags |= ProviderInfo.FLAG_SINGLE_USER; 2783 if (p.info.exported) { 2784 Slog.w(TAG, "Provider exported request ignored due to singleUser: " 2785 + p.className + " at " + mArchiveSourcePath + " " 2786 + parser.getPositionDescription()); 2787 p.info.exported = false; 2788 } 2789 } 2790 2791 sa.recycle(); 2792 2793 if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { 2794 // A heavy-weight application can not have providers in its main process 2795 // We can do direct compare because we intern all strings. 2796 if (p.info.processName == owner.packageName) { 2797 outError[0] = "Heavy-weight applications can not have providers in main process"; 2798 return null; 2799 } 2800 } 2801 2802 if (cpname == null) { 2803 outError[0] = "<provider> does not include authorities attribute"; 2804 return null; 2805 } 2806 p.info.authority = cpname.intern(); 2807 2808 if (!parseProviderTags(res, parser, attrs, p, outError)) { 2809 return null; 2810 } 2811 2812 return p; 2813 } 2814 2815 private boolean parseProviderTags(Resources res, 2816 XmlPullParser parser, AttributeSet attrs, 2817 Provider outInfo, String[] outError) 2818 throws XmlPullParserException, IOException { 2819 int outerDepth = parser.getDepth(); 2820 int type; 2821 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2822 && (type != XmlPullParser.END_TAG 2823 || parser.getDepth() > outerDepth)) { 2824 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2825 continue; 2826 } 2827 2828 if (parser.getName().equals("intent-filter")) { 2829 ProviderIntentInfo intent = new ProviderIntentInfo(outInfo); 2830 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 2831 return false; 2832 } 2833 outInfo.intents.add(intent); 2834 2835 } else if (parser.getName().equals("meta-data")) { 2836 if ((outInfo.metaData=parseMetaData(res, parser, attrs, 2837 outInfo.metaData, outError)) == null) { 2838 return false; 2839 } 2840 2841 } else if (parser.getName().equals("grant-uri-permission")) { 2842 TypedArray sa = res.obtainAttributes(attrs, 2843 com.android.internal.R.styleable.AndroidManifestGrantUriPermission); 2844 2845 PatternMatcher pa = null; 2846 2847 String str = sa.getNonConfigurationString( 2848 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0); 2849 if (str != null) { 2850 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); 2851 } 2852 2853 str = sa.getNonConfigurationString( 2854 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); 2855 if (str != null) { 2856 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); 2857 } 2858 2859 str = sa.getNonConfigurationString( 2860 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); 2861 if (str != null) { 2862 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 2863 } 2864 2865 sa.recycle(); 2866 2867 if (pa != null) { 2868 if (outInfo.info.uriPermissionPatterns == null) { 2869 outInfo.info.uriPermissionPatterns = new PatternMatcher[1]; 2870 outInfo.info.uriPermissionPatterns[0] = pa; 2871 } else { 2872 final int N = outInfo.info.uriPermissionPatterns.length; 2873 PatternMatcher[] newp = new PatternMatcher[N+1]; 2874 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N); 2875 newp[N] = pa; 2876 outInfo.info.uriPermissionPatterns = newp; 2877 } 2878 outInfo.info.grantUriPermissions = true; 2879 } else { 2880 if (!RIGID_PARSER) { 2881 Slog.w(TAG, "Unknown element under <path-permission>: " 2882 + parser.getName() + " at " + mArchiveSourcePath + " " 2883 + parser.getPositionDescription()); 2884 XmlUtils.skipCurrentTag(parser); 2885 continue; 2886 } else { 2887 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 2888 return false; 2889 } 2890 } 2891 XmlUtils.skipCurrentTag(parser); 2892 2893 } else if (parser.getName().equals("path-permission")) { 2894 TypedArray sa = res.obtainAttributes(attrs, 2895 com.android.internal.R.styleable.AndroidManifestPathPermission); 2896 2897 PathPermission pa = null; 2898 2899 String permission = sa.getNonConfigurationString( 2900 com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0); 2901 String readPermission = sa.getNonConfigurationString( 2902 com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0); 2903 if (readPermission == null) { 2904 readPermission = permission; 2905 } 2906 String writePermission = sa.getNonConfigurationString( 2907 com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0); 2908 if (writePermission == null) { 2909 writePermission = permission; 2910 } 2911 2912 boolean havePerm = false; 2913 if (readPermission != null) { 2914 readPermission = readPermission.intern(); 2915 havePerm = true; 2916 } 2917 if (writePermission != null) { 2918 writePermission = writePermission.intern(); 2919 havePerm = true; 2920 } 2921 2922 if (!havePerm) { 2923 if (!RIGID_PARSER) { 2924 Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: " 2925 + parser.getName() + " at " + mArchiveSourcePath + " " 2926 + parser.getPositionDescription()); 2927 XmlUtils.skipCurrentTag(parser); 2928 continue; 2929 } else { 2930 outError[0] = "No readPermission or writePermssion for <path-permission>"; 2931 return false; 2932 } 2933 } 2934 2935 String path = sa.getNonConfigurationString( 2936 com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0); 2937 if (path != null) { 2938 pa = new PathPermission(path, 2939 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission); 2940 } 2941 2942 path = sa.getNonConfigurationString( 2943 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0); 2944 if (path != null) { 2945 pa = new PathPermission(path, 2946 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission); 2947 } 2948 2949 path = sa.getNonConfigurationString( 2950 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0); 2951 if (path != null) { 2952 pa = new PathPermission(path, 2953 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission); 2954 } 2955 2956 sa.recycle(); 2957 2958 if (pa != null) { 2959 if (outInfo.info.pathPermissions == null) { 2960 outInfo.info.pathPermissions = new PathPermission[1]; 2961 outInfo.info.pathPermissions[0] = pa; 2962 } else { 2963 final int N = outInfo.info.pathPermissions.length; 2964 PathPermission[] newp = new PathPermission[N+1]; 2965 System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N); 2966 newp[N] = pa; 2967 outInfo.info.pathPermissions = newp; 2968 } 2969 } else { 2970 if (!RIGID_PARSER) { 2971 Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: " 2972 + parser.getName() + " at " + mArchiveSourcePath + " " 2973 + parser.getPositionDescription()); 2974 XmlUtils.skipCurrentTag(parser); 2975 continue; 2976 } 2977 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 2978 return false; 2979 } 2980 XmlUtils.skipCurrentTag(parser); 2981 2982 } else { 2983 if (!RIGID_PARSER) { 2984 Slog.w(TAG, "Unknown element under <provider>: " 2985 + parser.getName() + " at " + mArchiveSourcePath + " " 2986 + parser.getPositionDescription()); 2987 XmlUtils.skipCurrentTag(parser); 2988 continue; 2989 } else { 2990 outError[0] = "Bad element under <provider>: " + parser.getName(); 2991 return false; 2992 } 2993 } 2994 } 2995 return true; 2996 } 2997 2998 private Service parseService(Package owner, Resources res, 2999 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) 3000 throws XmlPullParserException, IOException { 3001 TypedArray sa = res.obtainAttributes(attrs, 3002 com.android.internal.R.styleable.AndroidManifestService); 3003 3004 if (mParseServiceArgs == null) { 3005 mParseServiceArgs = new ParseComponentArgs(owner, outError, 3006 com.android.internal.R.styleable.AndroidManifestService_name, 3007 com.android.internal.R.styleable.AndroidManifestService_label, 3008 com.android.internal.R.styleable.AndroidManifestService_icon, 3009 com.android.internal.R.styleable.AndroidManifestService_logo, 3010 mSeparateProcesses, 3011 com.android.internal.R.styleable.AndroidManifestService_process, 3012 com.android.internal.R.styleable.AndroidManifestService_description, 3013 com.android.internal.R.styleable.AndroidManifestService_enabled); 3014 mParseServiceArgs.tag = "<service>"; 3015 } 3016 3017 mParseServiceArgs.sa = sa; 3018 mParseServiceArgs.flags = flags; 3019 3020 Service s = new Service(mParseServiceArgs, new ServiceInfo()); 3021 if (outError[0] != null) { 3022 sa.recycle(); 3023 return null; 3024 } 3025 3026 boolean setExported = sa.hasValue( 3027 com.android.internal.R.styleable.AndroidManifestService_exported); 3028 if (setExported) { 3029 s.info.exported = sa.getBoolean( 3030 com.android.internal.R.styleable.AndroidManifestService_exported, false); 3031 } 3032 3033 String str = sa.getNonConfigurationString( 3034 com.android.internal.R.styleable.AndroidManifestService_permission, 0); 3035 if (str == null) { 3036 s.info.permission = owner.applicationInfo.permission; 3037 } else { 3038 s.info.permission = str.length() > 0 ? str.toString().intern() : null; 3039 } 3040 3041 s.info.flags = 0; 3042 if (sa.getBoolean( 3043 com.android.internal.R.styleable.AndroidManifestService_stopWithTask, 3044 false)) { 3045 s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK; 3046 } 3047 if (sa.getBoolean( 3048 com.android.internal.R.styleable.AndroidManifestService_isolatedProcess, 3049 false)) { 3050 s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS; 3051 } 3052 if (sa.getBoolean( 3053 com.android.internal.R.styleable.AndroidManifestService_singleUser, 3054 false)) { 3055 s.info.flags |= ServiceInfo.FLAG_SINGLE_USER; 3056 if (s.info.exported) { 3057 Slog.w(TAG, "Service exported request ignored due to singleUser: " 3058 + s.className + " at " + mArchiveSourcePath + " " 3059 + parser.getPositionDescription()); 3060 s.info.exported = false; 3061 } 3062 setExported = true; 3063 } 3064 3065 sa.recycle(); 3066 3067 if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { 3068 // A heavy-weight application can not have services in its main process 3069 // We can do direct compare because we intern all strings. 3070 if (s.info.processName == owner.packageName) { 3071 outError[0] = "Heavy-weight applications can not have services in main process"; 3072 return null; 3073 } 3074 } 3075 3076 int outerDepth = parser.getDepth(); 3077 int type; 3078 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3079 && (type != XmlPullParser.END_TAG 3080 || parser.getDepth() > outerDepth)) { 3081 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3082 continue; 3083 } 3084 3085 if (parser.getName().equals("intent-filter")) { 3086 ServiceIntentInfo intent = new ServiceIntentInfo(s); 3087 if (!parseIntent(res, parser, attrs, true, intent, outError)) { 3088 return null; 3089 } 3090 3091 s.intents.add(intent); 3092 } else if (parser.getName().equals("meta-data")) { 3093 if ((s.metaData=parseMetaData(res, parser, attrs, s.metaData, 3094 outError)) == null) { 3095 return null; 3096 } 3097 } else { 3098 if (!RIGID_PARSER) { 3099 Slog.w(TAG, "Unknown element under <service>: " 3100 + parser.getName() + " at " + mArchiveSourcePath + " " 3101 + parser.getPositionDescription()); 3102 XmlUtils.skipCurrentTag(parser); 3103 continue; 3104 } else { 3105 outError[0] = "Bad element under <service>: " + parser.getName(); 3106 return null; 3107 } 3108 } 3109 } 3110 3111 if (!setExported) { 3112 s.info.exported = s.intents.size() > 0; 3113 } 3114 3115 return s; 3116 } 3117 3118 private boolean parseAllMetaData(Resources res, 3119 XmlPullParser parser, AttributeSet attrs, String tag, 3120 Component outInfo, String[] outError) 3121 throws XmlPullParserException, IOException { 3122 int outerDepth = parser.getDepth(); 3123 int type; 3124 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3125 && (type != XmlPullParser.END_TAG 3126 || parser.getDepth() > outerDepth)) { 3127 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3128 continue; 3129 } 3130 3131 if (parser.getName().equals("meta-data")) { 3132 if ((outInfo.metaData=parseMetaData(res, parser, attrs, 3133 outInfo.metaData, outError)) == null) { 3134 return false; 3135 } 3136 } else { 3137 if (!RIGID_PARSER) { 3138 Slog.w(TAG, "Unknown element under " + tag + ": " 3139 + parser.getName() + " at " + mArchiveSourcePath + " " 3140 + parser.getPositionDescription()); 3141 XmlUtils.skipCurrentTag(parser); 3142 continue; 3143 } else { 3144 outError[0] = "Bad element under " + tag + ": " + parser.getName(); 3145 return false; 3146 } 3147 } 3148 } 3149 return true; 3150 } 3151 3152 private Bundle parseMetaData(Resources res, 3153 XmlPullParser parser, AttributeSet attrs, 3154 Bundle data, String[] outError) 3155 throws XmlPullParserException, IOException { 3156 3157 TypedArray sa = res.obtainAttributes(attrs, 3158 com.android.internal.R.styleable.AndroidManifestMetaData); 3159 3160 if (data == null) { 3161 data = new Bundle(); 3162 } 3163 3164 String name = sa.getNonConfigurationString( 3165 com.android.internal.R.styleable.AndroidManifestMetaData_name, 0); 3166 if (name == null) { 3167 outError[0] = "<meta-data> requires an android:name attribute"; 3168 sa.recycle(); 3169 return null; 3170 } 3171 3172 name = name.intern(); 3173 3174 TypedValue v = sa.peekValue( 3175 com.android.internal.R.styleable.AndroidManifestMetaData_resource); 3176 if (v != null && v.resourceId != 0) { 3177 //Slog.i(TAG, "Meta data ref " + name + ": " + v); 3178 data.putInt(name, v.resourceId); 3179 } else { 3180 v = sa.peekValue( 3181 com.android.internal.R.styleable.AndroidManifestMetaData_value); 3182 //Slog.i(TAG, "Meta data " + name + ": " + v); 3183 if (v != null) { 3184 if (v.type == TypedValue.TYPE_STRING) { 3185 CharSequence cs = v.coerceToString(); 3186 data.putString(name, cs != null ? cs.toString().intern() : null); 3187 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { 3188 data.putBoolean(name, v.data != 0); 3189 } else if (v.type >= TypedValue.TYPE_FIRST_INT 3190 && v.type <= TypedValue.TYPE_LAST_INT) { 3191 data.putInt(name, v.data); 3192 } else if (v.type == TypedValue.TYPE_FLOAT) { 3193 data.putFloat(name, v.getFloat()); 3194 } else { 3195 if (!RIGID_PARSER) { 3196 Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: " 3197 + parser.getName() + " at " + mArchiveSourcePath + " " 3198 + parser.getPositionDescription()); 3199 } else { 3200 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types"; 3201 data = null; 3202 } 3203 } 3204 } else { 3205 outError[0] = "<meta-data> requires an android:value or android:resource attribute"; 3206 data = null; 3207 } 3208 } 3209 3210 sa.recycle(); 3211 3212 XmlUtils.skipCurrentTag(parser); 3213 3214 return data; 3215 } 3216 3217 private static VerifierInfo parseVerifier(Resources res, XmlPullParser parser, 3218 AttributeSet attrs, int flags, String[] outError) throws XmlPullParserException, 3219 IOException { 3220 final TypedArray sa = res.obtainAttributes(attrs, 3221 com.android.internal.R.styleable.AndroidManifestPackageVerifier); 3222 3223 final String packageName = sa.getNonResourceString( 3224 com.android.internal.R.styleable.AndroidManifestPackageVerifier_name); 3225 3226 final String encodedPublicKey = sa.getNonResourceString( 3227 com.android.internal.R.styleable.AndroidManifestPackageVerifier_publicKey); 3228 3229 sa.recycle(); 3230 3231 if (packageName == null || packageName.length() == 0) { 3232 Slog.i(TAG, "verifier package name was null; skipping"); 3233 return null; 3234 } else if (encodedPublicKey == null) { 3235 Slog.i(TAG, "verifier " + packageName + " public key was null; skipping"); 3236 } 3237 3238 PublicKey publicKey = parsePublicKey(encodedPublicKey); 3239 if (publicKey != null) { 3240 return new VerifierInfo(packageName, publicKey); 3241 } 3242 3243 return null; 3244 } 3245 3246 public static final PublicKey parsePublicKey(String encodedPublicKey) { 3247 EncodedKeySpec keySpec; 3248 try { 3249 final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT); 3250 keySpec = new X509EncodedKeySpec(encoded); 3251 } catch (IllegalArgumentException e) { 3252 Slog.i(TAG, "Could not parse verifier public key; invalid Base64"); 3253 return null; 3254 } 3255 3256 /* First try the key as an RSA key. */ 3257 try { 3258 final KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 3259 return keyFactory.generatePublic(keySpec); 3260 } catch (NoSuchAlgorithmException e) { 3261 Log.wtf(TAG, "Could not parse public key because RSA isn't included in build"); 3262 return null; 3263 } catch (InvalidKeySpecException e) { 3264 // Not a RSA public key. 3265 } 3266 3267 /* Now try it as a DSA key. */ 3268 try { 3269 final KeyFactory keyFactory = KeyFactory.getInstance("DSA"); 3270 return keyFactory.generatePublic(keySpec); 3271 } catch (NoSuchAlgorithmException e) { 3272 Log.wtf(TAG, "Could not parse public key because DSA isn't included in build"); 3273 return null; 3274 } catch (InvalidKeySpecException e) { 3275 // Not a DSA public key. 3276 } 3277 3278 return null; 3279 } 3280 3281 private static final String ANDROID_RESOURCES 3282 = "http://schemas.android.com/apk/res/android"; 3283 3284 private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs, 3285 boolean allowGlobs, IntentInfo outInfo, String[] outError) 3286 throws XmlPullParserException, IOException { 3287 3288 TypedArray sa = res.obtainAttributes(attrs, 3289 com.android.internal.R.styleable.AndroidManifestIntentFilter); 3290 3291 int priority = sa.getInt( 3292 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0); 3293 outInfo.setPriority(priority); 3294 3295 TypedValue v = sa.peekValue( 3296 com.android.internal.R.styleable.AndroidManifestIntentFilter_label); 3297 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 3298 outInfo.nonLocalizedLabel = v.coerceToString(); 3299 } 3300 3301 outInfo.icon = sa.getResourceId( 3302 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0); 3303 3304 outInfo.logo = sa.getResourceId( 3305 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0); 3306 3307 sa.recycle(); 3308 3309 int outerDepth = parser.getDepth(); 3310 int type; 3311 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 3312 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 3313 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3314 continue; 3315 } 3316 3317 String nodeName = parser.getName(); 3318 if (nodeName.equals("action")) { 3319 String value = attrs.getAttributeValue( 3320 ANDROID_RESOURCES, "name"); 3321 if (value == null || value == "") { 3322 outError[0] = "No value supplied for <android:name>"; 3323 return false; 3324 } 3325 XmlUtils.skipCurrentTag(parser); 3326 3327 outInfo.addAction(value); 3328 } else if (nodeName.equals("category")) { 3329 String value = attrs.getAttributeValue( 3330 ANDROID_RESOURCES, "name"); 3331 if (value == null || value == "") { 3332 outError[0] = "No value supplied for <android:name>"; 3333 return false; 3334 } 3335 XmlUtils.skipCurrentTag(parser); 3336 3337 outInfo.addCategory(value); 3338 3339 } else if (nodeName.equals("data")) { 3340 sa = res.obtainAttributes(attrs, 3341 com.android.internal.R.styleable.AndroidManifestData); 3342 3343 String str = sa.getNonConfigurationString( 3344 com.android.internal.R.styleable.AndroidManifestData_mimeType, 0); 3345 if (str != null) { 3346 try { 3347 outInfo.addDataType(str); 3348 } catch (IntentFilter.MalformedMimeTypeException e) { 3349 outError[0] = e.toString(); 3350 sa.recycle(); 3351 return false; 3352 } 3353 } 3354 3355 str = sa.getNonConfigurationString( 3356 com.android.internal.R.styleable.AndroidManifestData_scheme, 0); 3357 if (str != null) { 3358 outInfo.addDataScheme(str); 3359 } 3360 3361 str = sa.getNonConfigurationString( 3362 com.android.internal.R.styleable.AndroidManifestData_ssp, 0); 3363 if (str != null) { 3364 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL); 3365 } 3366 3367 str = sa.getNonConfigurationString( 3368 com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0); 3369 if (str != null) { 3370 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX); 3371 } 3372 3373 str = sa.getNonConfigurationString( 3374 com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0); 3375 if (str != null) { 3376 if (!allowGlobs) { 3377 outError[0] = "sspPattern not allowed here; ssp must be literal"; 3378 return false; 3379 } 3380 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 3381 } 3382 3383 String host = sa.getNonConfigurationString( 3384 com.android.internal.R.styleable.AndroidManifestData_host, 0); 3385 String port = sa.getNonConfigurationString( 3386 com.android.internal.R.styleable.AndroidManifestData_port, 0); 3387 if (host != null) { 3388 outInfo.addDataAuthority(host, port); 3389 } 3390 3391 str = sa.getNonConfigurationString( 3392 com.android.internal.R.styleable.AndroidManifestData_path, 0); 3393 if (str != null) { 3394 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); 3395 } 3396 3397 str = sa.getNonConfigurationString( 3398 com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0); 3399 if (str != null) { 3400 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); 3401 } 3402 3403 str = sa.getNonConfigurationString( 3404 com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0); 3405 if (str != null) { 3406 if (!allowGlobs) { 3407 outError[0] = "pathPattern not allowed here; path must be literal"; 3408 return false; 3409 } 3410 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 3411 } 3412 3413 sa.recycle(); 3414 XmlUtils.skipCurrentTag(parser); 3415 } else if (!RIGID_PARSER) { 3416 Slog.w(TAG, "Unknown element under <intent-filter>: " 3417 + parser.getName() + " at " + mArchiveSourcePath + " " 3418 + parser.getPositionDescription()); 3419 XmlUtils.skipCurrentTag(parser); 3420 } else { 3421 outError[0] = "Bad element under <intent-filter>: " + parser.getName(); 3422 return false; 3423 } 3424 } 3425 3426 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT); 3427 3428 if (DEBUG_PARSER) { 3429 final StringBuilder cats = new StringBuilder("Intent d="); 3430 cats.append(outInfo.hasDefault); 3431 cats.append(", cat="); 3432 3433 final Iterator<String> it = outInfo.categoriesIterator(); 3434 if (it != null) { 3435 while (it.hasNext()) { 3436 cats.append(' '); 3437 cats.append(it.next()); 3438 } 3439 } 3440 Slog.d(TAG, cats.toString()); 3441 } 3442 3443 return true; 3444 } 3445 3446 public final static class Package { 3447 3448 public String packageName; 3449 3450 // For now we only support one application per package. 3451 public final ApplicationInfo applicationInfo = new ApplicationInfo(); 3452 3453 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0); 3454 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0); 3455 public final ArrayList<Activity> activities = new ArrayList<Activity>(0); 3456 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0); 3457 public final ArrayList<Provider> providers = new ArrayList<Provider>(0); 3458 public final ArrayList<Service> services = new ArrayList<Service>(0); 3459 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0); 3460 3461 public final ArrayList<String> requestedPermissions = new ArrayList<String>(); 3462 public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>(); 3463 3464 public ArrayList<String> protectedBroadcasts; 3465 3466 public ArrayList<String> libraryNames = null; 3467 public ArrayList<String> usesLibraries = null; 3468 public ArrayList<String> usesOptionalLibraries = null; 3469 public String[] usesLibraryFiles = null; 3470 3471 public ArrayList<ActivityIntentInfo> preferredActivityFilters = null; 3472 3473 public ArrayList<String> mOriginalPackages = null; 3474 public String mRealPackage = null; 3475 public ArrayList<String> mAdoptPermissions = null; 3476 3477 // We store the application meta-data independently to avoid multiple unwanted references 3478 public Bundle mAppMetaData = null; 3479 3480 // If this is a 3rd party app, this is the path of the zip file. 3481 public String mPath; 3482 3483 // The version code declared for this package. 3484 public int mVersionCode; 3485 3486 // The version name declared for this package. 3487 public String mVersionName; 3488 3489 // The shared user id that this package wants to use. 3490 public String mSharedUserId; 3491 3492 // The shared user label that this package wants to use. 3493 public int mSharedUserLabel; 3494 3495 // Signatures that were read from the package. 3496 public Signature mSignatures[]; 3497 3498 // For use by package manager service for quick lookup of 3499 // preferred up order. 3500 public int mPreferredOrder = 0; 3501 3502 // For use by the package manager to keep track of the path to the 3503 // file an app came from. 3504 public String mScanPath; 3505 3506 // For use by package manager to keep track of where it has done dexopt. 3507 public boolean mDidDexOpt; 3508 3509 // // User set enabled state. 3510 // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; 3511 // 3512 // // Whether the package has been stopped. 3513 // public boolean mSetStopped = false; 3514 3515 // Additional data supplied by callers. 3516 public Object mExtras; 3517 3518 // Whether an operation is currently pending on this package 3519 public boolean mOperationPending; 3520 3521 /* 3522 * Applications hardware preferences 3523 */ 3524 public final ArrayList<ConfigurationInfo> configPreferences = 3525 new ArrayList<ConfigurationInfo>(); 3526 3527 /* 3528 * Applications requested features 3529 */ 3530 public ArrayList<FeatureInfo> reqFeatures = null; 3531 3532 public int installLocation; 3533 3534 /* An app that's required for all users and cannot be uninstalled for a user */ 3535 public boolean mRequiredForAllUsers; 3536 3537 /* The restricted account authenticator type that is used by this application */ 3538 public String mRestrictedAccountType; 3539 3540 /* The required account type without which this application will not function */ 3541 public String mRequiredAccountType; 3542 3543 /** 3544 * Digest suitable for comparing whether this package's manifest is the 3545 * same as another. 3546 */ 3547 public ManifestDigest manifestDigest; 3548 3549 /** 3550 * Data used to feed the KeySetManager 3551 */ 3552 public Set<PublicKey> mSigningKeys; 3553 public Map<String, Set<PublicKey>> mKeySetMapping; 3554 3555 public Package(String _name) { 3556 packageName = _name; 3557 applicationInfo.packageName = _name; 3558 applicationInfo.uid = -1; 3559 } 3560 3561 public void setPackageName(String newName) { 3562 packageName = newName; 3563 applicationInfo.packageName = newName; 3564 for (int i=permissions.size()-1; i>=0; i--) { 3565 permissions.get(i).setPackageName(newName); 3566 } 3567 for (int i=permissionGroups.size()-1; i>=0; i--) { 3568 permissionGroups.get(i).setPackageName(newName); 3569 } 3570 for (int i=activities.size()-1; i>=0; i--) { 3571 activities.get(i).setPackageName(newName); 3572 } 3573 for (int i=receivers.size()-1; i>=0; i--) { 3574 receivers.get(i).setPackageName(newName); 3575 } 3576 for (int i=providers.size()-1; i>=0; i--) { 3577 providers.get(i).setPackageName(newName); 3578 } 3579 for (int i=services.size()-1; i>=0; i--) { 3580 services.get(i).setPackageName(newName); 3581 } 3582 for (int i=instrumentation.size()-1; i>=0; i--) { 3583 instrumentation.get(i).setPackageName(newName); 3584 } 3585 } 3586 3587 public boolean hasComponentClassName(String name) { 3588 for (int i=activities.size()-1; i>=0; i--) { 3589 if (name.equals(activities.get(i).className)) { 3590 return true; 3591 } 3592 } 3593 for (int i=receivers.size()-1; i>=0; i--) { 3594 if (name.equals(receivers.get(i).className)) { 3595 return true; 3596 } 3597 } 3598 for (int i=providers.size()-1; i>=0; i--) { 3599 if (name.equals(providers.get(i).className)) { 3600 return true; 3601 } 3602 } 3603 for (int i=services.size()-1; i>=0; i--) { 3604 if (name.equals(services.get(i).className)) { 3605 return true; 3606 } 3607 } 3608 for (int i=instrumentation.size()-1; i>=0; i--) { 3609 if (name.equals(instrumentation.get(i).className)) { 3610 return true; 3611 } 3612 } 3613 return false; 3614 } 3615 3616 public String toString() { 3617 return "Package{" 3618 + Integer.toHexString(System.identityHashCode(this)) 3619 + " " + packageName + "}"; 3620 } 3621 } 3622 3623 public static class Component<II extends IntentInfo> { 3624 public final Package owner; 3625 public final ArrayList<II> intents; 3626 public final String className; 3627 public Bundle metaData; 3628 3629 ComponentName componentName; 3630 String componentShortName; 3631 3632 public Component(Package _owner) { 3633 owner = _owner; 3634 intents = null; 3635 className = null; 3636 } 3637 3638 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) { 3639 owner = args.owner; 3640 intents = new ArrayList<II>(0); 3641 String name = args.sa.getNonConfigurationString(args.nameRes, 0); 3642 if (name == null) { 3643 className = null; 3644 args.outError[0] = args.tag + " does not specify android:name"; 3645 return; 3646 } 3647 3648 outInfo.name 3649 = buildClassName(owner.applicationInfo.packageName, name, args.outError); 3650 if (outInfo.name == null) { 3651 className = null; 3652 args.outError[0] = args.tag + " does not have valid android:name"; 3653 return; 3654 } 3655 3656 className = outInfo.name; 3657 3658 int iconVal = args.sa.getResourceId(args.iconRes, 0); 3659 if (iconVal != 0) { 3660 outInfo.icon = iconVal; 3661 outInfo.nonLocalizedLabel = null; 3662 } 3663 3664 int logoVal = args.sa.getResourceId(args.logoRes, 0); 3665 if (logoVal != 0) { 3666 outInfo.logo = logoVal; 3667 } 3668 3669 TypedValue v = args.sa.peekValue(args.labelRes); 3670 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 3671 outInfo.nonLocalizedLabel = v.coerceToString(); 3672 } 3673 3674 outInfo.packageName = owner.packageName; 3675 } 3676 3677 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) { 3678 this(args, (PackageItemInfo)outInfo); 3679 if (args.outError[0] != null) { 3680 return; 3681 } 3682 3683 if (args.processRes != 0) { 3684 CharSequence pname; 3685 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 3686 pname = args.sa.getNonConfigurationString(args.processRes, 3687 Configuration.NATIVE_CONFIG_VERSION); 3688 } else { 3689 // Some older apps have been seen to use a resource reference 3690 // here that on older builds was ignored (with a warning). We 3691 // need to continue to do this for them so they don't break. 3692 pname = args.sa.getNonResourceString(args.processRes); 3693 } 3694 outInfo.processName = buildProcessName(owner.applicationInfo.packageName, 3695 owner.applicationInfo.processName, pname, 3696 args.flags, args.sepProcesses, args.outError); 3697 } 3698 3699 if (args.descriptionRes != 0) { 3700 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0); 3701 } 3702 3703 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true); 3704 } 3705 3706 public Component(Component<II> clone) { 3707 owner = clone.owner; 3708 intents = clone.intents; 3709 className = clone.className; 3710 componentName = clone.componentName; 3711 componentShortName = clone.componentShortName; 3712 } 3713 3714 public ComponentName getComponentName() { 3715 if (componentName != null) { 3716 return componentName; 3717 } 3718 if (className != null) { 3719 componentName = new ComponentName(owner.applicationInfo.packageName, 3720 className); 3721 } 3722 return componentName; 3723 } 3724 3725 public void appendComponentShortName(StringBuilder sb) { 3726 ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className); 3727 } 3728 3729 public void printComponentShortName(PrintWriter pw) { 3730 ComponentName.printShortString(pw, owner.applicationInfo.packageName, className); 3731 } 3732 3733 public void setPackageName(String packageName) { 3734 componentName = null; 3735 componentShortName = null; 3736 } 3737 } 3738 3739 public final static class Permission extends Component<IntentInfo> { 3740 public final PermissionInfo info; 3741 public boolean tree; 3742 public PermissionGroup group; 3743 3744 public Permission(Package _owner) { 3745 super(_owner); 3746 info = new PermissionInfo(); 3747 } 3748 3749 public Permission(Package _owner, PermissionInfo _info) { 3750 super(_owner); 3751 info = _info; 3752 } 3753 3754 public void setPackageName(String packageName) { 3755 super.setPackageName(packageName); 3756 info.packageName = packageName; 3757 } 3758 3759 public String toString() { 3760 return "Permission{" 3761 + Integer.toHexString(System.identityHashCode(this)) 3762 + " " + info.name + "}"; 3763 } 3764 } 3765 3766 public final static class PermissionGroup extends Component<IntentInfo> { 3767 public final PermissionGroupInfo info; 3768 3769 public PermissionGroup(Package _owner) { 3770 super(_owner); 3771 info = new PermissionGroupInfo(); 3772 } 3773 3774 public PermissionGroup(Package _owner, PermissionGroupInfo _info) { 3775 super(_owner); 3776 info = _info; 3777 } 3778 3779 public void setPackageName(String packageName) { 3780 super.setPackageName(packageName); 3781 info.packageName = packageName; 3782 } 3783 3784 public String toString() { 3785 return "PermissionGroup{" 3786 + Integer.toHexString(System.identityHashCode(this)) 3787 + " " + info.name + "}"; 3788 } 3789 } 3790 3791 private static boolean copyNeeded(int flags, Package p, 3792 PackageUserState state, Bundle metaData, int userId) { 3793 if (userId != 0) { 3794 // We always need to copy for other users, since we need 3795 // to fix up the uid. 3796 return true; 3797 } 3798 if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 3799 boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 3800 if (p.applicationInfo.enabled != enabled) { 3801 return true; 3802 } 3803 } 3804 if (!state.installed || state.blocked) { 3805 return true; 3806 } 3807 if (state.stopped) { 3808 return true; 3809 } 3810 if ((flags & PackageManager.GET_META_DATA) != 0 3811 && (metaData != null || p.mAppMetaData != null)) { 3812 return true; 3813 } 3814 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 3815 && p.usesLibraryFiles != null) { 3816 return true; 3817 } 3818 return false; 3819 } 3820 3821 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 3822 PackageUserState state) { 3823 return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId()); 3824 } 3825 3826 private static void updateApplicationInfo(ApplicationInfo ai, int flags, 3827 PackageUserState state) { 3828 // CompatibilityMode is global state. 3829 if (!sCompatibilityModeEnabled) { 3830 ai.disableCompatibilityMode(); 3831 } 3832 if (state.installed) { 3833 ai.flags |= ApplicationInfo.FLAG_INSTALLED; 3834 } else { 3835 ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; 3836 } 3837 if (state.blocked) { 3838 ai.flags |= ApplicationInfo.FLAG_BLOCKED; 3839 } else { 3840 ai.flags &= ~ApplicationInfo.FLAG_BLOCKED; 3841 } 3842 if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 3843 ai.enabled = true; 3844 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { 3845 ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0; 3846 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED 3847 || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { 3848 ai.enabled = false; 3849 } 3850 ai.enabledSetting = state.enabled; 3851 } 3852 3853 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 3854 PackageUserState state, int userId) { 3855 if (p == null) return null; 3856 if (!checkUseInstalledOrBlocked(flags, state)) { 3857 return null; 3858 } 3859 if (!copyNeeded(flags, p, state, null, userId) 3860 && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0 3861 || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { 3862 // In this case it is safe to directly modify the internal ApplicationInfo state: 3863 // - CompatibilityMode is global state, so will be the same for every call. 3864 // - We only come in to here if the app should reported as installed; this is the 3865 // default state, and we will do a copy otherwise. 3866 // - The enable state will always be reported the same for the application across 3867 // calls; the only exception is for the UNTIL_USED mode, and in that case we will 3868 // be doing a copy. 3869 updateApplicationInfo(p.applicationInfo, flags, state); 3870 return p.applicationInfo; 3871 } 3872 3873 // Make shallow copy so we can store the metadata/libraries safely 3874 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo); 3875 if (userId != 0) { 3876 ai.uid = UserHandle.getUid(userId, ai.uid); 3877 ai.dataDir = PackageManager.getDataDirForUser(userId, ai.packageName); 3878 } 3879 if ((flags & PackageManager.GET_META_DATA) != 0) { 3880 ai.metaData = p.mAppMetaData; 3881 } 3882 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { 3883 ai.sharedLibraryFiles = p.usesLibraryFiles; 3884 } 3885 if (state.stopped) { 3886 ai.flags |= ApplicationInfo.FLAG_STOPPED; 3887 } else { 3888 ai.flags &= ~ApplicationInfo.FLAG_STOPPED; 3889 } 3890 updateApplicationInfo(ai, flags, state); 3891 return ai; 3892 } 3893 3894 public static final PermissionInfo generatePermissionInfo( 3895 Permission p, int flags) { 3896 if (p == null) return null; 3897 if ((flags&PackageManager.GET_META_DATA) == 0) { 3898 return p.info; 3899 } 3900 PermissionInfo pi = new PermissionInfo(p.info); 3901 pi.metaData = p.metaData; 3902 return pi; 3903 } 3904 3905 public static final PermissionGroupInfo generatePermissionGroupInfo( 3906 PermissionGroup pg, int flags) { 3907 if (pg == null) return null; 3908 if ((flags&PackageManager.GET_META_DATA) == 0) { 3909 return pg.info; 3910 } 3911 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info); 3912 pgi.metaData = pg.metaData; 3913 return pgi; 3914 } 3915 3916 public final static class Activity extends Component<ActivityIntentInfo> { 3917 public final ActivityInfo info; 3918 3919 public Activity(final ParseComponentArgs args, final ActivityInfo _info) { 3920 super(args, _info); 3921 info = _info; 3922 info.applicationInfo = args.owner.applicationInfo; 3923 } 3924 3925 public void setPackageName(String packageName) { 3926 super.setPackageName(packageName); 3927 info.packageName = packageName; 3928 } 3929 3930 public String toString() { 3931 StringBuilder sb = new StringBuilder(128); 3932 sb.append("Activity{"); 3933 sb.append(Integer.toHexString(System.identityHashCode(this))); 3934 sb.append(' '); 3935 appendComponentShortName(sb); 3936 sb.append('}'); 3937 return sb.toString(); 3938 } 3939 } 3940 3941 public static final ActivityInfo generateActivityInfo(Activity a, int flags, 3942 PackageUserState state, int userId) { 3943 if (a == null) return null; 3944 if (!checkUseInstalledOrBlocked(flags, state)) { 3945 return null; 3946 } 3947 if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) { 3948 return a.info; 3949 } 3950 // Make shallow copies so we can store the metadata safely 3951 ActivityInfo ai = new ActivityInfo(a.info); 3952 ai.metaData = a.metaData; 3953 ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId); 3954 return ai; 3955 } 3956 3957 public final static class Service extends Component<ServiceIntentInfo> { 3958 public final ServiceInfo info; 3959 3960 public Service(final ParseComponentArgs args, final ServiceInfo _info) { 3961 super(args, _info); 3962 info = _info; 3963 info.applicationInfo = args.owner.applicationInfo; 3964 } 3965 3966 public void setPackageName(String packageName) { 3967 super.setPackageName(packageName); 3968 info.packageName = packageName; 3969 } 3970 3971 public String toString() { 3972 StringBuilder sb = new StringBuilder(128); 3973 sb.append("Service{"); 3974 sb.append(Integer.toHexString(System.identityHashCode(this))); 3975 sb.append(' '); 3976 appendComponentShortName(sb); 3977 sb.append('}'); 3978 return sb.toString(); 3979 } 3980 } 3981 3982 public static final ServiceInfo generateServiceInfo(Service s, int flags, 3983 PackageUserState state, int userId) { 3984 if (s == null) return null; 3985 if (!checkUseInstalledOrBlocked(flags, state)) { 3986 return null; 3987 } 3988 if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) { 3989 return s.info; 3990 } 3991 // Make shallow copies so we can store the metadata safely 3992 ServiceInfo si = new ServiceInfo(s.info); 3993 si.metaData = s.metaData; 3994 si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId); 3995 return si; 3996 } 3997 3998 public final static class Provider extends Component<ProviderIntentInfo> { 3999 public final ProviderInfo info; 4000 public boolean syncable; 4001 4002 public Provider(final ParseComponentArgs args, final ProviderInfo _info) { 4003 super(args, _info); 4004 info = _info; 4005 info.applicationInfo = args.owner.applicationInfo; 4006 syncable = false; 4007 } 4008 4009 public Provider(Provider existingProvider) { 4010 super(existingProvider); 4011 this.info = existingProvider.info; 4012 this.syncable = existingProvider.syncable; 4013 } 4014 4015 public void setPackageName(String packageName) { 4016 super.setPackageName(packageName); 4017 info.packageName = packageName; 4018 } 4019 4020 public String toString() { 4021 StringBuilder sb = new StringBuilder(128); 4022 sb.append("Provider{"); 4023 sb.append(Integer.toHexString(System.identityHashCode(this))); 4024 sb.append(' '); 4025 appendComponentShortName(sb); 4026 sb.append('}'); 4027 return sb.toString(); 4028 } 4029 } 4030 4031 public static final ProviderInfo generateProviderInfo(Provider p, int flags, 4032 PackageUserState state, int userId) { 4033 if (p == null) return null; 4034 if (!checkUseInstalledOrBlocked(flags, state)) { 4035 return null; 4036 } 4037 if (!copyNeeded(flags, p.owner, state, p.metaData, userId) 4038 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 4039 || p.info.uriPermissionPatterns == null)) { 4040 return p.info; 4041 } 4042 // Make shallow copies so we can store the metadata safely 4043 ProviderInfo pi = new ProviderInfo(p.info); 4044 pi.metaData = p.metaData; 4045 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { 4046 pi.uriPermissionPatterns = null; 4047 } 4048 pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId); 4049 return pi; 4050 } 4051 4052 public final static class Instrumentation extends Component { 4053 public final InstrumentationInfo info; 4054 4055 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) { 4056 super(args, _info); 4057 info = _info; 4058 } 4059 4060 public void setPackageName(String packageName) { 4061 super.setPackageName(packageName); 4062 info.packageName = packageName; 4063 } 4064 4065 public String toString() { 4066 StringBuilder sb = new StringBuilder(128); 4067 sb.append("Instrumentation{"); 4068 sb.append(Integer.toHexString(System.identityHashCode(this))); 4069 sb.append(' '); 4070 appendComponentShortName(sb); 4071 sb.append('}'); 4072 return sb.toString(); 4073 } 4074 } 4075 4076 public static final InstrumentationInfo generateInstrumentationInfo( 4077 Instrumentation i, int flags) { 4078 if (i == null) return null; 4079 if ((flags&PackageManager.GET_META_DATA) == 0) { 4080 return i.info; 4081 } 4082 InstrumentationInfo ii = new InstrumentationInfo(i.info); 4083 ii.metaData = i.metaData; 4084 return ii; 4085 } 4086 4087 public static class IntentInfo extends IntentFilter { 4088 public boolean hasDefault; 4089 public int labelRes; 4090 public CharSequence nonLocalizedLabel; 4091 public int icon; 4092 public int logo; 4093 public int preferred; 4094 } 4095 4096 public final static class ActivityIntentInfo extends IntentInfo { 4097 public final Activity activity; 4098 4099 public ActivityIntentInfo(Activity _activity) { 4100 activity = _activity; 4101 } 4102 4103 public String toString() { 4104 StringBuilder sb = new StringBuilder(128); 4105 sb.append("ActivityIntentInfo{"); 4106 sb.append(Integer.toHexString(System.identityHashCode(this))); 4107 sb.append(' '); 4108 activity.appendComponentShortName(sb); 4109 sb.append('}'); 4110 return sb.toString(); 4111 } 4112 } 4113 4114 public final static class ServiceIntentInfo extends IntentInfo { 4115 public final Service service; 4116 4117 public ServiceIntentInfo(Service _service) { 4118 service = _service; 4119 } 4120 4121 public String toString() { 4122 StringBuilder sb = new StringBuilder(128); 4123 sb.append("ServiceIntentInfo{"); 4124 sb.append(Integer.toHexString(System.identityHashCode(this))); 4125 sb.append(' '); 4126 service.appendComponentShortName(sb); 4127 sb.append('}'); 4128 return sb.toString(); 4129 } 4130 } 4131 4132 public static final class ProviderIntentInfo extends IntentInfo { 4133 public final Provider provider; 4134 4135 public ProviderIntentInfo(Provider provider) { 4136 this.provider = provider; 4137 } 4138 4139 public String toString() { 4140 StringBuilder sb = new StringBuilder(128); 4141 sb.append("ProviderIntentInfo{"); 4142 sb.append(Integer.toHexString(System.identityHashCode(this))); 4143 sb.append(' '); 4144 provider.appendComponentShortName(sb); 4145 sb.append('}'); 4146 return sb.toString(); 4147 } 4148 } 4149 4150 /** 4151 * @hide 4152 */ 4153 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { 4154 sCompatibilityModeEnabled = compatibilityModeEnabled; 4155 } 4156} 4157