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