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