PackageParser.java revision 354cd3ce2213a1032d9138ea6fa1420f055ab08c
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 com.android.internal.R; 20import com.android.internal.util.ArrayUtils; 21import com.android.internal.util.XmlUtils; 22 23import org.xmlpull.v1.XmlPullParser; 24import org.xmlpull.v1.XmlPullParserException; 25 26import android.app.ActivityManager; 27import android.content.ComponentName; 28import android.content.Intent; 29import android.content.IntentFilter; 30import android.content.res.AssetManager; 31import android.content.res.Configuration; 32import android.content.res.Resources; 33import android.content.res.TypedArray; 34import android.content.res.XmlResourceParser; 35import android.os.Build; 36import android.os.Bundle; 37import android.os.FileUtils; 38import android.os.PatternMatcher; 39import android.os.Trace; 40import android.os.UserHandle; 41import android.text.TextUtils; 42import android.util.ArrayMap; 43import android.util.ArraySet; 44import android.util.AttributeSet; 45import android.util.Base64; 46import android.util.DisplayMetrics; 47import android.util.Log; 48import android.util.Pair; 49import android.util.Slog; 50import android.util.TypedValue; 51import android.util.apk.ApkSignatureSchemeV2Verifier; 52import android.util.jar.StrictJarFile; 53import android.view.Gravity; 54 55import java.io.File; 56import java.io.IOException; 57import java.io.InputStream; 58import java.io.PrintWriter; 59import java.security.GeneralSecurityException; 60import java.security.KeyFactory; 61import java.security.NoSuchAlgorithmException; 62import java.security.PublicKey; 63import java.security.cert.Certificate; 64import java.security.cert.CertificateEncodingException; 65import java.security.spec.EncodedKeySpec; 66import java.security.spec.InvalidKeySpecException; 67import java.security.spec.X509EncodedKeySpec; 68import java.util.ArrayList; 69import java.util.Arrays; 70import java.util.Collections; 71import java.util.Comparator; 72import java.util.Iterator; 73import java.util.List; 74import java.util.Set; 75import java.util.concurrent.atomic.AtomicReference; 76import java.util.zip.ZipEntry; 77 78import libcore.io.IoUtils; 79 80import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; 81import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE; 82import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS; 83import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 84import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE; 85import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; 86import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 87import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES; 88import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; 89import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 90import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; 91import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; 92import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 93import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; 94import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; 95import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; 96import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; 97 98/** 99 * Parser for package files (APKs) on disk. This supports apps packaged either 100 * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple 101 * APKs in a single directory. 102 * <p> 103 * Apps packaged as multiple APKs always consist of a single "base" APK (with a 104 * {@code null} split name) and zero or more "split" APKs (with unique split 105 * names). Any subset of those split APKs are a valid install, as long as the 106 * following constraints are met: 107 * <ul> 108 * <li>All APKs must have the exact same package name, version code, and signing 109 * certificates. 110 * <li>All APKs must have unique split names. 111 * <li>All installations must contain a single base APK. 112 * </ul> 113 * 114 * @hide 115 */ 116public class PackageParser { 117 private static final boolean DEBUG_JAR = false; 118 private static final boolean DEBUG_PARSER = false; 119 private static final boolean DEBUG_BACKUP = false; 120 121 private static final int MAX_PACKAGES_PER_APK = 5; 122 123 // TODO: switch outError users to PackageParserException 124 // TODO: refactor "codePath" to "apkPath" 125 126 /** File name in an APK for the Android manifest. */ 127 private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; 128 129 /** 130 * File name in an APK for bytecode. There may be additional bytecode files 131 * but this one is always required for an APK that has code. 132 */ 133 private static final String BYTECODE_FILENAME = "classes.dex"; 134 135 /** Path prefix for apps on expanded storage */ 136 private static final String MNT_EXPAND = "/mnt/expand/"; 137 138 private static final String TAG_MANIFEST = "manifest"; 139 private static final String TAG_APPLICATION = "application"; 140 private static final String TAG_OVERLAY = "overlay"; 141 private static final String TAG_KEY_SETS = "key-sets"; 142 private static final String TAG_PERMISSION_GROUP = "permission-group"; 143 private static final String TAG_PERMISSION = "permission"; 144 private static final String TAG_PERMISSION_TREE = "permission-tree"; 145 private static final String TAG_USES_PERMISSION = "uses-permission"; 146 private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; 147 private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23"; 148 private static final String TAG_USES_CONFIGURATION = "uses-configuration"; 149 private static final String TAG_USES_FEATURE = "uses-feature"; 150 private static final String TAG_FEATURE_GROUP = "feature-group"; 151 private static final String TAG_USES_SDK = "uses-sdk"; 152 private static final String TAG_SUPPORT_SCREENS = "supports-screens"; 153 private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast"; 154 private static final String TAG_INSTRUMENTATION = "instrumentation"; 155 private static final String TAG_ORIGINAL_PACKAGE = "original-package"; 156 private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; 157 private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture"; 158 private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens"; 159 private static final String TAG_SUPPORTS_INPUT = "supports-input"; 160 private static final String TAG_EAT_COMMENT = "eat-comment"; 161 private static final String TAG_PACKAGE = "package"; 162 163 // These are the tags supported by child packages 164 private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>(); 165 static { 166 CHILD_PACKAGE_TAGS.add(TAG_APPLICATION); 167 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION); 168 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M); 169 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23); 170 CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION); 171 CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE); 172 CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP); 173 CHILD_PACKAGE_TAGS.add(TAG_USES_SDK); 174 CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS); 175 CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION); 176 CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE); 177 CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS); 178 CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT); 179 CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT); 180 } 181 182 /** @hide */ 183 public static class NewPermissionInfo { 184 public final String name; 185 public final int sdkVersion; 186 public final int fileVersion; 187 188 public NewPermissionInfo(String name, int sdkVersion, int fileVersion) { 189 this.name = name; 190 this.sdkVersion = sdkVersion; 191 this.fileVersion = fileVersion; 192 } 193 } 194 195 /** @hide */ 196 public static class SplitPermissionInfo { 197 public final String rootPerm; 198 public final String[] newPerms; 199 public final int targetSdk; 200 201 public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) { 202 this.rootPerm = rootPerm; 203 this.newPerms = newPerms; 204 this.targetSdk = targetSdk; 205 } 206 } 207 208 /** 209 * List of new permissions that have been added since 1.0. 210 * NOTE: These must be declared in SDK version order, with permissions 211 * added to older SDKs appearing before those added to newer SDKs. 212 * If sdkVersion is 0, then this is not a permission that we want to 213 * automatically add to older apps, but we do want to allow it to be 214 * granted during a platform update. 215 * @hide 216 */ 217 public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] = 218 new PackageParser.NewPermissionInfo[] { 219 new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 220 android.os.Build.VERSION_CODES.DONUT, 0), 221 new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE, 222 android.os.Build.VERSION_CODES.DONUT, 0) 223 }; 224 225 /** 226 * List of permissions that have been split into more granular or dependent 227 * permissions. 228 * @hide 229 */ 230 public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] = 231 new PackageParser.SplitPermissionInfo[] { 232 // READ_EXTERNAL_STORAGE is always required when an app requests 233 // WRITE_EXTERNAL_STORAGE, because we can't have an app that has 234 // write access without read access. The hack here with the target 235 // target SDK version ensures that this grant is always done. 236 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, 237 new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE }, 238 android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1), 239 new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS, 240 new String[] { android.Manifest.permission.READ_CALL_LOG }, 241 android.os.Build.VERSION_CODES.JELLY_BEAN), 242 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS, 243 new String[] { android.Manifest.permission.WRITE_CALL_LOG }, 244 android.os.Build.VERSION_CODES.JELLY_BEAN) 245 }; 246 247 /** 248 * @deprecated callers should move to explicitly passing around source path. 249 */ 250 @Deprecated 251 private String mArchiveSourcePath; 252 253 private String[] mSeparateProcesses; 254 private boolean mOnlyCoreApps; 255 private DisplayMetrics mMetrics; 256 257 private static final int SDK_VERSION = Build.VERSION.SDK_INT; 258 private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES; 259 260 private int mParseError = PackageManager.INSTALL_SUCCEEDED; 261 262 private static boolean sCompatibilityModeEnabled = true; 263 private static final int PARSE_DEFAULT_INSTALL_LOCATION = 264 PackageInfo.INSTALL_LOCATION_UNSPECIFIED; 265 266 static class ParsePackageItemArgs { 267 final Package owner; 268 final String[] outError; 269 final int nameRes; 270 final int labelRes; 271 final int iconRes; 272 final int logoRes; 273 final int bannerRes; 274 275 String tag; 276 TypedArray sa; 277 278 ParsePackageItemArgs(Package _owner, String[] _outError, 279 int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes) { 280 owner = _owner; 281 outError = _outError; 282 nameRes = _nameRes; 283 labelRes = _labelRes; 284 iconRes = _iconRes; 285 logoRes = _logoRes; 286 bannerRes = _bannerRes; 287 } 288 } 289 290 static class ParseComponentArgs extends ParsePackageItemArgs { 291 final String[] sepProcesses; 292 final int processRes; 293 final int descriptionRes; 294 final int enabledRes; 295 int flags; 296 297 ParseComponentArgs(Package _owner, String[] _outError, 298 int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes, 299 String[] _sepProcesses, int _processRes, 300 int _descriptionRes, int _enabledRes) { 301 super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes, _bannerRes); 302 sepProcesses = _sepProcesses; 303 processRes = _processRes; 304 descriptionRes = _descriptionRes; 305 enabledRes = _enabledRes; 306 } 307 } 308 309 /** 310 * Lightweight parsed details about a single package. 311 */ 312 public static class PackageLite { 313 public final String packageName; 314 public final int versionCode; 315 public final int installLocation; 316 public final VerifierInfo[] verifiers; 317 318 /** Names of any split APKs, ordered by parsed splitName */ 319 public final String[] splitNames; 320 321 /** 322 * Path where this package was found on disk. For monolithic packages 323 * this is path to single base APK file; for cluster packages this is 324 * path to the cluster directory. 325 */ 326 public final String codePath; 327 328 /** Path of base APK */ 329 public final String baseCodePath; 330 /** Paths of any split APKs, ordered by parsed splitName */ 331 public final String[] splitCodePaths; 332 333 /** Revision code of base APK */ 334 public final int baseRevisionCode; 335 /** Revision codes of any split APKs, ordered by parsed splitName */ 336 public final int[] splitRevisionCodes; 337 338 public final boolean coreApp; 339 public final boolean multiArch; 340 public final String abiOverride; 341 public final boolean extractNativeLibs; 342 343 public PackageLite(String codePath, ApkLite baseApk, String[] splitNames, 344 String[] splitCodePaths, int[] splitRevisionCodes) { 345 this.packageName = baseApk.packageName; 346 this.versionCode = baseApk.versionCode; 347 this.installLocation = baseApk.installLocation; 348 this.verifiers = baseApk.verifiers; 349 this.splitNames = splitNames; 350 this.codePath = codePath; 351 this.baseCodePath = baseApk.codePath; 352 this.splitCodePaths = splitCodePaths; 353 this.baseRevisionCode = baseApk.revisionCode; 354 this.splitRevisionCodes = splitRevisionCodes; 355 this.coreApp = baseApk.coreApp; 356 this.multiArch = baseApk.multiArch; 357 this.abiOverride = baseApk.abiOverride; 358 this.extractNativeLibs = baseApk.extractNativeLibs; 359 } 360 361 public List<String> getAllCodePaths() { 362 ArrayList<String> paths = new ArrayList<>(); 363 paths.add(baseCodePath); 364 if (!ArrayUtils.isEmpty(splitCodePaths)) { 365 Collections.addAll(paths, splitCodePaths); 366 } 367 return paths; 368 } 369 } 370 371 /** 372 * Lightweight parsed details about a single APK file. 373 */ 374 public static class ApkLite { 375 public final String codePath; 376 public final String packageName; 377 public final String splitName; 378 public final int versionCode; 379 public final int revisionCode; 380 public final int installLocation; 381 public final VerifierInfo[] verifiers; 382 public final Signature[] signatures; 383 public final boolean coreApp; 384 public final boolean multiArch; 385 public final String abiOverride; 386 public final boolean extractNativeLibs; 387 388 public ApkLite(String codePath, String packageName, String splitName, int versionCode, 389 int revisionCode, int installLocation, List<VerifierInfo> verifiers, 390 Signature[] signatures, boolean coreApp, boolean multiArch, String abiOverride, 391 boolean extractNativeLibs) { 392 this.codePath = codePath; 393 this.packageName = packageName; 394 this.splitName = splitName; 395 this.versionCode = versionCode; 396 this.revisionCode = revisionCode; 397 this.installLocation = installLocation; 398 this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]); 399 this.signatures = signatures; 400 this.coreApp = coreApp; 401 this.multiArch = multiArch; 402 this.abiOverride = abiOverride; 403 this.extractNativeLibs = extractNativeLibs; 404 } 405 } 406 407 private ParsePackageItemArgs mParseInstrumentationArgs; 408 private ParseComponentArgs mParseActivityArgs; 409 private ParseComponentArgs mParseActivityAliasArgs; 410 private ParseComponentArgs mParseServiceArgs; 411 private ParseComponentArgs mParseProviderArgs; 412 413 /** If set to true, we will only allow package files that exactly match 414 * the DTD. Otherwise, we try to get as much from the package as we 415 * can without failing. This should normally be set to false, to 416 * support extensions to the DTD in future versions. */ 417 private static final boolean RIGID_PARSER = false; 418 419 private static final String TAG = "PackageParser"; 420 421 public PackageParser() { 422 mMetrics = new DisplayMetrics(); 423 mMetrics.setToDefaults(); 424 } 425 426 public void setSeparateProcesses(String[] procs) { 427 mSeparateProcesses = procs; 428 } 429 430 /** 431 * Flag indicating this parser should only consider apps with 432 * {@code coreApp} manifest attribute to be valid apps. This is useful when 433 * creating a minimalist boot environment. 434 */ 435 public void setOnlyCoreApps(boolean onlyCoreApps) { 436 mOnlyCoreApps = onlyCoreApps; 437 } 438 439 public void setDisplayMetrics(DisplayMetrics metrics) { 440 mMetrics = metrics; 441 } 442 443 public static final boolean isApkFile(File file) { 444 return isApkPath(file.getName()); 445 } 446 447 private static boolean isApkPath(String path) { 448 return path.endsWith(".apk"); 449 } 450 451 /** 452 * Generate and return the {@link PackageInfo} for a parsed package. 453 * 454 * @param p the parsed package. 455 * @param flags indicating which optional information is included. 456 */ 457 public static PackageInfo generatePackageInfo(PackageParser.Package p, 458 int gids[], int flags, long firstInstallTime, long lastUpdateTime, 459 Set<String> grantedPermissions, PackageUserState state) { 460 461 return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, 462 grantedPermissions, state, UserHandle.getCallingUserId()); 463 } 464 465 /** 466 * Returns true if the package is installed and not hidden, or if the caller 467 * explicitly wanted all uninstalled and hidden packages as well. 468 */ 469 private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state) { 470 return (state.installed && !state.hidden) 471 || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; 472 } 473 474 public static boolean isAvailable(PackageUserState state) { 475 return checkUseInstalledOrHidden(0, state); 476 } 477 478 public static PackageInfo generatePackageInfo(PackageParser.Package p, 479 int gids[], int flags, long firstInstallTime, long lastUpdateTime, 480 Set<String> grantedPermissions, PackageUserState state, int userId) { 481 if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) { 482 return null; 483 } 484 PackageInfo pi = new PackageInfo(); 485 pi.packageName = p.packageName; 486 pi.splitNames = p.splitNames; 487 pi.versionCode = p.mVersionCode; 488 pi.baseRevisionCode = p.baseRevisionCode; 489 pi.splitRevisionCodes = p.splitRevisionCodes; 490 pi.versionName = p.mVersionName; 491 pi.sharedUserId = p.mSharedUserId; 492 pi.sharedUserLabel = p.mSharedUserLabel; 493 pi.applicationInfo = generateApplicationInfo(p, flags, state, userId); 494 pi.installLocation = p.installLocation; 495 pi.coreApp = p.coreApp; 496 if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0 497 || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { 498 pi.requiredForAllUsers = p.mRequiredForAllUsers; 499 } 500 pi.restrictedAccountType = p.mRestrictedAccountType; 501 pi.requiredAccountType = p.mRequiredAccountType; 502 pi.overlayTarget = p.mOverlayTarget; 503 pi.firstInstallTime = firstInstallTime; 504 pi.lastUpdateTime = lastUpdateTime; 505 if ((flags&PackageManager.GET_GIDS) != 0) { 506 pi.gids = gids; 507 } 508 if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) { 509 int N = p.configPreferences != null ? p.configPreferences.size() : 0; 510 if (N > 0) { 511 pi.configPreferences = new ConfigurationInfo[N]; 512 p.configPreferences.toArray(pi.configPreferences); 513 } 514 N = p.reqFeatures != null ? p.reqFeatures.size() : 0; 515 if (N > 0) { 516 pi.reqFeatures = new FeatureInfo[N]; 517 p.reqFeatures.toArray(pi.reqFeatures); 518 } 519 N = p.featureGroups != null ? p.featureGroups.size() : 0; 520 if (N > 0) { 521 pi.featureGroups = new FeatureGroupInfo[N]; 522 p.featureGroups.toArray(pi.featureGroups); 523 } 524 } 525 if ((flags & PackageManager.GET_ACTIVITIES) != 0) { 526 final int N = p.activities.size(); 527 if (N > 0) { 528 int num = 0; 529 final ActivityInfo[] res = new ActivityInfo[N]; 530 for (int i = 0; i < N; i++) { 531 final Activity a = p.activities.get(i); 532 if (state.isMatch(a.info, flags)) { 533 res[num++] = generateActivityInfo(a, flags, state, userId); 534 } 535 } 536 pi.activities = ArrayUtils.trimToSize(res, num); 537 } 538 } 539 if ((flags & PackageManager.GET_RECEIVERS) != 0) { 540 final int N = p.receivers.size(); 541 if (N > 0) { 542 int num = 0; 543 final ActivityInfo[] res = new ActivityInfo[N]; 544 for (int i = 0; i < N; i++) { 545 final Activity a = p.receivers.get(i); 546 if (state.isMatch(a.info, flags)) { 547 res[num++] = generateActivityInfo(a, flags, state, userId); 548 } 549 } 550 pi.receivers = ArrayUtils.trimToSize(res, num); 551 } 552 } 553 if ((flags & PackageManager.GET_SERVICES) != 0) { 554 final int N = p.services.size(); 555 if (N > 0) { 556 int num = 0; 557 final ServiceInfo[] res = new ServiceInfo[N]; 558 for (int i = 0; i < N; i++) { 559 final Service s = p.services.get(i); 560 if (state.isMatch(s.info, flags)) { 561 res[num++] = generateServiceInfo(s, flags, state, userId); 562 } 563 } 564 pi.services = ArrayUtils.trimToSize(res, num); 565 } 566 } 567 if ((flags & PackageManager.GET_PROVIDERS) != 0) { 568 final int N = p.providers.size(); 569 if (N > 0) { 570 int num = 0; 571 final ProviderInfo[] res = new ProviderInfo[N]; 572 for (int i = 0; i < N; i++) { 573 final Provider pr = p.providers.get(i); 574 if (state.isMatch(pr.info, flags)) { 575 res[num++] = generateProviderInfo(pr, flags, state, userId); 576 } 577 } 578 pi.providers = ArrayUtils.trimToSize(res, num); 579 } 580 } 581 if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) { 582 int N = p.instrumentation.size(); 583 if (N > 0) { 584 pi.instrumentation = new InstrumentationInfo[N]; 585 for (int i=0; i<N; i++) { 586 pi.instrumentation[i] = generateInstrumentationInfo( 587 p.instrumentation.get(i), flags); 588 } 589 } 590 } 591 if ((flags&PackageManager.GET_PERMISSIONS) != 0) { 592 int N = p.permissions.size(); 593 if (N > 0) { 594 pi.permissions = new PermissionInfo[N]; 595 for (int i=0; i<N; i++) { 596 pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags); 597 } 598 } 599 N = p.requestedPermissions.size(); 600 if (N > 0) { 601 pi.requestedPermissions = new String[N]; 602 pi.requestedPermissionsFlags = new int[N]; 603 for (int i=0; i<N; i++) { 604 final String perm = p.requestedPermissions.get(i); 605 pi.requestedPermissions[i] = perm; 606 // The notion of required permissions is deprecated but for compatibility. 607 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED; 608 if (grantedPermissions != null && grantedPermissions.contains(perm)) { 609 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED; 610 } 611 } 612 } 613 } 614 if ((flags&PackageManager.GET_SIGNATURES) != 0) { 615 int N = (p.mSignatures != null) ? p.mSignatures.length : 0; 616 if (N > 0) { 617 pi.signatures = new Signature[N]; 618 System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N); 619 } 620 } 621 return pi; 622 } 623 624 private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry) 625 throws PackageParserException { 626 InputStream is = null; 627 try { 628 // We must read the stream for the JarEntry to retrieve 629 // its certificates. 630 is = jarFile.getInputStream(entry); 631 readFullyIgnoringContents(is); 632 return jarFile.getCertificateChains(entry); 633 } catch (IOException | RuntimeException e) { 634 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 635 "Failed reading " + entry.getName() + " in " + jarFile, e); 636 } finally { 637 IoUtils.closeQuietly(is); 638 } 639 } 640 641 public final static int PARSE_IS_SYSTEM = 1<<0; 642 public final static int PARSE_CHATTY = 1<<1; 643 public final static int PARSE_MUST_BE_APK = 1<<2; 644 public final static int PARSE_IGNORE_PROCESSES = 1<<3; 645 public final static int PARSE_FORWARD_LOCK = 1<<4; 646 public final static int PARSE_EXTERNAL_STORAGE = 1<<5; 647 public final static int PARSE_IS_SYSTEM_DIR = 1<<6; 648 public final static int PARSE_IS_PRIVILEGED = 1<<7; 649 public final static int PARSE_COLLECT_CERTIFICATES = 1<<8; 650 public final static int PARSE_TRUSTED_OVERLAY = 1<<9; 651 public final static int PARSE_ENFORCE_CODE = 1<<10; 652 public final static int PARSE_IS_EPHEMERAL = 1<<11; 653 654 private static final Comparator<String> sSplitNameComparator = new SplitNameComparator(); 655 656 /** 657 * Used to sort a set of APKs based on their split names, always placing the 658 * base APK (with {@code null} split name) first. 659 */ 660 private static class SplitNameComparator implements Comparator<String> { 661 @Override 662 public int compare(String lhs, String rhs) { 663 if (lhs == null) { 664 return -1; 665 } else if (rhs == null) { 666 return 1; 667 } else { 668 return lhs.compareTo(rhs); 669 } 670 } 671 } 672 673 /** 674 * Parse only lightweight details about the package at the given location. 675 * Automatically detects if the package is a monolithic style (single APK 676 * file) or cluster style (directory of APKs). 677 * <p> 678 * This performs sanity checking on cluster style packages, such as 679 * requiring identical package name and version codes, a single base APK, 680 * and unique split names. 681 * 682 * @see PackageParser#parsePackage(File, int) 683 */ 684 public static PackageLite parsePackageLite(File packageFile, int flags) 685 throws PackageParserException { 686 if (packageFile.isDirectory()) { 687 return parseClusterPackageLite(packageFile, flags); 688 } else { 689 return parseMonolithicPackageLite(packageFile, flags); 690 } 691 } 692 693 private static PackageLite parseMonolithicPackageLite(File packageFile, int flags) 694 throws PackageParserException { 695 final ApkLite baseApk = parseApkLite(packageFile, flags); 696 final String packagePath = packageFile.getAbsolutePath(); 697 return new PackageLite(packagePath, baseApk, null, null, null); 698 } 699 700 private static PackageLite parseClusterPackageLite(File packageDir, int flags) 701 throws PackageParserException { 702 final File[] files = packageDir.listFiles(); 703 if (ArrayUtils.isEmpty(files)) { 704 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 705 "No packages found in split"); 706 } 707 708 String packageName = null; 709 int versionCode = 0; 710 711 final ArrayMap<String, ApkLite> apks = new ArrayMap<>(); 712 for (File file : files) { 713 if (isApkFile(file)) { 714 final ApkLite lite = parseApkLite(file, flags); 715 716 // Assert that all package names and version codes are 717 // consistent with the first one we encounter. 718 if (packageName == null) { 719 packageName = lite.packageName; 720 versionCode = lite.versionCode; 721 } else { 722 if (!packageName.equals(lite.packageName)) { 723 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 724 "Inconsistent package " + lite.packageName + " in " + file 725 + "; expected " + packageName); 726 } 727 if (versionCode != lite.versionCode) { 728 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 729 "Inconsistent version " + lite.versionCode + " in " + file 730 + "; expected " + versionCode); 731 } 732 } 733 734 // Assert that each split is defined only once 735 if (apks.put(lite.splitName, lite) != null) { 736 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 737 "Split name " + lite.splitName 738 + " defined more than once; most recent was " + file); 739 } 740 } 741 } 742 743 final ApkLite baseApk = apks.remove(null); 744 if (baseApk == null) { 745 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 746 "Missing base APK in " + packageDir); 747 } 748 749 // Always apply deterministic ordering based on splitName 750 final int size = apks.size(); 751 752 String[] splitNames = null; 753 String[] splitCodePaths = null; 754 int[] splitRevisionCodes = null; 755 if (size > 0) { 756 splitNames = new String[size]; 757 splitCodePaths = new String[size]; 758 splitRevisionCodes = new int[size]; 759 760 splitNames = apks.keySet().toArray(splitNames); 761 Arrays.sort(splitNames, sSplitNameComparator); 762 763 for (int i = 0; i < size; i++) { 764 splitCodePaths[i] = apks.get(splitNames[i]).codePath; 765 splitRevisionCodes[i] = apks.get(splitNames[i]).revisionCode; 766 } 767 } 768 769 final String codePath = packageDir.getAbsolutePath(); 770 return new PackageLite(codePath, baseApk, splitNames, splitCodePaths, 771 splitRevisionCodes); 772 } 773 774 /** 775 * Parse the package at the given location. Automatically detects if the 776 * package is a monolithic style (single APK file) or cluster style 777 * (directory of APKs). 778 * <p> 779 * This performs sanity checking on cluster style packages, such as 780 * requiring identical package name and version codes, a single base APK, 781 * and unique split names. 782 * <p> 783 * Note that this <em>does not</em> perform signature verification; that 784 * must be done separately in {@link #collectCertificates(Package, int)}. 785 * 786 * @see #parsePackageLite(File, int) 787 */ 788 public Package parsePackage(File packageFile, int flags) throws PackageParserException { 789 if (packageFile.isDirectory()) { 790 return parseClusterPackage(packageFile, flags); 791 } else { 792 return parseMonolithicPackage(packageFile, flags); 793 } 794 } 795 796 /** 797 * Parse all APKs contained in the given directory, treating them as a 798 * single package. This also performs sanity checking, such as requiring 799 * identical package name and version codes, a single base APK, and unique 800 * split names. 801 * <p> 802 * Note that this <em>does not</em> perform signature verification; that 803 * must be done separately in {@link #collectCertificates(Package, int)}. 804 */ 805 private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException { 806 final PackageLite lite = parseClusterPackageLite(packageDir, 0); 807 808 if (mOnlyCoreApps && !lite.coreApp) { 809 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 810 "Not a coreApp: " + packageDir); 811 } 812 813 final AssetManager assets = new AssetManager(); 814 try { 815 // Load the base and all splits into the AssetManager 816 // so that resources can be overriden when parsing the manifests. 817 loadApkIntoAssetManager(assets, lite.baseCodePath, flags); 818 819 if (!ArrayUtils.isEmpty(lite.splitCodePaths)) { 820 for (String path : lite.splitCodePaths) { 821 loadApkIntoAssetManager(assets, path, flags); 822 } 823 } 824 825 final File baseApk = new File(lite.baseCodePath); 826 final Package pkg = parseBaseApk(baseApk, assets, flags); 827 if (pkg == null) { 828 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 829 "Failed to parse base APK: " + baseApk); 830 } 831 832 if (!ArrayUtils.isEmpty(lite.splitNames)) { 833 final int num = lite.splitNames.length; 834 pkg.splitNames = lite.splitNames; 835 pkg.splitCodePaths = lite.splitCodePaths; 836 pkg.splitRevisionCodes = lite.splitRevisionCodes; 837 pkg.splitFlags = new int[num]; 838 pkg.splitPrivateFlags = new int[num]; 839 840 for (int i = 0; i < num; i++) { 841 parseSplitApk(pkg, i, assets, flags); 842 } 843 } 844 845 pkg.setCodePath(packageDir.getAbsolutePath()); 846 pkg.setCpuAbiOverride(lite.abiOverride); 847 848 return pkg; 849 } finally { 850 IoUtils.closeQuietly(assets); 851 } 852 } 853 854 /** 855 * Parse the given APK file, treating it as as a single monolithic package. 856 * <p> 857 * Note that this <em>does not</em> perform signature verification; that 858 * must be done separately in {@link #collectCertificates(Package, int)}. 859 * 860 * @deprecated external callers should move to 861 * {@link #parsePackage(File, int)}. Eventually this method will 862 * be marked private. 863 */ 864 @Deprecated 865 public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException { 866 final PackageLite lite = parseMonolithicPackageLite(apkFile, flags); 867 if (mOnlyCoreApps) { 868 if (!lite.coreApp) { 869 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 870 "Not a coreApp: " + apkFile); 871 } 872 } 873 874 final AssetManager assets = new AssetManager(); 875 try { 876 final Package pkg = parseBaseApk(apkFile, assets, flags); 877 pkg.setCodePath(apkFile.getAbsolutePath()); 878 pkg.setCpuAbiOverride(lite.abiOverride); 879 return pkg; 880 } finally { 881 IoUtils.closeQuietly(assets); 882 } 883 } 884 885 private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags) 886 throws PackageParserException { 887 if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) { 888 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 889 "Invalid package file: " + apkPath); 890 } 891 892 // The AssetManager guarantees uniqueness for asset paths, so if this asset path 893 // already exists in the AssetManager, addAssetPath will only return the cookie 894 // assigned to it. 895 int cookie = assets.addAssetPath(apkPath); 896 if (cookie == 0) { 897 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 898 "Failed adding asset path: " + apkPath); 899 } 900 return cookie; 901 } 902 903 private Package parseBaseApk(File apkFile, AssetManager assets, int flags) 904 throws PackageParserException { 905 final String apkPath = apkFile.getAbsolutePath(); 906 907 String volumeUuid = null; 908 if (apkPath.startsWith(MNT_EXPAND)) { 909 final int end = apkPath.indexOf('/', MNT_EXPAND.length()); 910 volumeUuid = apkPath.substring(MNT_EXPAND.length(), end); 911 } 912 913 mParseError = PackageManager.INSTALL_SUCCEEDED; 914 mArchiveSourcePath = apkFile.getAbsolutePath(); 915 916 if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); 917 918 final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); 919 920 Resources res = null; 921 XmlResourceParser parser = null; 922 try { 923 res = new Resources(assets, mMetrics, null); 924 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 925 Build.VERSION.RESOURCES_SDK_INT); 926 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 927 928 final String[] outError = new String[1]; 929 final Package pkg = parseBaseApk(res, parser, flags, outError); 930 if (pkg == null) { 931 throw new PackageParserException(mParseError, 932 apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]); 933 } 934 935 pkg.setVolumeUuid(volumeUuid); 936 pkg.setApplicationVolumeUuid(volumeUuid); 937 pkg.setBaseCodePath(apkPath); 938 pkg.setSignatures(null); 939 940 return pkg; 941 942 } catch (PackageParserException e) { 943 throw e; 944 } catch (Exception e) { 945 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 946 "Failed to read manifest from " + apkPath, e); 947 } finally { 948 IoUtils.closeQuietly(parser); 949 } 950 } 951 952 private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags) 953 throws PackageParserException { 954 final String apkPath = pkg.splitCodePaths[splitIndex]; 955 956 mParseError = PackageManager.INSTALL_SUCCEEDED; 957 mArchiveSourcePath = apkPath; 958 959 if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); 960 961 final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); 962 963 Resources res = null; 964 XmlResourceParser parser = null; 965 try { 966 res = new Resources(assets, mMetrics, null); 967 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 968 Build.VERSION.RESOURCES_SDK_INT); 969 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 970 971 final String[] outError = new String[1]; 972 pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError); 973 if (pkg == null) { 974 throw new PackageParserException(mParseError, 975 apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]); 976 } 977 978 } catch (PackageParserException e) { 979 throw e; 980 } catch (Exception e) { 981 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 982 "Failed to read manifest from " + apkPath, e); 983 } finally { 984 IoUtils.closeQuietly(parser); 985 } 986 } 987 988 /** 989 * Parse the manifest of a <em>split APK</em>. 990 * <p> 991 * Note that split APKs have many more restrictions on what they're capable 992 * of doing, so many valid features of a base APK have been carefully 993 * omitted here. 994 */ 995 private Package parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags, 996 int splitIndex, String[] outError) throws XmlPullParserException, IOException, 997 PackageParserException { 998 AttributeSet attrs = parser; 999 1000 // We parsed manifest tag earlier; just skip past it 1001 parsePackageSplitNames(parser, attrs); 1002 1003 mParseInstrumentationArgs = null; 1004 mParseActivityArgs = null; 1005 mParseServiceArgs = null; 1006 mParseProviderArgs = null; 1007 1008 int type; 1009 1010 boolean foundApp = false; 1011 1012 int outerDepth = parser.getDepth(); 1013 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1014 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1015 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1016 continue; 1017 } 1018 1019 String tagName = parser.getName(); 1020 if (tagName.equals("application")) { 1021 if (foundApp) { 1022 if (RIGID_PARSER) { 1023 outError[0] = "<manifest> has more than one <application>"; 1024 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1025 return null; 1026 } else { 1027 Slog.w(TAG, "<manifest> has more than one <application>"); 1028 XmlUtils.skipCurrentTag(parser); 1029 continue; 1030 } 1031 } 1032 1033 foundApp = true; 1034 if (!parseSplitApplication(pkg, res, parser, flags, splitIndex, outError)) { 1035 return null; 1036 } 1037 1038 } else if (RIGID_PARSER) { 1039 outError[0] = "Bad element under <manifest>: " 1040 + parser.getName(); 1041 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1042 return null; 1043 1044 } else { 1045 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() 1046 + " at " + mArchiveSourcePath + " " 1047 + parser.getPositionDescription()); 1048 XmlUtils.skipCurrentTag(parser); 1049 continue; 1050 } 1051 } 1052 1053 if (!foundApp) { 1054 outError[0] = "<manifest> does not contain an <application>"; 1055 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; 1056 } 1057 1058 return pkg; 1059 } 1060 1061 /** 1062 * Collect certificates from all the APKs described in the given package, 1063 * populating {@link Package#mSignatures}. Also asserts that all APK 1064 * contents are signed correctly and consistently. 1065 */ 1066 public static void collectCertificates(Package pkg, int parseFlags) throws PackageParserException { 1067 collectCertificatesInternal(pkg, parseFlags); 1068 final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; 1069 for (int i = 0; i < childCount; i++) { 1070 Package childPkg = pkg.childPackages.get(i); 1071 childPkg.mCertificates = pkg.mCertificates; 1072 childPkg.mSignatures = pkg.mSignatures; 1073 childPkg.mSigningKeys = pkg.mSigningKeys; 1074 } 1075 } 1076 1077 private static void collectCertificatesInternal(Package pkg, int parseFlags) throws PackageParserException { 1078 pkg.mCertificates = null; 1079 pkg.mSignatures = null; 1080 pkg.mSigningKeys = null; 1081 1082 collectCertificates(pkg, new File(pkg.baseCodePath), pkg.applicationInfo.flags, parseFlags); 1083 1084 if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { 1085 for (int i = 0; i < pkg.splitCodePaths.length; i++) { 1086 collectCertificates(pkg, new File(pkg.splitCodePaths[i]), pkg.splitFlags[i], 1087 parseFlags); 1088 } 1089 } 1090 } 1091 1092 private static void collectCertificates(Package pkg, File apkFile, int apkFlags, int parseFlags) 1093 throws PackageParserException { 1094 final boolean hasCode = (apkFlags & ApplicationInfo.FLAG_HAS_CODE) != 0; 1095 final boolean requireCode = ((parseFlags & PARSE_ENFORCE_CODE) != 0) && hasCode; 1096 final String apkPath = apkFile.getAbsolutePath(); 1097 1098 // Try to verify the APK using APK Signature Scheme v2. 1099 boolean verified = false; 1100 { 1101 Certificate[][] allSignersCerts = null; 1102 Signature[] signatures = null; 1103 try { 1104 allSignersCerts = ApkSignatureSchemeV2Verifier.verify(apkPath); 1105 signatures = convertToSignatures(allSignersCerts); 1106 // APK verified using APK Signature Scheme v2. 1107 verified = true; 1108 } catch (ApkSignatureSchemeV2Verifier.SignatureNotFoundException e) { 1109 // No APK Signature Scheme v2 signature found 1110 } catch (Exception e) { 1111 // APK Signature Scheme v2 signature was found but did not verify 1112 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1113 "Failed to collect certificates from " + apkPath 1114 + " using APK Signature Scheme v2", 1115 e); 1116 } 1117 1118 if (verified) { 1119 if (pkg.mCertificates == null) { 1120 pkg.mCertificates = allSignersCerts; 1121 pkg.mSignatures = signatures; 1122 pkg.mSigningKeys = new ArraySet<>(allSignersCerts.length); 1123 for (int i = 0; i < allSignersCerts.length; i++) { 1124 Certificate[] signerCerts = allSignersCerts[i]; 1125 Certificate signerCert = signerCerts[0]; 1126 pkg.mSigningKeys.add(signerCert.getPublicKey()); 1127 } 1128 } else { 1129 if (!Signature.areExactMatch(pkg.mSignatures, signatures)) { 1130 throw new PackageParserException( 1131 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, 1132 apkPath + " has mismatched certificates"); 1133 } 1134 } 1135 // Not yet done, because we need to confirm that AndroidManifest.xml exists and, 1136 // if requested, that classes.dex exists. 1137 } 1138 } 1139 1140 boolean codeFound = false; 1141 StrictJarFile jarFile = null; 1142 try { 1143 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor"); 1144 jarFile = new StrictJarFile( 1145 apkPath, 1146 !verified // whether to verify JAR signature 1147 ); 1148 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1149 1150 // Always verify manifest, regardless of source 1151 final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME); 1152 if (manifestEntry == null) { 1153 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, 1154 "Package " + apkPath + " has no manifest"); 1155 } 1156 1157 // Optimization: early termination when APK already verified 1158 if (verified) { 1159 if ((requireCode) && (jarFile.findEntry(BYTECODE_FILENAME) == null)) { 1160 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 1161 "Package " + apkPath + " code is missing"); 1162 } 1163 return; 1164 } 1165 1166 // APK's integrity needs to be verified using JAR signature scheme. 1167 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "buildVerifyList"); 1168 final List<ZipEntry> toVerify = new ArrayList<>(); 1169 toVerify.add(manifestEntry); 1170 1171 // If we're parsing an untrusted package, verify all contents 1172 if ((parseFlags & PARSE_IS_SYSTEM) == 0) { 1173 final Iterator<ZipEntry> i = jarFile.iterator(); 1174 while (i.hasNext()) { 1175 final ZipEntry entry = i.next(); 1176 1177 if (entry.isDirectory()) continue; 1178 1179 final String entryName = entry.getName(); 1180 if (entryName.startsWith("META-INF/")) continue; 1181 if (entryName.equals(ANDROID_MANIFEST_FILENAME)) continue; 1182 if (entryName.equals(BYTECODE_FILENAME)) { 1183 codeFound = true; 1184 } 1185 1186 toVerify.add(entry); 1187 } 1188 } 1189 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1190 1191 if (!codeFound && requireCode) { 1192 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 1193 "Package " + apkPath + " code is missing"); 1194 } 1195 1196 // Verify that entries are signed consistently with the first entry 1197 // we encountered. Note that for splits, certificates may have 1198 // already been populated during an earlier parse of a base APK. 1199 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyEntries"); 1200 for (ZipEntry entry : toVerify) { 1201 final Certificate[][] entryCerts = loadCertificates(jarFile, entry); 1202 if (ArrayUtils.isEmpty(entryCerts)) { 1203 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1204 "Package " + apkPath + " has no certificates at entry " 1205 + entry.getName()); 1206 } 1207 final Signature[] entrySignatures = convertToSignatures(entryCerts); 1208 1209 if (pkg.mCertificates == null) { 1210 pkg.mCertificates = entryCerts; 1211 pkg.mSignatures = entrySignatures; 1212 pkg.mSigningKeys = new ArraySet<PublicKey>(); 1213 for (int i=0; i < entryCerts.length; i++) { 1214 pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey()); 1215 } 1216 } else { 1217 if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) { 1218 throw new PackageParserException( 1219 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath 1220 + " has mismatched certificates at entry " 1221 + entry.getName()); 1222 } 1223 } 1224 } 1225 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1226 } catch (GeneralSecurityException e) { 1227 throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING, 1228 "Failed to collect certificates from " + apkPath, e); 1229 } catch (IOException | RuntimeException e) { 1230 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, 1231 "Failed to collect certificates from " + apkPath, e); 1232 } finally { 1233 closeQuietly(jarFile); 1234 } 1235 } 1236 1237 private static Signature[] convertToSignatures(Certificate[][] certs) 1238 throws CertificateEncodingException { 1239 final Signature[] res = new Signature[certs.length]; 1240 for (int i = 0; i < certs.length; i++) { 1241 res[i] = new Signature(certs[i]); 1242 } 1243 return res; 1244 } 1245 1246 /** 1247 * Utility method that retrieves lightweight details about a single APK 1248 * file, including package name, split name, and install location. 1249 * 1250 * @param apkFile path to a single APK 1251 * @param flags optional parse flags, such as 1252 * {@link #PARSE_COLLECT_CERTIFICATES} 1253 */ 1254 public static ApkLite parseApkLite(File apkFile, int flags) 1255 throws PackageParserException { 1256 final String apkPath = apkFile.getAbsolutePath(); 1257 1258 AssetManager assets = null; 1259 XmlResourceParser parser = null; 1260 try { 1261 assets = new AssetManager(); 1262 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1263 Build.VERSION.RESOURCES_SDK_INT); 1264 1265 int cookie = assets.addAssetPath(apkPath); 1266 if (cookie == 0) { 1267 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 1268 "Failed to parse " + apkPath); 1269 } 1270 1271 final DisplayMetrics metrics = new DisplayMetrics(); 1272 metrics.setToDefaults(); 1273 1274 final Resources res = new Resources(assets, metrics, null); 1275 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); 1276 1277 final Signature[] signatures; 1278 if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) { 1279 // TODO: factor signature related items out of Package object 1280 final Package tempPkg = new Package(null); 1281 collectCertificates(tempPkg, apkFile, 0 /*apkFlags*/, 0 /*flags*/); 1282 signatures = tempPkg.mSignatures; 1283 } else { 1284 signatures = null; 1285 } 1286 1287 final AttributeSet attrs = parser; 1288 return parseApkLite(apkPath, res, parser, attrs, flags, signatures); 1289 1290 } catch (XmlPullParserException | IOException | RuntimeException e) { 1291 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, 1292 "Failed to parse " + apkPath, e); 1293 } finally { 1294 IoUtils.closeQuietly(parser); 1295 IoUtils.closeQuietly(assets); 1296 } 1297 } 1298 1299 private static String validateName(String name, boolean requireSeparator, 1300 boolean requireFilename) { 1301 final int N = name.length(); 1302 boolean hasSep = false; 1303 boolean front = true; 1304 for (int i=0; i<N; i++) { 1305 final char c = name.charAt(i); 1306 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { 1307 front = false; 1308 continue; 1309 } 1310 if (!front) { 1311 if ((c >= '0' && c <= '9') || c == '_') { 1312 continue; 1313 } 1314 } 1315 if (c == '.') { 1316 hasSep = true; 1317 front = true; 1318 continue; 1319 } 1320 return "bad character '" + c + "'"; 1321 } 1322 if (requireFilename && !FileUtils.isValidExtFilename(name)) { 1323 return "Invalid filename"; 1324 } 1325 return hasSep || !requireSeparator 1326 ? null : "must have at least one '.' separator"; 1327 } 1328 1329 private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser, 1330 AttributeSet attrs) throws IOException, XmlPullParserException, 1331 PackageParserException { 1332 1333 int type; 1334 while ((type = parser.next()) != XmlPullParser.START_TAG 1335 && type != XmlPullParser.END_DOCUMENT) { 1336 } 1337 1338 if (type != XmlPullParser.START_TAG) { 1339 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 1340 "No start tag found"); 1341 } 1342 if (!parser.getName().equals(TAG_MANIFEST)) { 1343 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, 1344 "No <manifest> tag"); 1345 } 1346 1347 final String packageName = attrs.getAttributeValue(null, "package"); 1348 if (!"android".equals(packageName)) { 1349 final String error = validateName(packageName, true, true); 1350 if (error != null) { 1351 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, 1352 "Invalid manifest package: " + error); 1353 } 1354 } 1355 1356 String splitName = attrs.getAttributeValue(null, "split"); 1357 if (splitName != null) { 1358 if (splitName.length() == 0) { 1359 splitName = null; 1360 } else { 1361 final String error = validateName(splitName, false, false); 1362 if (error != null) { 1363 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, 1364 "Invalid manifest split: " + error); 1365 } 1366 } 1367 } 1368 1369 return Pair.create(packageName.intern(), 1370 (splitName != null) ? splitName.intern() : splitName); 1371 } 1372 1373 private static ApkLite parseApkLite(String codePath, Resources res, XmlPullParser parser, 1374 AttributeSet attrs, int flags, Signature[] signatures) throws IOException, 1375 XmlPullParserException, PackageParserException { 1376 final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs); 1377 1378 int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; 1379 int versionCode = 0; 1380 int revisionCode = 0; 1381 boolean coreApp = false; 1382 boolean multiArch = false; 1383 String abiOverride = null; 1384 boolean extractNativeLibs = true; 1385 1386 for (int i = 0; i < attrs.getAttributeCount(); i++) { 1387 final String attr = attrs.getAttributeName(i); 1388 if (attr.equals("installLocation")) { 1389 installLocation = attrs.getAttributeIntValue(i, 1390 PARSE_DEFAULT_INSTALL_LOCATION); 1391 } else if (attr.equals("versionCode")) { 1392 versionCode = attrs.getAttributeIntValue(i, 0); 1393 } else if (attr.equals("revisionCode")) { 1394 revisionCode = attrs.getAttributeIntValue(i, 0); 1395 } else if (attr.equals("coreApp")) { 1396 coreApp = attrs.getAttributeBooleanValue(i, false); 1397 } 1398 } 1399 1400 // Only search the tree when the tag is directly below <manifest> 1401 int type; 1402 final int searchDepth = parser.getDepth() + 1; 1403 1404 final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>(); 1405 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1406 && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) { 1407 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1408 continue; 1409 } 1410 1411 if (parser.getDepth() == searchDepth && "package-verifier".equals(parser.getName())) { 1412 final VerifierInfo verifier = parseVerifier(res, parser, attrs, flags); 1413 if (verifier != null) { 1414 verifiers.add(verifier); 1415 } 1416 } 1417 1418 if (parser.getDepth() == searchDepth && "application".equals(parser.getName())) { 1419 for (int i = 0; i < attrs.getAttributeCount(); ++i) { 1420 final String attr = attrs.getAttributeName(i); 1421 if ("multiArch".equals(attr)) { 1422 multiArch = attrs.getAttributeBooleanValue(i, false); 1423 } 1424 if ("abiOverride".equals(attr)) { 1425 abiOverride = attrs.getAttributeValue(i); 1426 } 1427 if ("extractNativeLibs".equals(attr)) { 1428 extractNativeLibs = attrs.getAttributeBooleanValue(i, true); 1429 } 1430 } 1431 } 1432 } 1433 1434 return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode, 1435 revisionCode, installLocation, verifiers, signatures, coreApp, multiArch, 1436 abiOverride, extractNativeLibs); 1437 } 1438 1439 /** 1440 * Temporary. 1441 */ 1442 static public Signature stringToSignature(String str) { 1443 final int N = str.length(); 1444 byte[] sig = new byte[N]; 1445 for (int i=0; i<N; i++) { 1446 sig[i] = (byte)str.charAt(i); 1447 } 1448 return new Signature(sig); 1449 } 1450 1451 /** 1452 * Parses a child package and adds it to the parent if successful. If you add 1453 * new tags that need to be supported by child packages make sure to add them 1454 * to {@link #CHILD_PACKAGE_TAGS}. 1455 * 1456 * @param parentPkg The parent that contains the child 1457 * @param res Resources against which to resolve values 1458 * @param parser Parser of the manifest 1459 * @param flags Flags about how to parse 1460 * @param outError Human readable error if parsing fails 1461 * @return True of parsing succeeded. 1462 * 1463 * @throws XmlPullParserException 1464 * @throws IOException 1465 */ 1466 private boolean parseBaseApkChild(Package parentPkg, Resources res, XmlResourceParser parser, 1467 int flags, String[] outError) throws XmlPullParserException, IOException { 1468 // Let ppl not abuse this mechanism by limiting the packages per APK 1469 if (parentPkg.childPackages != null && parentPkg.childPackages.size() + 2 1470 > MAX_PACKAGES_PER_APK) { 1471 outError[0] = "Maximum number of packages per APK is: " + MAX_PACKAGES_PER_APK; 1472 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1473 return false; 1474 } 1475 1476 // Make sure we have a valid child package name 1477 String childPackageName = parser.getAttributeValue(null, "package"); 1478 if (validateName(childPackageName, true, false) != null) { 1479 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 1480 return false; 1481 } 1482 1483 // Child packages must be unique 1484 if (childPackageName.equals(parentPkg.packageName)) { 1485 String message = "Child package name cannot be equal to parent package name: " 1486 + parentPkg.packageName; 1487 Slog.w(TAG, message); 1488 outError[0] = message; 1489 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1490 return false; 1491 } 1492 1493 // Child packages must be unique 1494 if (parentPkg.hasChildPackage(childPackageName)) { 1495 String message = "Duplicate child package:" + childPackageName; 1496 Slog.w(TAG, message); 1497 outError[0] = message; 1498 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1499 return false; 1500 } 1501 1502 // Go ahead and parse the child 1503 Package childPkg = new Package(childPackageName); 1504 1505 // Child package inherits parent version code/name/target SDK 1506 childPkg.mVersionCode = parentPkg.mVersionCode; 1507 childPkg.baseRevisionCode = parentPkg.baseRevisionCode; 1508 childPkg.mVersionName = parentPkg.mVersionName; 1509 childPkg.applicationInfo.targetSdkVersion = parentPkg.applicationInfo.targetSdkVersion; 1510 1511 childPkg = parseBaseApkCommon(childPkg, CHILD_PACKAGE_TAGS, res, parser, flags, outError); 1512 if (childPkg == null) { 1513 // If we got null then error was set during child parsing 1514 return false; 1515 } 1516 1517 // Set the parent-child relation 1518 if (parentPkg.childPackages == null) { 1519 parentPkg.childPackages = new ArrayList<>(); 1520 } 1521 parentPkg.childPackages.add(childPkg); 1522 childPkg.parentPackage = parentPkg; 1523 1524 return true; 1525 } 1526 1527 /** 1528 * Parse the manifest of a <em>base APK</em>. When adding new features you 1529 * need to consider whether they should be supported by split APKs and child 1530 * packages. 1531 * 1532 * @param res The resources from which to resolve values 1533 * @param parser The manifest parser 1534 * @param flags Flags how to parse 1535 * @param outError Human readable error message 1536 * @return Parsed package or null on error. 1537 * 1538 * @throws XmlPullParserException 1539 * @throws IOException 1540 */ 1541 private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags, 1542 String[] outError) throws XmlPullParserException, IOException { 1543 final String splitName; 1544 final String pkgName; 1545 1546 try { 1547 Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser); 1548 pkgName = packageSplit.first; 1549 splitName = packageSplit.second; 1550 1551 if (!TextUtils.isEmpty(splitName)) { 1552 outError[0] = "Expected base APK, but found split " + splitName; 1553 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 1554 return null; 1555 } 1556 } catch (PackageParserException e) { 1557 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; 1558 return null; 1559 } 1560 1561 final Package pkg = new Package(pkgName); 1562 1563 TypedArray sa = res.obtainAttributes(parser, 1564 com.android.internal.R.styleable.AndroidManifest); 1565 1566 pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger( 1567 com.android.internal.R.styleable.AndroidManifest_versionCode, 0); 1568 pkg.baseRevisionCode = sa.getInteger( 1569 com.android.internal.R.styleable.AndroidManifest_revisionCode, 0); 1570 pkg.mVersionName = sa.getNonConfigurationString( 1571 com.android.internal.R.styleable.AndroidManifest_versionName, 0); 1572 if (pkg.mVersionName != null) { 1573 pkg.mVersionName = pkg.mVersionName.intern(); 1574 } 1575 1576 pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false); 1577 1578 sa.recycle(); 1579 1580 return parseBaseApkCommon(pkg, null, res, parser, flags, outError); 1581 } 1582 1583 /** 1584 * This is the common parsing routing for handling parent and child 1585 * packages in a base APK. The difference between parent and child 1586 * parsing is that some targs are not supported by child packages as 1587 * well as some manifest attributes are ignored. The implementation 1588 * assumes the calling code already handled the manifest tag if needed 1589 * (this applies to the parent only). 1590 * 1591 * @param pkg The package which to populate 1592 * @param acceptedTags Which tags to handle, null to handle all 1593 * @param res Resources against which to resolve values 1594 * @param parser Parser of the manifest 1595 * @param flags Flags about how to parse 1596 * @param outError Human readable error if parsing fails 1597 * @return The package if parsing succeeded or null. 1598 * 1599 * @throws XmlPullParserException 1600 * @throws IOException 1601 */ 1602 private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res, 1603 XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, 1604 IOException { 1605 final boolean trustedOverlay = (flags & PARSE_TRUSTED_OVERLAY) != 0; 1606 mParseInstrumentationArgs = null; 1607 mParseActivityArgs = null; 1608 mParseServiceArgs = null; 1609 mParseProviderArgs = null; 1610 1611 int type; 1612 boolean foundApp = false; 1613 1614 TypedArray sa = res.obtainAttributes(parser, 1615 com.android.internal.R.styleable.AndroidManifest); 1616 1617 String str = sa.getNonConfigurationString( 1618 com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); 1619 if (str != null && str.length() > 0) { 1620 String nameError = validateName(str, true, false); 1621 if (nameError != null && !"android".equals(pkg.packageName)) { 1622 outError[0] = "<manifest> specifies bad sharedUserId name \"" 1623 + str + "\": " + nameError; 1624 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; 1625 return null; 1626 } 1627 pkg.mSharedUserId = str.intern(); 1628 pkg.mSharedUserLabel = sa.getResourceId( 1629 com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0); 1630 } 1631 1632 pkg.installLocation = sa.getInteger( 1633 com.android.internal.R.styleable.AndroidManifest_installLocation, 1634 PARSE_DEFAULT_INSTALL_LOCATION); 1635 pkg.applicationInfo.installLocation = pkg.installLocation; 1636 1637 1638 /* Set the global "forward lock" flag */ 1639 if ((flags & PARSE_FORWARD_LOCK) != 0) { 1640 pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK; 1641 } 1642 1643 /* Set the global "on SD card" flag */ 1644 if ((flags & PARSE_EXTERNAL_STORAGE) != 0) { 1645 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE; 1646 } 1647 1648 if ((flags & PARSE_IS_EPHEMERAL) != 0) { 1649 pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_EPHEMERAL; 1650 } 1651 1652 // Resource boolean are -1, so 1 means we don't know the value. 1653 int supportsSmallScreens = 1; 1654 int supportsNormalScreens = 1; 1655 int supportsLargeScreens = 1; 1656 int supportsXLargeScreens = 1; 1657 int resizeable = 1; 1658 int anyDensity = 1; 1659 1660 int outerDepth = parser.getDepth(); 1661 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1662 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1663 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1664 continue; 1665 } 1666 1667 String tagName = parser.getName(); 1668 1669 if (acceptedTags != null && !acceptedTags.contains(tagName)) { 1670 Slog.w(TAG, "Skipping unsupported element under <manifest>: " 1671 + tagName + " at " + mArchiveSourcePath + " " 1672 + parser.getPositionDescription()); 1673 XmlUtils.skipCurrentTag(parser); 1674 continue; 1675 } 1676 1677 if (tagName.equals(TAG_APPLICATION)) { 1678 if (foundApp) { 1679 if (RIGID_PARSER) { 1680 outError[0] = "<manifest> has more than one <application>"; 1681 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1682 return null; 1683 } else { 1684 Slog.w(TAG, "<manifest> has more than one <application>"); 1685 XmlUtils.skipCurrentTag(parser); 1686 continue; 1687 } 1688 } 1689 1690 foundApp = true; 1691 if (!parseBaseApplication(pkg, res, parser, flags, outError)) { 1692 return null; 1693 } 1694 } else if (tagName.equals(TAG_OVERLAY)) { 1695 pkg.mTrustedOverlay = trustedOverlay; 1696 1697 sa = res.obtainAttributes(parser, 1698 com.android.internal.R.styleable.AndroidManifestResourceOverlay); 1699 pkg.mOverlayTarget = sa.getString( 1700 com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage); 1701 pkg.mOverlayPriority = sa.getInt( 1702 com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority, 1703 -1); 1704 sa.recycle(); 1705 1706 if (pkg.mOverlayTarget == null) { 1707 outError[0] = "<overlay> does not specify a target package"; 1708 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1709 return null; 1710 } 1711 if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) { 1712 outError[0] = "<overlay> priority must be between 0 and 9999"; 1713 mParseError = 1714 PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 1715 return null; 1716 } 1717 XmlUtils.skipCurrentTag(parser); 1718 1719 } else if (tagName.equals(TAG_KEY_SETS)) { 1720 if (!parseKeySets(pkg, res, parser, outError)) { 1721 return null; 1722 } 1723 } else if (tagName.equals(TAG_PERMISSION_GROUP)) { 1724 if (parsePermissionGroup(pkg, flags, res, parser, outError) == null) { 1725 return null; 1726 } 1727 } else if (tagName.equals(TAG_PERMISSION)) { 1728 if (parsePermission(pkg, res, parser, outError) == null) { 1729 return null; 1730 } 1731 } else if (tagName.equals(TAG_PERMISSION_TREE)) { 1732 if (parsePermissionTree(pkg, res, parser, outError) == null) { 1733 return null; 1734 } 1735 } else if (tagName.equals(TAG_USES_PERMISSION)) { 1736 if (!parseUsesPermission(pkg, res, parser)) { 1737 return null; 1738 } 1739 } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M) 1740 || tagName.equals(TAG_USES_PERMISSION_SDK_23)) { 1741 if (!parseUsesPermission(pkg, res, parser)) { 1742 return null; 1743 } 1744 } else if (tagName.equals(TAG_USES_CONFIGURATION)) { 1745 ConfigurationInfo cPref = new ConfigurationInfo(); 1746 sa = res.obtainAttributes(parser, 1747 com.android.internal.R.styleable.AndroidManifestUsesConfiguration); 1748 cPref.reqTouchScreen = sa.getInt( 1749 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, 1750 Configuration.TOUCHSCREEN_UNDEFINED); 1751 cPref.reqKeyboardType = sa.getInt( 1752 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, 1753 Configuration.KEYBOARD_UNDEFINED); 1754 if (sa.getBoolean( 1755 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, 1756 false)) { 1757 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; 1758 } 1759 cPref.reqNavigation = sa.getInt( 1760 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation, 1761 Configuration.NAVIGATION_UNDEFINED); 1762 if (sa.getBoolean( 1763 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, 1764 false)) { 1765 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; 1766 } 1767 sa.recycle(); 1768 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref); 1769 1770 XmlUtils.skipCurrentTag(parser); 1771 1772 } else if (tagName.equals(TAG_USES_FEATURE)) { 1773 FeatureInfo fi = parseUsesFeature(res, parser); 1774 pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi); 1775 1776 if (fi.name == null) { 1777 ConfigurationInfo cPref = new ConfigurationInfo(); 1778 cPref.reqGlEsVersion = fi.reqGlEsVersion; 1779 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref); 1780 } 1781 1782 XmlUtils.skipCurrentTag(parser); 1783 1784 } else if (tagName.equals(TAG_FEATURE_GROUP)) { 1785 FeatureGroupInfo group = new FeatureGroupInfo(); 1786 ArrayList<FeatureInfo> features = null; 1787 final int innerDepth = parser.getDepth(); 1788 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1789 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 1790 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 1791 continue; 1792 } 1793 1794 final String innerTagName = parser.getName(); 1795 if (innerTagName.equals("uses-feature")) { 1796 FeatureInfo featureInfo = parseUsesFeature(res, parser); 1797 // FeatureGroups are stricter and mandate that 1798 // any <uses-feature> declared are mandatory. 1799 featureInfo.flags |= FeatureInfo.FLAG_REQUIRED; 1800 features = ArrayUtils.add(features, featureInfo); 1801 } else { 1802 Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName + 1803 " at " + mArchiveSourcePath + " " + 1804 parser.getPositionDescription()); 1805 } 1806 XmlUtils.skipCurrentTag(parser); 1807 } 1808 1809 if (features != null) { 1810 group.features = new FeatureInfo[features.size()]; 1811 group.features = features.toArray(group.features); 1812 } 1813 pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group); 1814 1815 } else if (tagName.equals(TAG_USES_SDK)) { 1816 if (SDK_VERSION > 0) { 1817 sa = res.obtainAttributes(parser, 1818 com.android.internal.R.styleable.AndroidManifestUsesSdk); 1819 1820 int minVers = 0; 1821 String minCode = null; 1822 int targetVers = 0; 1823 String targetCode = null; 1824 1825 TypedValue val = sa.peekValue( 1826 com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion); 1827 if (val != null) { 1828 if (val.type == TypedValue.TYPE_STRING && val.string != null) { 1829 targetCode = minCode = val.string.toString(); 1830 } else { 1831 // If it's not a string, it's an integer. 1832 targetVers = minVers = val.data; 1833 } 1834 } 1835 1836 val = sa.peekValue( 1837 com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion); 1838 if (val != null) { 1839 if (val.type == TypedValue.TYPE_STRING && val.string != null) { 1840 targetCode = minCode = val.string.toString(); 1841 } else { 1842 // If it's not a string, it's an integer. 1843 targetVers = val.data; 1844 } 1845 } 1846 1847 sa.recycle(); 1848 1849 if (minCode != null) { 1850 boolean allowedCodename = false; 1851 for (String codename : SDK_CODENAMES) { 1852 if (minCode.equals(codename)) { 1853 allowedCodename = true; 1854 break; 1855 } 1856 } 1857 if (!allowedCodename) { 1858 if (SDK_CODENAMES.length > 0) { 1859 outError[0] = "Requires development platform " + minCode 1860 + " (current platform is any of " 1861 + Arrays.toString(SDK_CODENAMES) + ")"; 1862 } else { 1863 outError[0] = "Requires development platform " + minCode 1864 + " but this is a release platform."; 1865 } 1866 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1867 return null; 1868 } 1869 } else if (minVers > SDK_VERSION) { 1870 outError[0] = "Requires newer sdk version #" + minVers 1871 + " (current version is #" + SDK_VERSION + ")"; 1872 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1873 return null; 1874 } 1875 1876 if (targetCode != null) { 1877 boolean allowedCodename = false; 1878 for (String codename : SDK_CODENAMES) { 1879 if (targetCode.equals(codename)) { 1880 allowedCodename = true; 1881 break; 1882 } 1883 } 1884 if (!allowedCodename) { 1885 if (SDK_CODENAMES.length > 0) { 1886 outError[0] = "Requires development platform " + targetCode 1887 + " (current platform is any of " 1888 + Arrays.toString(SDK_CODENAMES) + ")"; 1889 } else { 1890 outError[0] = "Requires development platform " + targetCode 1891 + " but this is a release platform."; 1892 } 1893 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK; 1894 return null; 1895 } 1896 // If the code matches, it definitely targets this SDK. 1897 pkg.applicationInfo.targetSdkVersion 1898 = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; 1899 } else { 1900 pkg.applicationInfo.targetSdkVersion = targetVers; 1901 } 1902 } 1903 1904 XmlUtils.skipCurrentTag(parser); 1905 1906 } else if (tagName.equals(TAG_SUPPORT_SCREENS)) { 1907 sa = res.obtainAttributes(parser, 1908 com.android.internal.R.styleable.AndroidManifestSupportsScreens); 1909 1910 pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger( 1911 com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, 1912 0); 1913 pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger( 1914 com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, 1915 0); 1916 pkg.applicationInfo.largestWidthLimitDp = sa.getInteger( 1917 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, 1918 0); 1919 1920 // This is a trick to get a boolean and still able to detect 1921 // if a value was actually set. 1922 supportsSmallScreens = sa.getInteger( 1923 com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens, 1924 supportsSmallScreens); 1925 supportsNormalScreens = sa.getInteger( 1926 com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens, 1927 supportsNormalScreens); 1928 supportsLargeScreens = sa.getInteger( 1929 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens, 1930 supportsLargeScreens); 1931 supportsXLargeScreens = sa.getInteger( 1932 com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1933 supportsXLargeScreens); 1934 resizeable = sa.getInteger( 1935 com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable, 1936 resizeable); 1937 anyDensity = sa.getInteger( 1938 com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity, 1939 anyDensity); 1940 1941 sa.recycle(); 1942 1943 XmlUtils.skipCurrentTag(parser); 1944 1945 } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) { 1946 sa = res.obtainAttributes(parser, 1947 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast); 1948 1949 // Note: don't allow this value to be a reference to a resource 1950 // that may change. 1951 String name = sa.getNonResourceString( 1952 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name); 1953 1954 sa.recycle(); 1955 1956 if (name != null && (flags&PARSE_IS_SYSTEM) != 0) { 1957 if (pkg.protectedBroadcasts == null) { 1958 pkg.protectedBroadcasts = new ArrayList<String>(); 1959 } 1960 if (!pkg.protectedBroadcasts.contains(name)) { 1961 pkg.protectedBroadcasts.add(name.intern()); 1962 } 1963 } 1964 1965 XmlUtils.skipCurrentTag(parser); 1966 1967 } else if (tagName.equals(TAG_INSTRUMENTATION)) { 1968 if (parseInstrumentation(pkg, res, parser, outError) == null) { 1969 return null; 1970 } 1971 } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) { 1972 sa = res.obtainAttributes(parser, 1973 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 1974 1975 String orig =sa.getNonConfigurationString( 1976 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 1977 if (!pkg.packageName.equals(orig)) { 1978 if (pkg.mOriginalPackages == null) { 1979 pkg.mOriginalPackages = new ArrayList<String>(); 1980 pkg.mRealPackage = pkg.packageName; 1981 } 1982 pkg.mOriginalPackages.add(orig); 1983 } 1984 1985 sa.recycle(); 1986 1987 XmlUtils.skipCurrentTag(parser); 1988 1989 } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) { 1990 sa = res.obtainAttributes(parser, 1991 com.android.internal.R.styleable.AndroidManifestOriginalPackage); 1992 1993 String name = sa.getNonConfigurationString( 1994 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0); 1995 1996 sa.recycle(); 1997 1998 if (name != null) { 1999 if (pkg.mAdoptPermissions == null) { 2000 pkg.mAdoptPermissions = new ArrayList<String>(); 2001 } 2002 pkg.mAdoptPermissions.add(name); 2003 } 2004 2005 XmlUtils.skipCurrentTag(parser); 2006 2007 } else if (tagName.equals(TAG_USES_GL_TEXTURE)) { 2008 // Just skip this tag 2009 XmlUtils.skipCurrentTag(parser); 2010 continue; 2011 2012 } else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) { 2013 // Just skip this tag 2014 XmlUtils.skipCurrentTag(parser); 2015 continue; 2016 } else if (tagName.equals(TAG_SUPPORTS_INPUT)) {// 2017 XmlUtils.skipCurrentTag(parser); 2018 continue; 2019 2020 } else if (tagName.equals(TAG_EAT_COMMENT)) { 2021 // Just skip this tag 2022 XmlUtils.skipCurrentTag(parser); 2023 continue; 2024 2025 } else if (tagName.equals(TAG_PACKAGE)) { 2026 if (!parseBaseApkChild(pkg, res, parser, flags, outError)) { 2027 // If parsing a child failed the error is already set 2028 return null; 2029 } 2030 } else if (RIGID_PARSER) { 2031 outError[0] = "Bad element under <manifest>: " 2032 + parser.getName(); 2033 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2034 return null; 2035 2036 } else { 2037 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() 2038 + " at " + mArchiveSourcePath + " " 2039 + parser.getPositionDescription()); 2040 XmlUtils.skipCurrentTag(parser); 2041 continue; 2042 } 2043 } 2044 2045 if (!foundApp && pkg.instrumentation.size() == 0) { 2046 outError[0] = "<manifest> does not contain an <application> or <instrumentation>"; 2047 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; 2048 } 2049 2050 final int NP = PackageParser.NEW_PERMISSIONS.length; 2051 StringBuilder implicitPerms = null; 2052 for (int ip=0; ip<NP; ip++) { 2053 final PackageParser.NewPermissionInfo npi 2054 = PackageParser.NEW_PERMISSIONS[ip]; 2055 if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) { 2056 break; 2057 } 2058 if (!pkg.requestedPermissions.contains(npi.name)) { 2059 if (implicitPerms == null) { 2060 implicitPerms = new StringBuilder(128); 2061 implicitPerms.append(pkg.packageName); 2062 implicitPerms.append(": compat added "); 2063 } else { 2064 implicitPerms.append(' '); 2065 } 2066 implicitPerms.append(npi.name); 2067 pkg.requestedPermissions.add(npi.name); 2068 } 2069 } 2070 if (implicitPerms != null) { 2071 Slog.i(TAG, implicitPerms.toString()); 2072 } 2073 2074 final int NS = PackageParser.SPLIT_PERMISSIONS.length; 2075 for (int is=0; is<NS; is++) { 2076 final PackageParser.SplitPermissionInfo spi 2077 = PackageParser.SPLIT_PERMISSIONS[is]; 2078 if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk 2079 || !pkg.requestedPermissions.contains(spi.rootPerm)) { 2080 continue; 2081 } 2082 for (int in=0; in<spi.newPerms.length; in++) { 2083 final String perm = spi.newPerms[in]; 2084 if (!pkg.requestedPermissions.contains(perm)) { 2085 pkg.requestedPermissions.add(perm); 2086 } 2087 } 2088 } 2089 2090 if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 2091 && pkg.applicationInfo.targetSdkVersion 2092 >= android.os.Build.VERSION_CODES.DONUT)) { 2093 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; 2094 } 2095 if (supportsNormalScreens != 0) { 2096 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; 2097 } 2098 if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 2099 && pkg.applicationInfo.targetSdkVersion 2100 >= android.os.Build.VERSION_CODES.DONUT)) { 2101 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; 2102 } 2103 if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 2104 && pkg.applicationInfo.targetSdkVersion 2105 >= android.os.Build.VERSION_CODES.GINGERBREAD)) { 2106 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; 2107 } 2108 if (resizeable < 0 || (resizeable > 0 2109 && pkg.applicationInfo.targetSdkVersion 2110 >= android.os.Build.VERSION_CODES.DONUT)) { 2111 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; 2112 } 2113 if (anyDensity < 0 || (anyDensity > 0 2114 && pkg.applicationInfo.targetSdkVersion 2115 >= android.os.Build.VERSION_CODES.DONUT)) { 2116 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; 2117 } 2118 2119 return pkg; 2120 } 2121 2122 private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs) { 2123 FeatureInfo fi = new FeatureInfo(); 2124 TypedArray sa = res.obtainAttributes(attrs, 2125 com.android.internal.R.styleable.AndroidManifestUsesFeature); 2126 // Note: don't allow this value to be a reference to a resource 2127 // that may change. 2128 fi.name = sa.getNonResourceString( 2129 com.android.internal.R.styleable.AndroidManifestUsesFeature_name); 2130 if (fi.name == null) { 2131 fi.reqGlEsVersion = sa.getInt( 2132 com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion, 2133 FeatureInfo.GL_ES_VERSION_UNDEFINED); 2134 } 2135 if (sa.getBoolean( 2136 com.android.internal.R.styleable.AndroidManifestUsesFeature_required, true)) { 2137 fi.flags |= FeatureInfo.FLAG_REQUIRED; 2138 } 2139 sa.recycle(); 2140 return fi; 2141 } 2142 2143 private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser) 2144 throws XmlPullParserException, IOException { 2145 TypedArray sa = res.obtainAttributes(parser, 2146 com.android.internal.R.styleable.AndroidManifestUsesPermission); 2147 2148 // Note: don't allow this value to be a reference to a resource 2149 // that may change. 2150 String name = sa.getNonResourceString( 2151 com.android.internal.R.styleable.AndroidManifestUsesPermission_name); 2152 2153 int maxSdkVersion = 0; 2154 TypedValue val = sa.peekValue( 2155 com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion); 2156 if (val != null) { 2157 if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) { 2158 maxSdkVersion = val.data; 2159 } 2160 } 2161 2162 sa.recycle(); 2163 2164 if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) { 2165 if (name != null) { 2166 int index = pkg.requestedPermissions.indexOf(name); 2167 if (index == -1) { 2168 pkg.requestedPermissions.add(name.intern()); 2169 } else { 2170 Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: " 2171 + name + " in package: " + pkg.packageName + " at: " 2172 + parser.getPositionDescription()); 2173 } 2174 } 2175 } 2176 2177 XmlUtils.skipCurrentTag(parser); 2178 return true; 2179 } 2180 2181 private static String buildClassName(String pkg, CharSequence clsSeq, 2182 String[] outError) { 2183 if (clsSeq == null || clsSeq.length() <= 0) { 2184 outError[0] = "Empty class name in package " + pkg; 2185 return null; 2186 } 2187 String cls = clsSeq.toString(); 2188 char c = cls.charAt(0); 2189 if (c == '.') { 2190 return (pkg + cls).intern(); 2191 } 2192 if (cls.indexOf('.') < 0) { 2193 StringBuilder b = new StringBuilder(pkg); 2194 b.append('.'); 2195 b.append(cls); 2196 return b.toString().intern(); 2197 } 2198 if (c >= 'a' && c <= 'z') { 2199 return cls.intern(); 2200 } 2201 outError[0] = "Bad class name " + cls + " in package " + pkg; 2202 return null; 2203 } 2204 2205 private static String buildCompoundName(String pkg, 2206 CharSequence procSeq, String type, String[] outError) { 2207 String proc = procSeq.toString(); 2208 char c = proc.charAt(0); 2209 if (pkg != null && c == ':') { 2210 if (proc.length() < 2) { 2211 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg 2212 + ": must be at least two characters"; 2213 return null; 2214 } 2215 String subName = proc.substring(1); 2216 String nameError = validateName(subName, false, false); 2217 if (nameError != null) { 2218 outError[0] = "Invalid " + type + " name " + proc + " in package " 2219 + pkg + ": " + nameError; 2220 return null; 2221 } 2222 return (pkg + proc).intern(); 2223 } 2224 String nameError = validateName(proc, true, false); 2225 if (nameError != null && !"system".equals(proc)) { 2226 outError[0] = "Invalid " + type + " name " + proc + " in package " 2227 + pkg + ": " + nameError; 2228 return null; 2229 } 2230 return proc.intern(); 2231 } 2232 2233 private static String buildProcessName(String pkg, String defProc, 2234 CharSequence procSeq, int flags, String[] separateProcesses, 2235 String[] outError) { 2236 if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) { 2237 return defProc != null ? defProc : pkg; 2238 } 2239 if (separateProcesses != null) { 2240 for (int i=separateProcesses.length-1; i>=0; i--) { 2241 String sp = separateProcesses[i]; 2242 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) { 2243 return pkg; 2244 } 2245 } 2246 } 2247 if (procSeq == null || procSeq.length() <= 0) { 2248 return defProc; 2249 } 2250 return buildCompoundName(pkg, procSeq, "process", outError); 2251 } 2252 2253 private static String buildTaskAffinityName(String pkg, String defProc, 2254 CharSequence procSeq, String[] outError) { 2255 if (procSeq == null) { 2256 return defProc; 2257 } 2258 if (procSeq.length() <= 0) { 2259 return null; 2260 } 2261 return buildCompoundName(pkg, procSeq, "taskAffinity", outError); 2262 } 2263 2264 private boolean parseKeySets(Package owner, Resources res, 2265 XmlResourceParser parser, String[] outError) 2266 throws XmlPullParserException, IOException { 2267 // we've encountered the 'key-sets' tag 2268 // all the keys and keysets that we want must be defined here 2269 // so we're going to iterate over the parser and pull out the things we want 2270 int outerDepth = parser.getDepth(); 2271 int currentKeySetDepth = -1; 2272 int type; 2273 String currentKeySet = null; 2274 ArrayMap<String, PublicKey> publicKeys = new ArrayMap<String, PublicKey>(); 2275 ArraySet<String> upgradeKeySets = new ArraySet<String>(); 2276 ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<String, ArraySet<String>>(); 2277 ArraySet<String> improperKeySets = new ArraySet<String>(); 2278 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 2279 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 2280 if (type == XmlPullParser.END_TAG) { 2281 if (parser.getDepth() == currentKeySetDepth) { 2282 currentKeySet = null; 2283 currentKeySetDepth = -1; 2284 } 2285 continue; 2286 } 2287 String tagName = parser.getName(); 2288 if (tagName.equals("key-set")) { 2289 if (currentKeySet != null) { 2290 outError[0] = "Improperly nested 'key-set' tag at " 2291 + parser.getPositionDescription(); 2292 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2293 return false; 2294 } 2295 final TypedArray sa = res.obtainAttributes(parser, 2296 com.android.internal.R.styleable.AndroidManifestKeySet); 2297 final String keysetName = sa.getNonResourceString( 2298 com.android.internal.R.styleable.AndroidManifestKeySet_name); 2299 definedKeySets.put(keysetName, new ArraySet<String>()); 2300 currentKeySet = keysetName; 2301 currentKeySetDepth = parser.getDepth(); 2302 sa.recycle(); 2303 } else if (tagName.equals("public-key")) { 2304 if (currentKeySet == null) { 2305 outError[0] = "Improperly nested 'key-set' tag at " 2306 + parser.getPositionDescription(); 2307 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2308 return false; 2309 } 2310 final TypedArray sa = res.obtainAttributes(parser, 2311 com.android.internal.R.styleable.AndroidManifestPublicKey); 2312 final String publicKeyName = sa.getNonResourceString( 2313 com.android.internal.R.styleable.AndroidManifestPublicKey_name); 2314 final String encodedKey = sa.getNonResourceString( 2315 com.android.internal.R.styleable.AndroidManifestPublicKey_value); 2316 if (encodedKey == null && publicKeys.get(publicKeyName) == null) { 2317 outError[0] = "'public-key' " + publicKeyName + " must define a public-key value" 2318 + " on first use at " + parser.getPositionDescription(); 2319 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2320 sa.recycle(); 2321 return false; 2322 } else if (encodedKey != null) { 2323 PublicKey currentKey = parsePublicKey(encodedKey); 2324 if (currentKey == null) { 2325 Slog.w(TAG, "No recognized valid key in 'public-key' tag at " 2326 + parser.getPositionDescription() + " key-set " + currentKeySet 2327 + " will not be added to the package's defined key-sets."); 2328 sa.recycle(); 2329 improperKeySets.add(currentKeySet); 2330 XmlUtils.skipCurrentTag(parser); 2331 continue; 2332 } 2333 if (publicKeys.get(publicKeyName) == null 2334 || publicKeys.get(publicKeyName).equals(currentKey)) { 2335 2336 /* public-key first definition, or matches old definition */ 2337 publicKeys.put(publicKeyName, currentKey); 2338 } else { 2339 outError[0] = "Value of 'public-key' " + publicKeyName 2340 + " conflicts with previously defined value at " 2341 + parser.getPositionDescription(); 2342 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2343 sa.recycle(); 2344 return false; 2345 } 2346 } 2347 definedKeySets.get(currentKeySet).add(publicKeyName); 2348 sa.recycle(); 2349 XmlUtils.skipCurrentTag(parser); 2350 } else if (tagName.equals("upgrade-key-set")) { 2351 final TypedArray sa = res.obtainAttributes(parser, 2352 com.android.internal.R.styleable.AndroidManifestUpgradeKeySet); 2353 String name = sa.getNonResourceString( 2354 com.android.internal.R.styleable.AndroidManifestUpgradeKeySet_name); 2355 upgradeKeySets.add(name); 2356 sa.recycle(); 2357 XmlUtils.skipCurrentTag(parser); 2358 } else if (RIGID_PARSER) { 2359 outError[0] = "Bad element under <key-sets>: " + parser.getName() 2360 + " at " + mArchiveSourcePath + " " 2361 + parser.getPositionDescription(); 2362 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2363 return false; 2364 } else { 2365 Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName() 2366 + " at " + mArchiveSourcePath + " " 2367 + parser.getPositionDescription()); 2368 XmlUtils.skipCurrentTag(parser); 2369 continue; 2370 } 2371 } 2372 Set<String> publicKeyNames = publicKeys.keySet(); 2373 if (publicKeyNames.removeAll(definedKeySets.keySet())) { 2374 outError[0] = "Package" + owner.packageName + " AndroidManifext.xml " 2375 + "'key-set' and 'public-key' names must be distinct."; 2376 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2377 return false; 2378 } 2379 owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>(); 2380 for (ArrayMap.Entry<String, ArraySet<String>> e: definedKeySets.entrySet()) { 2381 final String keySetName = e.getKey(); 2382 if (e.getValue().size() == 0) { 2383 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml " 2384 + "'key-set' " + keySetName + " has no valid associated 'public-key'." 2385 + " Not including in package's defined key-sets."); 2386 continue; 2387 } else if (improperKeySets.contains(keySetName)) { 2388 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml " 2389 + "'key-set' " + keySetName + " contained improper 'public-key'" 2390 + " tags. Not including in package's defined key-sets."); 2391 continue; 2392 } 2393 owner.mKeySetMapping.put(keySetName, new ArraySet<PublicKey>()); 2394 for (String s : e.getValue()) { 2395 owner.mKeySetMapping.get(keySetName).add(publicKeys.get(s)); 2396 } 2397 } 2398 if (owner.mKeySetMapping.keySet().containsAll(upgradeKeySets)) { 2399 owner.mUpgradeKeySets = upgradeKeySets; 2400 } else { 2401 outError[0] ="Package" + owner.packageName + " AndroidManifext.xml " 2402 + "does not define all 'upgrade-key-set's ."; 2403 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2404 return false; 2405 } 2406 return true; 2407 } 2408 2409 private PermissionGroup parsePermissionGroup(Package owner, int flags, Resources res, 2410 XmlResourceParser parser, String[] outError) 2411 throws XmlPullParserException, IOException { 2412 PermissionGroup perm = new PermissionGroup(owner); 2413 2414 TypedArray sa = res.obtainAttributes(parser, 2415 com.android.internal.R.styleable.AndroidManifestPermissionGroup); 2416 2417 if (!parsePackageItemInfo(owner, perm.info, outError, 2418 "<permission-group>", sa, 2419 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name, 2420 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label, 2421 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon, 2422 com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo, 2423 com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) { 2424 sa.recycle(); 2425 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2426 return null; 2427 } 2428 2429 perm.info.descriptionRes = sa.getResourceId( 2430 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description, 2431 0); 2432 perm.info.flags = sa.getInt( 2433 com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0); 2434 perm.info.priority = sa.getInt( 2435 com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0); 2436 if (perm.info.priority > 0 && (flags&PARSE_IS_SYSTEM) == 0) { 2437 perm.info.priority = 0; 2438 } 2439 2440 sa.recycle(); 2441 2442 if (!parseAllMetaData(res, parser, "<permission-group>", perm, 2443 outError)) { 2444 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2445 return null; 2446 } 2447 2448 owner.permissionGroups.add(perm); 2449 2450 return perm; 2451 } 2452 2453 private Permission parsePermission(Package owner, Resources res, 2454 XmlResourceParser parser, String[] outError) 2455 throws XmlPullParserException, IOException { 2456 Permission perm = new Permission(owner); 2457 2458 TypedArray sa = res.obtainAttributes(parser, 2459 com.android.internal.R.styleable.AndroidManifestPermission); 2460 2461 if (!parsePackageItemInfo(owner, perm.info, outError, 2462 "<permission>", sa, 2463 com.android.internal.R.styleable.AndroidManifestPermission_name, 2464 com.android.internal.R.styleable.AndroidManifestPermission_label, 2465 com.android.internal.R.styleable.AndroidManifestPermission_icon, 2466 com.android.internal.R.styleable.AndroidManifestPermission_logo, 2467 com.android.internal.R.styleable.AndroidManifestPermission_banner)) { 2468 sa.recycle(); 2469 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2470 return null; 2471 } 2472 2473 // Note: don't allow this value to be a reference to a resource 2474 // that may change. 2475 perm.info.group = sa.getNonResourceString( 2476 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup); 2477 if (perm.info.group != null) { 2478 perm.info.group = perm.info.group.intern(); 2479 } 2480 2481 perm.info.descriptionRes = sa.getResourceId( 2482 com.android.internal.R.styleable.AndroidManifestPermission_description, 2483 0); 2484 2485 perm.info.protectionLevel = sa.getInt( 2486 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel, 2487 PermissionInfo.PROTECTION_NORMAL); 2488 2489 perm.info.flags = sa.getInt( 2490 com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0); 2491 2492 sa.recycle(); 2493 2494 if (perm.info.protectionLevel == -1) { 2495 outError[0] = "<permission> does not specify protectionLevel"; 2496 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2497 return null; 2498 } 2499 2500 perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel); 2501 2502 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) { 2503 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) != 2504 PermissionInfo.PROTECTION_SIGNATURE) { 2505 outError[0] = "<permission> protectionLevel specifies a flag but is " 2506 + "not based on signature type"; 2507 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2508 return null; 2509 } 2510 } 2511 2512 if (!parseAllMetaData(res, parser, "<permission>", perm, outError)) { 2513 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2514 return null; 2515 } 2516 2517 owner.permissions.add(perm); 2518 2519 return perm; 2520 } 2521 2522 private Permission parsePermissionTree(Package owner, Resources res, 2523 XmlResourceParser parser, String[] outError) 2524 throws XmlPullParserException, IOException { 2525 Permission perm = new Permission(owner); 2526 2527 TypedArray sa = res.obtainAttributes(parser, 2528 com.android.internal.R.styleable.AndroidManifestPermissionTree); 2529 2530 if (!parsePackageItemInfo(owner, perm.info, outError, 2531 "<permission-tree>", sa, 2532 com.android.internal.R.styleable.AndroidManifestPermissionTree_name, 2533 com.android.internal.R.styleable.AndroidManifestPermissionTree_label, 2534 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon, 2535 com.android.internal.R.styleable.AndroidManifestPermissionTree_logo, 2536 com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) { 2537 sa.recycle(); 2538 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2539 return null; 2540 } 2541 2542 sa.recycle(); 2543 2544 int index = perm.info.name.indexOf('.'); 2545 if (index > 0) { 2546 index = perm.info.name.indexOf('.', index+1); 2547 } 2548 if (index < 0) { 2549 outError[0] = "<permission-tree> name has less than three segments: " 2550 + perm.info.name; 2551 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2552 return null; 2553 } 2554 2555 perm.info.descriptionRes = 0; 2556 perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL; 2557 perm.tree = true; 2558 2559 if (!parseAllMetaData(res, parser, "<permission-tree>", perm, 2560 outError)) { 2561 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2562 return null; 2563 } 2564 2565 owner.permissions.add(perm); 2566 2567 return perm; 2568 } 2569 2570 private Instrumentation parseInstrumentation(Package owner, Resources res, 2571 XmlResourceParser parser, String[] outError) 2572 throws XmlPullParserException, IOException { 2573 TypedArray sa = res.obtainAttributes(parser, 2574 com.android.internal.R.styleable.AndroidManifestInstrumentation); 2575 2576 if (mParseInstrumentationArgs == null) { 2577 mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError, 2578 com.android.internal.R.styleable.AndroidManifestInstrumentation_name, 2579 com.android.internal.R.styleable.AndroidManifestInstrumentation_label, 2580 com.android.internal.R.styleable.AndroidManifestInstrumentation_icon, 2581 com.android.internal.R.styleable.AndroidManifestInstrumentation_logo, 2582 com.android.internal.R.styleable.AndroidManifestInstrumentation_banner); 2583 mParseInstrumentationArgs.tag = "<instrumentation>"; 2584 } 2585 2586 mParseInstrumentationArgs.sa = sa; 2587 2588 Instrumentation a = new Instrumentation(mParseInstrumentationArgs, 2589 new InstrumentationInfo()); 2590 if (outError[0] != null) { 2591 sa.recycle(); 2592 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2593 return null; 2594 } 2595 2596 String str; 2597 // Note: don't allow this value to be a reference to a resource 2598 // that may change. 2599 str = sa.getNonResourceString( 2600 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage); 2601 a.info.targetPackage = str != null ? str.intern() : null; 2602 2603 a.info.handleProfiling = sa.getBoolean( 2604 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling, 2605 false); 2606 2607 a.info.functionalTest = sa.getBoolean( 2608 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest, 2609 false); 2610 2611 sa.recycle(); 2612 2613 if (a.info.targetPackage == null) { 2614 outError[0] = "<instrumentation> does not specify targetPackage"; 2615 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2616 return null; 2617 } 2618 2619 if (!parseAllMetaData(res, parser, "<instrumentation>", a, 2620 outError)) { 2621 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2622 return null; 2623 } 2624 2625 owner.instrumentation.add(a); 2626 2627 return a; 2628 } 2629 2630 /** 2631 * Parse the {@code application} XML tree at the current parse location in a 2632 * <em>base APK</em> manifest. 2633 * <p> 2634 * When adding new features, carefully consider if they should also be 2635 * supported by split APKs. 2636 */ 2637 private boolean parseBaseApplication(Package owner, Resources res, 2638 XmlResourceParser parser, int flags, String[] outError) 2639 throws XmlPullParserException, IOException { 2640 final ApplicationInfo ai = owner.applicationInfo; 2641 final String pkgName = owner.applicationInfo.packageName; 2642 2643 TypedArray sa = res.obtainAttributes(parser, 2644 com.android.internal.R.styleable.AndroidManifestApplication); 2645 2646 String name = sa.getNonConfigurationString( 2647 com.android.internal.R.styleable.AndroidManifestApplication_name, 0); 2648 if (name != null) { 2649 ai.className = buildClassName(pkgName, name, outError); 2650 if (ai.className == null) { 2651 sa.recycle(); 2652 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2653 return false; 2654 } 2655 } 2656 2657 String manageSpaceActivity = sa.getNonConfigurationString( 2658 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity, 2659 Configuration.NATIVE_CONFIG_VERSION); 2660 if (manageSpaceActivity != null) { 2661 ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity, 2662 outError); 2663 } 2664 2665 boolean allowBackup = sa.getBoolean( 2666 com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true); 2667 if (allowBackup) { 2668 ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; 2669 2670 // backupAgent, killAfterRestore, fullBackupContent and restoreAnyVersion are only 2671 // relevant if backup is possible for the given application. 2672 String backupAgent = sa.getNonConfigurationString( 2673 com.android.internal.R.styleable.AndroidManifestApplication_backupAgent, 2674 Configuration.NATIVE_CONFIG_VERSION); 2675 if (backupAgent != null) { 2676 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError); 2677 if (DEBUG_BACKUP) { 2678 Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName 2679 + " from " + pkgName + "+" + backupAgent); 2680 } 2681 2682 if (sa.getBoolean( 2683 com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore, 2684 true)) { 2685 ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE; 2686 } 2687 if (sa.getBoolean( 2688 com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion, 2689 false)) { 2690 ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION; 2691 } 2692 if (sa.getBoolean( 2693 com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly, 2694 false)) { 2695 ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY; 2696 } 2697 } 2698 2699 TypedValue v = sa.peekValue( 2700 com.android.internal.R.styleable.AndroidManifestApplication_fullBackupContent); 2701 if (v != null && (ai.fullBackupContent = v.resourceId) == 0) { 2702 if (DEBUG_BACKUP) { 2703 Slog.v(TAG, "fullBackupContent specified as boolean=" + 2704 (v.data == 0 ? "false" : "true")); 2705 } 2706 // "false" => -1, "true" => 0 2707 ai.fullBackupContent = (v.data == 0 ? -1 : 0); 2708 } 2709 if (DEBUG_BACKUP) { 2710 Slog.v(TAG, "fullBackupContent=" + ai.fullBackupContent + " for " + pkgName); 2711 } 2712 } 2713 2714 TypedValue v = sa.peekValue( 2715 com.android.internal.R.styleable.AndroidManifestApplication_label); 2716 if (v != null && (ai.labelRes=v.resourceId) == 0) { 2717 ai.nonLocalizedLabel = v.coerceToString(); 2718 } 2719 2720 ai.icon = sa.getResourceId( 2721 com.android.internal.R.styleable.AndroidManifestApplication_icon, 0); 2722 ai.logo = sa.getResourceId( 2723 com.android.internal.R.styleable.AndroidManifestApplication_logo, 0); 2724 ai.banner = sa.getResourceId( 2725 com.android.internal.R.styleable.AndroidManifestApplication_banner, 0); 2726 ai.theme = sa.getResourceId( 2727 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); 2728 ai.descriptionRes = sa.getResourceId( 2729 com.android.internal.R.styleable.AndroidManifestApplication_description, 0); 2730 2731 if ((flags&PARSE_IS_SYSTEM) != 0) { 2732 if (sa.getBoolean( 2733 com.android.internal.R.styleable.AndroidManifestApplication_persistent, 2734 false)) { 2735 ai.flags |= ApplicationInfo.FLAG_PERSISTENT; 2736 } 2737 } 2738 2739 if (sa.getBoolean( 2740 com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers, 2741 false)) { 2742 owner.mRequiredForAllUsers = true; 2743 } 2744 2745 String restrictedAccountType = sa.getString(com.android.internal.R.styleable 2746 .AndroidManifestApplication_restrictedAccountType); 2747 if (restrictedAccountType != null && restrictedAccountType.length() > 0) { 2748 owner.mRestrictedAccountType = restrictedAccountType; 2749 } 2750 2751 String requiredAccountType = sa.getString(com.android.internal.R.styleable 2752 .AndroidManifestApplication_requiredAccountType); 2753 if (requiredAccountType != null && requiredAccountType.length() > 0) { 2754 owner.mRequiredAccountType = requiredAccountType; 2755 } 2756 2757 if (sa.getBoolean( 2758 com.android.internal.R.styleable.AndroidManifestApplication_debuggable, 2759 false)) { 2760 ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE; 2761 } 2762 2763 if (sa.getBoolean( 2764 com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode, 2765 false)) { 2766 ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE; 2767 } 2768 2769 owner.baseHardwareAccelerated = sa.getBoolean( 2770 com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated, 2771 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH); 2772 if (owner.baseHardwareAccelerated) { 2773 ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED; 2774 } 2775 2776 if (sa.getBoolean( 2777 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, 2778 true)) { 2779 ai.flags |= ApplicationInfo.FLAG_HAS_CODE; 2780 } 2781 2782 if (sa.getBoolean( 2783 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting, 2784 false)) { 2785 ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; 2786 } 2787 2788 if (sa.getBoolean( 2789 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData, 2790 true)) { 2791 ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; 2792 } 2793 2794 // The parent package controls installation, hence specify test only installs. 2795 if (owner.parentPackage == null) { 2796 if (sa.getBoolean( 2797 com.android.internal.R.styleable.AndroidManifestApplication_testOnly, 2798 false)) { 2799 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY; 2800 } 2801 } 2802 2803 if (sa.getBoolean( 2804 com.android.internal.R.styleable.AndroidManifestApplication_largeHeap, 2805 false)) { 2806 ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP; 2807 } 2808 2809 if (sa.getBoolean( 2810 com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic, 2811 true)) { 2812 ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC; 2813 } 2814 2815 if (sa.getBoolean( 2816 com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl, 2817 false /* default is no RTL support*/)) { 2818 ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL; 2819 } 2820 2821 if (sa.getBoolean( 2822 com.android.internal.R.styleable.AndroidManifestApplication_multiArch, 2823 false)) { 2824 ai.flags |= ApplicationInfo.FLAG_MULTIARCH; 2825 } 2826 2827 if (sa.getBoolean( 2828 com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs, 2829 true)) { 2830 ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS; 2831 } 2832 2833 if (sa.getBoolean(R.styleable.AndroidManifestApplication_forceDeviceEncrypted, false) 2834 && (flags & PARSE_IS_SYSTEM) != 0) { 2835 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED; 2836 } 2837 if (sa.getBoolean(R.styleable.AndroidManifestApplication_encryptionAware, false) 2838 && (flags & PARSE_IS_SYSTEM) != 0) { 2839 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ENCRYPTION_AWARE; 2840 } 2841 2842 if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity, 2843 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N)) { 2844 ai.privateFlags |= PRIVATE_FLAG_RESIZEABLE_ACTIVITIES; 2845 } 2846 2847 String str; 2848 str = sa.getNonConfigurationString( 2849 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0); 2850 ai.permission = (str != null && str.length() > 0) ? str.intern() : null; 2851 2852 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 2853 str = sa.getNonConfigurationString( 2854 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, 2855 Configuration.NATIVE_CONFIG_VERSION); 2856 } else { 2857 // Some older apps have been seen to use a resource reference 2858 // here that on older builds was ignored (with a warning). We 2859 // need to continue to do this for them so they don't break. 2860 str = sa.getNonResourceString( 2861 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity); 2862 } 2863 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName, 2864 str, outError); 2865 2866 if (outError[0] == null) { 2867 CharSequence pname; 2868 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 2869 pname = sa.getNonConfigurationString( 2870 com.android.internal.R.styleable.AndroidManifestApplication_process, 2871 Configuration.NATIVE_CONFIG_VERSION); 2872 } else { 2873 // Some older apps have been seen to use a resource reference 2874 // here that on older builds was ignored (with a warning). We 2875 // need to continue to do this for them so they don't break. 2876 pname = sa.getNonResourceString( 2877 com.android.internal.R.styleable.AndroidManifestApplication_process); 2878 } 2879 ai.processName = buildProcessName(ai.packageName, null, pname, 2880 flags, mSeparateProcesses, outError); 2881 2882 ai.enabled = sa.getBoolean( 2883 com.android.internal.R.styleable.AndroidManifestApplication_enabled, true); 2884 2885 if (sa.getBoolean( 2886 com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) { 2887 ai.flags |= ApplicationInfo.FLAG_IS_GAME; 2888 } 2889 2890 if (false) { 2891 if (sa.getBoolean( 2892 com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState, 2893 false)) { 2894 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE; 2895 2896 // A heavy-weight application can not be in a custom process. 2897 // We can do direct compare because we intern all strings. 2898 if (ai.processName != null && ai.processName != ai.packageName) { 2899 outError[0] = "cantSaveState applications can not use custom processes"; 2900 } 2901 } 2902 } 2903 } 2904 2905 ai.uiOptions = sa.getInt( 2906 com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0); 2907 2908 sa.recycle(); 2909 2910 if (outError[0] != null) { 2911 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2912 return false; 2913 } 2914 2915 final int innerDepth = parser.getDepth(); 2916 int type; 2917 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 2918 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 2919 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2920 continue; 2921 } 2922 2923 String tagName = parser.getName(); 2924 if (tagName.equals("activity")) { 2925 Activity a = parseActivity(owner, res, parser, flags, outError, false, 2926 owner.baseHardwareAccelerated); 2927 if (a == null) { 2928 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2929 return false; 2930 } 2931 2932 owner.activities.add(a); 2933 2934 } else if (tagName.equals("receiver")) { 2935 Activity a = parseActivity(owner, res, parser, flags, outError, true, false); 2936 if (a == null) { 2937 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2938 return false; 2939 } 2940 2941 owner.receivers.add(a); 2942 2943 } else if (tagName.equals("service")) { 2944 Service s = parseService(owner, res, parser, flags, outError); 2945 if (s == null) { 2946 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2947 return false; 2948 } 2949 2950 owner.services.add(s); 2951 2952 } else if (tagName.equals("provider")) { 2953 Provider p = parseProvider(owner, res, parser, flags, outError); 2954 if (p == null) { 2955 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2956 return false; 2957 } 2958 2959 owner.providers.add(p); 2960 2961 } else if (tagName.equals("activity-alias")) { 2962 Activity a = parseActivityAlias(owner, res, parser, flags, outError); 2963 if (a == null) { 2964 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2965 return false; 2966 } 2967 2968 owner.activities.add(a); 2969 2970 } else if (parser.getName().equals("meta-data")) { 2971 // note: application meta-data is stored off to the side, so it can 2972 // remain null in the primary copy (we like to avoid extra copies because 2973 // it can be large) 2974 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData, 2975 outError)) == null) { 2976 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 2977 return false; 2978 } 2979 2980 } else if (tagName.equals("library")) { 2981 sa = res.obtainAttributes(parser, 2982 com.android.internal.R.styleable.AndroidManifestLibrary); 2983 2984 // Note: don't allow this value to be a reference to a resource 2985 // that may change. 2986 String lname = sa.getNonResourceString( 2987 com.android.internal.R.styleable.AndroidManifestLibrary_name); 2988 2989 sa.recycle(); 2990 2991 if (lname != null) { 2992 lname = lname.intern(); 2993 if (!ArrayUtils.contains(owner.libraryNames, lname)) { 2994 owner.libraryNames = ArrayUtils.add(owner.libraryNames, lname); 2995 } 2996 } 2997 2998 XmlUtils.skipCurrentTag(parser); 2999 3000 } else if (tagName.equals("uses-library")) { 3001 sa = res.obtainAttributes(parser, 3002 com.android.internal.R.styleable.AndroidManifestUsesLibrary); 3003 3004 // Note: don't allow this value to be a reference to a resource 3005 // that may change. 3006 String lname = sa.getNonResourceString( 3007 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 3008 boolean req = sa.getBoolean( 3009 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, 3010 true); 3011 3012 sa.recycle(); 3013 3014 if (lname != null) { 3015 lname = lname.intern(); 3016 if (req) { 3017 owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname); 3018 } else { 3019 owner.usesOptionalLibraries = ArrayUtils.add( 3020 owner.usesOptionalLibraries, lname); 3021 } 3022 } 3023 3024 XmlUtils.skipCurrentTag(parser); 3025 3026 } else if (tagName.equals("uses-package")) { 3027 // Dependencies for app installers; we don't currently try to 3028 // enforce this. 3029 XmlUtils.skipCurrentTag(parser); 3030 3031 } else { 3032 if (!RIGID_PARSER) { 3033 Slog.w(TAG, "Unknown element under <application>: " + tagName 3034 + " at " + mArchiveSourcePath + " " 3035 + parser.getPositionDescription()); 3036 XmlUtils.skipCurrentTag(parser); 3037 continue; 3038 } else { 3039 outError[0] = "Bad element under <application>: " + tagName; 3040 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3041 return false; 3042 } 3043 } 3044 } 3045 3046 modifySharedLibrariesForBackwardCompatibility(owner); 3047 3048 if (hasDomainURLs(owner)) { 3049 owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS; 3050 } else { 3051 owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS; 3052 } 3053 3054 return true; 3055 } 3056 3057 private static void modifySharedLibrariesForBackwardCompatibility(Package owner) { 3058 // "org.apache.http.legacy" is now a part of the boot classpath so it doesn't need 3059 // to be an explicit dependency. 3060 // 3061 // A future change will remove this library from the boot classpath, at which point 3062 // all apps that target SDK 21 and earlier will have it automatically added to their 3063 // dependency lists. 3064 owner.usesLibraries = ArrayUtils.remove(owner.usesLibraries, "org.apache.http.legacy"); 3065 owner.usesOptionalLibraries = ArrayUtils.remove(owner.usesOptionalLibraries, 3066 "org.apache.http.legacy"); 3067 } 3068 3069 /** 3070 * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI 3071 */ 3072 private static boolean hasDomainURLs(Package pkg) { 3073 if (pkg == null || pkg.activities == null) return false; 3074 final ArrayList<Activity> activities = pkg.activities; 3075 final int countActivities = activities.size(); 3076 for (int n=0; n<countActivities; n++) { 3077 Activity activity = activities.get(n); 3078 ArrayList<ActivityIntentInfo> filters = activity.intents; 3079 if (filters == null) continue; 3080 final int countFilters = filters.size(); 3081 for (int m=0; m<countFilters; m++) { 3082 ActivityIntentInfo aii = filters.get(m); 3083 if (!aii.hasAction(Intent.ACTION_VIEW)) continue; 3084 if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue; 3085 if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) || 3086 aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) { 3087 return true; 3088 } 3089 } 3090 } 3091 return false; 3092 } 3093 3094 /** 3095 * Parse the {@code application} XML tree at the current parse location in a 3096 * <em>split APK</em> manifest. 3097 * <p> 3098 * Note that split APKs have many more restrictions on what they're capable 3099 * of doing, so many valid features of a base APK have been carefully 3100 * omitted here. 3101 */ 3102 private boolean parseSplitApplication(Package owner, Resources res, XmlResourceParser parser, 3103 int flags, int splitIndex, String[] outError) 3104 throws XmlPullParserException, IOException { 3105 TypedArray sa = res.obtainAttributes(parser, 3106 com.android.internal.R.styleable.AndroidManifestApplication); 3107 3108 if (sa.getBoolean( 3109 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, true)) { 3110 owner.splitFlags[splitIndex] |= ApplicationInfo.FLAG_HAS_CODE; 3111 } 3112 3113 final int innerDepth = parser.getDepth(); 3114 int type; 3115 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 3116 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 3117 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3118 continue; 3119 } 3120 3121 String tagName = parser.getName(); 3122 if (tagName.equals("activity")) { 3123 Activity a = parseActivity(owner, res, parser, flags, outError, false, 3124 owner.baseHardwareAccelerated); 3125 if (a == null) { 3126 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3127 return false; 3128 } 3129 3130 owner.activities.add(a); 3131 3132 } else if (tagName.equals("receiver")) { 3133 Activity a = parseActivity(owner, res, parser, flags, outError, true, false); 3134 if (a == null) { 3135 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3136 return false; 3137 } 3138 3139 owner.receivers.add(a); 3140 3141 } else if (tagName.equals("service")) { 3142 Service s = parseService(owner, res, parser, flags, outError); 3143 if (s == null) { 3144 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3145 return false; 3146 } 3147 3148 owner.services.add(s); 3149 3150 } else if (tagName.equals("provider")) { 3151 Provider p = parseProvider(owner, res, parser, flags, outError); 3152 if (p == null) { 3153 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3154 return false; 3155 } 3156 3157 owner.providers.add(p); 3158 3159 } else if (tagName.equals("activity-alias")) { 3160 Activity a = parseActivityAlias(owner, res, parser, flags, outError); 3161 if (a == null) { 3162 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3163 return false; 3164 } 3165 3166 owner.activities.add(a); 3167 3168 } else if (parser.getName().equals("meta-data")) { 3169 // note: application meta-data is stored off to the side, so it can 3170 // remain null in the primary copy (we like to avoid extra copies because 3171 // it can be large) 3172 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData, 3173 outError)) == null) { 3174 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3175 return false; 3176 } 3177 3178 } else if (tagName.equals("uses-library")) { 3179 sa = res.obtainAttributes(parser, 3180 com.android.internal.R.styleable.AndroidManifestUsesLibrary); 3181 3182 // Note: don't allow this value to be a reference to a resource 3183 // that may change. 3184 String lname = sa.getNonResourceString( 3185 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name); 3186 boolean req = sa.getBoolean( 3187 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required, 3188 true); 3189 3190 sa.recycle(); 3191 3192 if (lname != null) { 3193 lname = lname.intern(); 3194 if (req) { 3195 // Upgrade to treat as stronger constraint 3196 owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname); 3197 owner.usesOptionalLibraries = ArrayUtils.remove( 3198 owner.usesOptionalLibraries, lname); 3199 } else { 3200 // Ignore if someone already defined as required 3201 if (!ArrayUtils.contains(owner.usesLibraries, lname)) { 3202 owner.usesOptionalLibraries = ArrayUtils.add( 3203 owner.usesOptionalLibraries, lname); 3204 } 3205 } 3206 } 3207 3208 XmlUtils.skipCurrentTag(parser); 3209 3210 } else if (tagName.equals("uses-package")) { 3211 // Dependencies for app installers; we don't currently try to 3212 // enforce this. 3213 XmlUtils.skipCurrentTag(parser); 3214 3215 } else { 3216 if (!RIGID_PARSER) { 3217 Slog.w(TAG, "Unknown element under <application>: " + tagName 3218 + " at " + mArchiveSourcePath + " " 3219 + parser.getPositionDescription()); 3220 XmlUtils.skipCurrentTag(parser); 3221 continue; 3222 } else { 3223 outError[0] = "Bad element under <application>: " + tagName; 3224 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; 3225 return false; 3226 } 3227 } 3228 } 3229 3230 return true; 3231 } 3232 3233 private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo, 3234 String[] outError, String tag, TypedArray sa, 3235 int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) { 3236 String name = sa.getNonConfigurationString(nameRes, 0); 3237 if (name == null) { 3238 outError[0] = tag + " does not specify android:name"; 3239 return false; 3240 } 3241 3242 outInfo.name 3243 = buildClassName(owner.applicationInfo.packageName, name, outError); 3244 if (outInfo.name == null) { 3245 return false; 3246 } 3247 3248 int iconVal = sa.getResourceId(iconRes, 0); 3249 if (iconVal != 0) { 3250 outInfo.icon = iconVal; 3251 outInfo.nonLocalizedLabel = null; 3252 } 3253 3254 int logoVal = sa.getResourceId(logoRes, 0); 3255 if (logoVal != 0) { 3256 outInfo.logo = logoVal; 3257 } 3258 3259 int bannerVal = sa.getResourceId(bannerRes, 0); 3260 if (bannerVal != 0) { 3261 outInfo.banner = bannerVal; 3262 } 3263 3264 TypedValue v = sa.peekValue(labelRes); 3265 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 3266 outInfo.nonLocalizedLabel = v.coerceToString(); 3267 } 3268 3269 outInfo.packageName = owner.packageName; 3270 3271 return true; 3272 } 3273 3274 private Activity parseActivity(Package owner, Resources res, 3275 XmlResourceParser parser, int flags, String[] outError, 3276 boolean receiver, boolean hardwareAccelerated) 3277 throws XmlPullParserException, IOException { 3278 TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity); 3279 3280 if (mParseActivityArgs == null) { 3281 mParseActivityArgs = new ParseComponentArgs(owner, outError, 3282 R.styleable.AndroidManifestActivity_name, 3283 R.styleable.AndroidManifestActivity_label, 3284 R.styleable.AndroidManifestActivity_icon, 3285 R.styleable.AndroidManifestActivity_logo, 3286 R.styleable.AndroidManifestActivity_banner, 3287 mSeparateProcesses, 3288 R.styleable.AndroidManifestActivity_process, 3289 R.styleable.AndroidManifestActivity_description, 3290 R.styleable.AndroidManifestActivity_enabled); 3291 } 3292 3293 mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>"; 3294 mParseActivityArgs.sa = sa; 3295 mParseActivityArgs.flags = flags; 3296 3297 Activity a = new Activity(mParseActivityArgs, new ActivityInfo()); 3298 if (outError[0] != null) { 3299 sa.recycle(); 3300 return null; 3301 } 3302 3303 boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported); 3304 if (setExported) { 3305 a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false); 3306 } 3307 3308 a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0); 3309 3310 a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, 3311 a.info.applicationInfo.uiOptions); 3312 3313 String parentName = sa.getNonConfigurationString( 3314 R.styleable.AndroidManifestActivity_parentActivityName, 3315 Configuration.NATIVE_CONFIG_VERSION); 3316 if (parentName != null) { 3317 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 3318 if (outError[0] == null) { 3319 a.info.parentActivityName = parentClassName; 3320 } else { 3321 Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " + 3322 parentName); 3323 outError[0] = null; 3324 } 3325 } 3326 3327 String str; 3328 str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0); 3329 if (str == null) { 3330 a.info.permission = owner.applicationInfo.permission; 3331 } else { 3332 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 3333 } 3334 3335 str = sa.getNonConfigurationString( 3336 R.styleable.AndroidManifestActivity_taskAffinity, 3337 Configuration.NATIVE_CONFIG_VERSION); 3338 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName, 3339 owner.applicationInfo.taskAffinity, str, outError); 3340 3341 a.info.flags = 0; 3342 if (sa.getBoolean( 3343 R.styleable.AndroidManifestActivity_multiprocess, false)) { 3344 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS; 3345 } 3346 3347 if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) { 3348 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; 3349 } 3350 3351 if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) { 3352 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; 3353 } 3354 3355 if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) { 3356 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY; 3357 } 3358 3359 if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) { 3360 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; 3361 } 3362 3363 if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) { 3364 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; 3365 } 3366 3367 if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) { 3368 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; 3369 } 3370 3371 if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting, 3372 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) { 3373 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; 3374 } 3375 3376 if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) { 3377 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; 3378 } 3379 3380 if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false) 3381 || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) { 3382 a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; 3383 } 3384 3385 if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) { 3386 a.info.flags |= ActivityInfo.FLAG_IMMERSIVE; 3387 } 3388 3389 if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) { 3390 a.info.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY; 3391 } 3392 3393 if (!receiver) { 3394 if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated, 3395 hardwareAccelerated)) { 3396 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; 3397 } 3398 3399 a.info.launchMode = sa.getInt( 3400 R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE); 3401 a.info.documentLaunchMode = sa.getInt( 3402 R.styleable.AndroidManifestActivity_documentLaunchMode, 3403 ActivityInfo.DOCUMENT_LAUNCH_NONE); 3404 a.info.maxRecents = sa.getInt( 3405 R.styleable.AndroidManifestActivity_maxRecents, 3406 ActivityManager.getDefaultAppRecentsLimitStatic()); 3407 a.info.configChanges = sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0); 3408 a.info.softInputMode = sa.getInt( 3409 R.styleable.AndroidManifestActivity_windowSoftInputMode, 0); 3410 3411 a.info.persistableMode = sa.getInteger( 3412 R.styleable.AndroidManifestActivity_persistableMode, 3413 ActivityInfo.PERSIST_ROOT_ONLY); 3414 3415 if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) { 3416 a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED; 3417 } 3418 3419 if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) { 3420 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS; 3421 } 3422 3423 if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) { 3424 a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; 3425 } 3426 3427 if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) { 3428 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING; 3429 } 3430 3431 a.info.screenOrientation = sa.getInt( 3432 R.styleable.AndroidManifestActivity_screenOrientation, 3433 SCREEN_ORIENTATION_UNSPECIFIED); 3434 3435 a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; 3436 final boolean appDefault = (owner.applicationInfo.privateFlags 3437 & PRIVATE_FLAG_RESIZEABLE_ACTIVITIES) != 0; 3438 final boolean resizeable = sa.getBoolean( 3439 R.styleable.AndroidManifestActivity_resizeableActivity, appDefault); 3440 3441 if (resizeable) { 3442 if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, 3443 false)) { 3444 a.info.resizeMode = RESIZE_MODE_RESIZEABLE_AND_PIPABLE; 3445 } else { 3446 a.info.resizeMode = RESIZE_MODE_RESIZEABLE; 3447 } 3448 } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) { 3449 a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; 3450 } else if (a.info.screenOrientation == SCREEN_ORIENTATION_UNSPECIFIED 3451 && (a.info.flags & FLAG_IMMERSIVE) == 0) { 3452 a.info.resizeMode = RESIZE_MODE_CROP_WINDOWS; 3453 } 3454 3455 if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) { 3456 a.info.flags |= FLAG_ALWAYS_FOCUSABLE; 3457 } 3458 3459 a.info.lockTaskLaunchMode = 3460 sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0); 3461 3462 a.info.encryptionAware = sa.getBoolean( 3463 R.styleable.AndroidManifestActivity_encryptionAware, 3464 owner.applicationInfo.isEncryptionAware()); 3465 } else { 3466 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; 3467 a.info.configChanges = 0; 3468 3469 if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) { 3470 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER; 3471 if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 3472 Slog.w(TAG, "Activity exported request ignored due to singleUser: " 3473 + a.className + " at " + mArchiveSourcePath + " " 3474 + parser.getPositionDescription()); 3475 a.info.exported = false; 3476 setExported = true; 3477 } 3478 } 3479 3480 a.info.encryptionAware = sa.getBoolean( 3481 R.styleable.AndroidManifestActivity_encryptionAware, 3482 owner.applicationInfo.isEncryptionAware()); 3483 } 3484 3485 if (a.info.encryptionAware) { 3486 owner.applicationInfo.privateFlags |= 3487 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE; 3488 } 3489 3490 sa.recycle(); 3491 3492 if (receiver && (owner.applicationInfo.privateFlags 3493 &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { 3494 // A heavy-weight application can not have receives in its main process 3495 // We can do direct compare because we intern all strings. 3496 if (a.info.processName == owner.packageName) { 3497 outError[0] = "Heavy-weight applications can not have receivers in main process"; 3498 } 3499 } 3500 3501 if (outError[0] != null) { 3502 return null; 3503 } 3504 3505 int outerDepth = parser.getDepth(); 3506 int type; 3507 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3508 && (type != XmlPullParser.END_TAG 3509 || parser.getDepth() > outerDepth)) { 3510 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3511 continue; 3512 } 3513 3514 if (parser.getName().equals("intent-filter")) { 3515 ActivityIntentInfo intent = new ActivityIntentInfo(a); 3516 if (!parseIntent(res, parser, true, true, intent, outError)) { 3517 return null; 3518 } 3519 if (intent.countActions() == 0) { 3520 Slog.w(TAG, "No actions in intent filter at " 3521 + mArchiveSourcePath + " " 3522 + parser.getPositionDescription()); 3523 } else { 3524 a.intents.add(intent); 3525 } 3526 } else if (!receiver && parser.getName().equals("preferred")) { 3527 ActivityIntentInfo intent = new ActivityIntentInfo(a); 3528 if (!parseIntent(res, parser, false, false, intent, outError)) { 3529 return null; 3530 } 3531 if (intent.countActions() == 0) { 3532 Slog.w(TAG, "No actions in preferred at " 3533 + mArchiveSourcePath + " " 3534 + parser.getPositionDescription()); 3535 } else { 3536 if (owner.preferredActivityFilters == null) { 3537 owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>(); 3538 } 3539 owner.preferredActivityFilters.add(intent); 3540 } 3541 } else if (parser.getName().equals("meta-data")) { 3542 if ((a.metaData = parseMetaData(res, parser, a.metaData, 3543 outError)) == null) { 3544 return null; 3545 } 3546 } else if (!receiver && parser.getName().equals("layout")) { 3547 parseLayout(res, parser, a); 3548 } else { 3549 if (!RIGID_PARSER) { 3550 Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":"); 3551 if (receiver) { 3552 Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName() 3553 + " at " + mArchiveSourcePath + " " 3554 + parser.getPositionDescription()); 3555 } else { 3556 Slog.w(TAG, "Unknown element under <activity>: " + parser.getName() 3557 + " at " + mArchiveSourcePath + " " 3558 + parser.getPositionDescription()); 3559 } 3560 XmlUtils.skipCurrentTag(parser); 3561 continue; 3562 } else { 3563 if (receiver) { 3564 outError[0] = "Bad element under <receiver>: " + parser.getName(); 3565 } else { 3566 outError[0] = "Bad element under <activity>: " + parser.getName(); 3567 } 3568 return null; 3569 } 3570 } 3571 } 3572 3573 if (!setExported) { 3574 a.info.exported = a.intents.size() > 0; 3575 } 3576 3577 return a; 3578 } 3579 3580 private void parseLayout(Resources res, AttributeSet attrs, Activity a) { 3581 TypedArray sw = res.obtainAttributes(attrs, 3582 com.android.internal.R.styleable.AndroidManifestLayout); 3583 int width = -1; 3584 float widthFraction = -1f; 3585 int height = -1; 3586 float heightFraction = -1f; 3587 final int widthType = sw.getType( 3588 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth); 3589 if (widthType == TypedValue.TYPE_FRACTION) { 3590 widthFraction = sw.getFraction( 3591 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth, 3592 1, 1, -1); 3593 } else if (widthType == TypedValue.TYPE_DIMENSION) { 3594 width = sw.getDimensionPixelSize( 3595 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth, 3596 -1); 3597 } 3598 final int heightType = sw.getType( 3599 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight); 3600 if (heightType == TypedValue.TYPE_FRACTION) { 3601 heightFraction = sw.getFraction( 3602 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight, 3603 1, 1, -1); 3604 } else if (heightType == TypedValue.TYPE_DIMENSION) { 3605 height = sw.getDimensionPixelSize( 3606 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight, 3607 -1); 3608 } 3609 int gravity = sw.getInt( 3610 com.android.internal.R.styleable.AndroidManifestLayout_gravity, 3611 Gravity.CENTER); 3612 int minimalSize = sw.getDimensionPixelSize( 3613 com.android.internal.R.styleable.AndroidManifestLayout_minimalSize, 3614 -1); 3615 sw.recycle(); 3616 a.info.layout = new ActivityInfo.Layout(width, widthFraction, 3617 height, heightFraction, gravity, minimalSize); 3618 } 3619 3620 private Activity parseActivityAlias(Package owner, Resources res, 3621 XmlResourceParser parser, int flags, String[] outError) 3622 throws XmlPullParserException, IOException { 3623 TypedArray sa = res.obtainAttributes(parser, 3624 com.android.internal.R.styleable.AndroidManifestActivityAlias); 3625 3626 String targetActivity = sa.getNonConfigurationString( 3627 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity, 3628 Configuration.NATIVE_CONFIG_VERSION); 3629 if (targetActivity == null) { 3630 outError[0] = "<activity-alias> does not specify android:targetActivity"; 3631 sa.recycle(); 3632 return null; 3633 } 3634 3635 targetActivity = buildClassName(owner.applicationInfo.packageName, 3636 targetActivity, outError); 3637 if (targetActivity == null) { 3638 sa.recycle(); 3639 return null; 3640 } 3641 3642 if (mParseActivityAliasArgs == null) { 3643 mParseActivityAliasArgs = new ParseComponentArgs(owner, outError, 3644 com.android.internal.R.styleable.AndroidManifestActivityAlias_name, 3645 com.android.internal.R.styleable.AndroidManifestActivityAlias_label, 3646 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, 3647 com.android.internal.R.styleable.AndroidManifestActivityAlias_logo, 3648 com.android.internal.R.styleable.AndroidManifestActivityAlias_banner, 3649 mSeparateProcesses, 3650 0, 3651 com.android.internal.R.styleable.AndroidManifestActivityAlias_description, 3652 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled); 3653 mParseActivityAliasArgs.tag = "<activity-alias>"; 3654 } 3655 3656 mParseActivityAliasArgs.sa = sa; 3657 mParseActivityAliasArgs.flags = flags; 3658 3659 Activity target = null; 3660 3661 final int NA = owner.activities.size(); 3662 for (int i=0; i<NA; i++) { 3663 Activity t = owner.activities.get(i); 3664 if (targetActivity.equals(t.info.name)) { 3665 target = t; 3666 break; 3667 } 3668 } 3669 3670 if (target == null) { 3671 outError[0] = "<activity-alias> target activity " + targetActivity 3672 + " not found in manifest"; 3673 sa.recycle(); 3674 return null; 3675 } 3676 3677 ActivityInfo info = new ActivityInfo(); 3678 info.targetActivity = targetActivity; 3679 info.configChanges = target.info.configChanges; 3680 info.flags = target.info.flags; 3681 info.icon = target.info.icon; 3682 info.logo = target.info.logo; 3683 info.banner = target.info.banner; 3684 info.labelRes = target.info.labelRes; 3685 info.nonLocalizedLabel = target.info.nonLocalizedLabel; 3686 info.launchMode = target.info.launchMode; 3687 info.lockTaskLaunchMode = target.info.lockTaskLaunchMode; 3688 info.processName = target.info.processName; 3689 if (info.descriptionRes == 0) { 3690 info.descriptionRes = target.info.descriptionRes; 3691 } 3692 info.screenOrientation = target.info.screenOrientation; 3693 info.taskAffinity = target.info.taskAffinity; 3694 info.theme = target.info.theme; 3695 info.softInputMode = target.info.softInputMode; 3696 info.uiOptions = target.info.uiOptions; 3697 info.parentActivityName = target.info.parentActivityName; 3698 info.maxRecents = target.info.maxRecents; 3699 info.layout = target.info.layout; 3700 info.resizeMode = target.info.resizeMode; 3701 info.encryptionAware = target.info.encryptionAware; 3702 3703 Activity a = new Activity(mParseActivityAliasArgs, info); 3704 if (outError[0] != null) { 3705 sa.recycle(); 3706 return null; 3707 } 3708 3709 final boolean setExported = sa.hasValue( 3710 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported); 3711 if (setExported) { 3712 a.info.exported = sa.getBoolean( 3713 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false); 3714 } 3715 3716 String str; 3717 str = sa.getNonConfigurationString( 3718 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0); 3719 if (str != null) { 3720 a.info.permission = str.length() > 0 ? str.toString().intern() : null; 3721 } 3722 3723 String parentName = sa.getNonConfigurationString( 3724 com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName, 3725 Configuration.NATIVE_CONFIG_VERSION); 3726 if (parentName != null) { 3727 String parentClassName = buildClassName(a.info.packageName, parentName, outError); 3728 if (outError[0] == null) { 3729 a.info.parentActivityName = parentClassName; 3730 } else { 3731 Log.e(TAG, "Activity alias " + a.info.name + 3732 " specified invalid parentActivityName " + parentName); 3733 outError[0] = null; 3734 } 3735 } 3736 3737 sa.recycle(); 3738 3739 if (outError[0] != null) { 3740 return null; 3741 } 3742 3743 int outerDepth = parser.getDepth(); 3744 int type; 3745 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3746 && (type != XmlPullParser.END_TAG 3747 || parser.getDepth() > outerDepth)) { 3748 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3749 continue; 3750 } 3751 3752 if (parser.getName().equals("intent-filter")) { 3753 ActivityIntentInfo intent = new ActivityIntentInfo(a); 3754 if (!parseIntent(res, parser, true, true, intent, outError)) { 3755 return null; 3756 } 3757 if (intent.countActions() == 0) { 3758 Slog.w(TAG, "No actions in intent filter at " 3759 + mArchiveSourcePath + " " 3760 + parser.getPositionDescription()); 3761 } else { 3762 a.intents.add(intent); 3763 } 3764 } else if (parser.getName().equals("meta-data")) { 3765 if ((a.metaData=parseMetaData(res, parser, a.metaData, 3766 outError)) == null) { 3767 return null; 3768 } 3769 } else { 3770 if (!RIGID_PARSER) { 3771 Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName() 3772 + " at " + mArchiveSourcePath + " " 3773 + parser.getPositionDescription()); 3774 XmlUtils.skipCurrentTag(parser); 3775 continue; 3776 } else { 3777 outError[0] = "Bad element under <activity-alias>: " + parser.getName(); 3778 return null; 3779 } 3780 } 3781 } 3782 3783 if (!setExported) { 3784 a.info.exported = a.intents.size() > 0; 3785 } 3786 3787 return a; 3788 } 3789 3790 private Provider parseProvider(Package owner, Resources res, 3791 XmlResourceParser parser, int flags, String[] outError) 3792 throws XmlPullParserException, IOException { 3793 TypedArray sa = res.obtainAttributes(parser, 3794 com.android.internal.R.styleable.AndroidManifestProvider); 3795 3796 if (mParseProviderArgs == null) { 3797 mParseProviderArgs = new ParseComponentArgs(owner, outError, 3798 com.android.internal.R.styleable.AndroidManifestProvider_name, 3799 com.android.internal.R.styleable.AndroidManifestProvider_label, 3800 com.android.internal.R.styleable.AndroidManifestProvider_icon, 3801 com.android.internal.R.styleable.AndroidManifestProvider_logo, 3802 com.android.internal.R.styleable.AndroidManifestProvider_banner, 3803 mSeparateProcesses, 3804 com.android.internal.R.styleable.AndroidManifestProvider_process, 3805 com.android.internal.R.styleable.AndroidManifestProvider_description, 3806 com.android.internal.R.styleable.AndroidManifestProvider_enabled); 3807 mParseProviderArgs.tag = "<provider>"; 3808 } 3809 3810 mParseProviderArgs.sa = sa; 3811 mParseProviderArgs.flags = flags; 3812 3813 Provider p = new Provider(mParseProviderArgs, new ProviderInfo()); 3814 if (outError[0] != null) { 3815 sa.recycle(); 3816 return null; 3817 } 3818 3819 boolean providerExportedDefault = false; 3820 3821 if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 3822 // For compatibility, applications targeting API level 16 or lower 3823 // should have their content providers exported by default, unless they 3824 // specify otherwise. 3825 providerExportedDefault = true; 3826 } 3827 3828 p.info.exported = sa.getBoolean( 3829 com.android.internal.R.styleable.AndroidManifestProvider_exported, 3830 providerExportedDefault); 3831 3832 String cpname = sa.getNonConfigurationString( 3833 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0); 3834 3835 p.info.isSyncable = sa.getBoolean( 3836 com.android.internal.R.styleable.AndroidManifestProvider_syncable, 3837 false); 3838 3839 String permission = sa.getNonConfigurationString( 3840 com.android.internal.R.styleable.AndroidManifestProvider_permission, 0); 3841 String str = sa.getNonConfigurationString( 3842 com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0); 3843 if (str == null) { 3844 str = permission; 3845 } 3846 if (str == null) { 3847 p.info.readPermission = owner.applicationInfo.permission; 3848 } else { 3849 p.info.readPermission = 3850 str.length() > 0 ? str.toString().intern() : null; 3851 } 3852 str = sa.getNonConfigurationString( 3853 com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0); 3854 if (str == null) { 3855 str = permission; 3856 } 3857 if (str == null) { 3858 p.info.writePermission = owner.applicationInfo.permission; 3859 } else { 3860 p.info.writePermission = 3861 str.length() > 0 ? str.toString().intern() : null; 3862 } 3863 3864 p.info.grantUriPermissions = sa.getBoolean( 3865 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions, 3866 false); 3867 3868 p.info.multiprocess = sa.getBoolean( 3869 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess, 3870 false); 3871 3872 p.info.initOrder = sa.getInt( 3873 com.android.internal.R.styleable.AndroidManifestProvider_initOrder, 3874 0); 3875 3876 p.info.flags = 0; 3877 3878 if (sa.getBoolean( 3879 com.android.internal.R.styleable.AndroidManifestProvider_singleUser, 3880 false)) { 3881 p.info.flags |= ProviderInfo.FLAG_SINGLE_USER; 3882 if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 3883 Slog.w(TAG, "Provider exported request ignored due to singleUser: " 3884 + p.className + " at " + mArchiveSourcePath + " " 3885 + parser.getPositionDescription()); 3886 p.info.exported = false; 3887 } 3888 } 3889 3890 p.info.encryptionAware = sa.getBoolean( 3891 R.styleable.AndroidManifestProvider_encryptionAware, 3892 owner.applicationInfo.isEncryptionAware()); 3893 if (p.info.encryptionAware) { 3894 owner.applicationInfo.privateFlags |= 3895 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE; 3896 } 3897 3898 sa.recycle(); 3899 3900 if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) 3901 != 0) { 3902 // A heavy-weight application can not have providers in its main process 3903 // We can do direct compare because we intern all strings. 3904 if (p.info.processName == owner.packageName) { 3905 outError[0] = "Heavy-weight applications can not have providers in main process"; 3906 return null; 3907 } 3908 } 3909 3910 if (cpname == null) { 3911 outError[0] = "<provider> does not include authorities attribute"; 3912 return null; 3913 } 3914 if (cpname.length() <= 0) { 3915 outError[0] = "<provider> has empty authorities attribute"; 3916 return null; 3917 } 3918 p.info.authority = cpname.intern(); 3919 3920 if (!parseProviderTags(res, parser, p, outError)) { 3921 return null; 3922 } 3923 3924 return p; 3925 } 3926 3927 private boolean parseProviderTags(Resources res, 3928 XmlResourceParser parser, Provider outInfo, String[] outError) 3929 throws XmlPullParserException, IOException { 3930 int outerDepth = parser.getDepth(); 3931 int type; 3932 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 3933 && (type != XmlPullParser.END_TAG 3934 || parser.getDepth() > outerDepth)) { 3935 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 3936 continue; 3937 } 3938 3939 if (parser.getName().equals("intent-filter")) { 3940 ProviderIntentInfo intent = new ProviderIntentInfo(outInfo); 3941 if (!parseIntent(res, parser, true, false, intent, outError)) { 3942 return false; 3943 } 3944 outInfo.intents.add(intent); 3945 3946 } else if (parser.getName().equals("meta-data")) { 3947 if ((outInfo.metaData=parseMetaData(res, parser, 3948 outInfo.metaData, outError)) == null) { 3949 return false; 3950 } 3951 3952 } else if (parser.getName().equals("grant-uri-permission")) { 3953 TypedArray sa = res.obtainAttributes(parser, 3954 com.android.internal.R.styleable.AndroidManifestGrantUriPermission); 3955 3956 PatternMatcher pa = null; 3957 3958 String str = sa.getNonConfigurationString( 3959 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0); 3960 if (str != null) { 3961 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); 3962 } 3963 3964 str = sa.getNonConfigurationString( 3965 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); 3966 if (str != null) { 3967 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); 3968 } 3969 3970 str = sa.getNonConfigurationString( 3971 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); 3972 if (str != null) { 3973 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 3974 } 3975 3976 sa.recycle(); 3977 3978 if (pa != null) { 3979 if (outInfo.info.uriPermissionPatterns == null) { 3980 outInfo.info.uriPermissionPatterns = new PatternMatcher[1]; 3981 outInfo.info.uriPermissionPatterns[0] = pa; 3982 } else { 3983 final int N = outInfo.info.uriPermissionPatterns.length; 3984 PatternMatcher[] newp = new PatternMatcher[N+1]; 3985 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N); 3986 newp[N] = pa; 3987 outInfo.info.uriPermissionPatterns = newp; 3988 } 3989 outInfo.info.grantUriPermissions = true; 3990 } else { 3991 if (!RIGID_PARSER) { 3992 Slog.w(TAG, "Unknown element under <path-permission>: " 3993 + parser.getName() + " at " + mArchiveSourcePath + " " 3994 + parser.getPositionDescription()); 3995 XmlUtils.skipCurrentTag(parser); 3996 continue; 3997 } else { 3998 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 3999 return false; 4000 } 4001 } 4002 XmlUtils.skipCurrentTag(parser); 4003 4004 } else if (parser.getName().equals("path-permission")) { 4005 TypedArray sa = res.obtainAttributes(parser, 4006 com.android.internal.R.styleable.AndroidManifestPathPermission); 4007 4008 PathPermission pa = null; 4009 4010 String permission = sa.getNonConfigurationString( 4011 com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0); 4012 String readPermission = sa.getNonConfigurationString( 4013 com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0); 4014 if (readPermission == null) { 4015 readPermission = permission; 4016 } 4017 String writePermission = sa.getNonConfigurationString( 4018 com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0); 4019 if (writePermission == null) { 4020 writePermission = permission; 4021 } 4022 4023 boolean havePerm = false; 4024 if (readPermission != null) { 4025 readPermission = readPermission.intern(); 4026 havePerm = true; 4027 } 4028 if (writePermission != null) { 4029 writePermission = writePermission.intern(); 4030 havePerm = true; 4031 } 4032 4033 if (!havePerm) { 4034 if (!RIGID_PARSER) { 4035 Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: " 4036 + parser.getName() + " at " + mArchiveSourcePath + " " 4037 + parser.getPositionDescription()); 4038 XmlUtils.skipCurrentTag(parser); 4039 continue; 4040 } else { 4041 outError[0] = "No readPermission or writePermssion for <path-permission>"; 4042 return false; 4043 } 4044 } 4045 4046 String path = sa.getNonConfigurationString( 4047 com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0); 4048 if (path != null) { 4049 pa = new PathPermission(path, 4050 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission); 4051 } 4052 4053 path = sa.getNonConfigurationString( 4054 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0); 4055 if (path != null) { 4056 pa = new PathPermission(path, 4057 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission); 4058 } 4059 4060 path = sa.getNonConfigurationString( 4061 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0); 4062 if (path != null) { 4063 pa = new PathPermission(path, 4064 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission); 4065 } 4066 4067 sa.recycle(); 4068 4069 if (pa != null) { 4070 if (outInfo.info.pathPermissions == null) { 4071 outInfo.info.pathPermissions = new PathPermission[1]; 4072 outInfo.info.pathPermissions[0] = pa; 4073 } else { 4074 final int N = outInfo.info.pathPermissions.length; 4075 PathPermission[] newp = new PathPermission[N+1]; 4076 System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N); 4077 newp[N] = pa; 4078 outInfo.info.pathPermissions = newp; 4079 } 4080 } else { 4081 if (!RIGID_PARSER) { 4082 Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: " 4083 + parser.getName() + " at " + mArchiveSourcePath + " " 4084 + parser.getPositionDescription()); 4085 XmlUtils.skipCurrentTag(parser); 4086 continue; 4087 } 4088 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; 4089 return false; 4090 } 4091 XmlUtils.skipCurrentTag(parser); 4092 4093 } else { 4094 if (!RIGID_PARSER) { 4095 Slog.w(TAG, "Unknown element under <provider>: " 4096 + parser.getName() + " at " + mArchiveSourcePath + " " 4097 + parser.getPositionDescription()); 4098 XmlUtils.skipCurrentTag(parser); 4099 continue; 4100 } else { 4101 outError[0] = "Bad element under <provider>: " + parser.getName(); 4102 return false; 4103 } 4104 } 4105 } 4106 return true; 4107 } 4108 4109 private Service parseService(Package owner, Resources res, 4110 XmlResourceParser parser, int flags, String[] outError) 4111 throws XmlPullParserException, IOException { 4112 TypedArray sa = res.obtainAttributes(parser, 4113 com.android.internal.R.styleable.AndroidManifestService); 4114 4115 if (mParseServiceArgs == null) { 4116 mParseServiceArgs = new ParseComponentArgs(owner, outError, 4117 com.android.internal.R.styleable.AndroidManifestService_name, 4118 com.android.internal.R.styleable.AndroidManifestService_label, 4119 com.android.internal.R.styleable.AndroidManifestService_icon, 4120 com.android.internal.R.styleable.AndroidManifestService_logo, 4121 com.android.internal.R.styleable.AndroidManifestService_banner, 4122 mSeparateProcesses, 4123 com.android.internal.R.styleable.AndroidManifestService_process, 4124 com.android.internal.R.styleable.AndroidManifestService_description, 4125 com.android.internal.R.styleable.AndroidManifestService_enabled); 4126 mParseServiceArgs.tag = "<service>"; 4127 } 4128 4129 mParseServiceArgs.sa = sa; 4130 mParseServiceArgs.flags = flags; 4131 4132 Service s = new Service(mParseServiceArgs, new ServiceInfo()); 4133 if (outError[0] != null) { 4134 sa.recycle(); 4135 return null; 4136 } 4137 4138 boolean setExported = sa.hasValue( 4139 com.android.internal.R.styleable.AndroidManifestService_exported); 4140 if (setExported) { 4141 s.info.exported = sa.getBoolean( 4142 com.android.internal.R.styleable.AndroidManifestService_exported, false); 4143 } 4144 4145 String str = sa.getNonConfigurationString( 4146 com.android.internal.R.styleable.AndroidManifestService_permission, 0); 4147 if (str == null) { 4148 s.info.permission = owner.applicationInfo.permission; 4149 } else { 4150 s.info.permission = str.length() > 0 ? str.toString().intern() : null; 4151 } 4152 4153 s.info.flags = 0; 4154 if (sa.getBoolean( 4155 com.android.internal.R.styleable.AndroidManifestService_stopWithTask, 4156 false)) { 4157 s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK; 4158 } 4159 if (sa.getBoolean( 4160 com.android.internal.R.styleable.AndroidManifestService_isolatedProcess, 4161 false)) { 4162 s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS; 4163 } 4164 if (sa.getBoolean( 4165 com.android.internal.R.styleable.AndroidManifestService_externalService, 4166 false)) { 4167 s.info.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE; 4168 } 4169 if (sa.getBoolean( 4170 com.android.internal.R.styleable.AndroidManifestService_singleUser, 4171 false)) { 4172 s.info.flags |= ServiceInfo.FLAG_SINGLE_USER; 4173 if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) { 4174 Slog.w(TAG, "Service exported request ignored due to singleUser: " 4175 + s.className + " at " + mArchiveSourcePath + " " 4176 + parser.getPositionDescription()); 4177 s.info.exported = false; 4178 setExported = true; 4179 } 4180 } 4181 4182 s.info.encryptionAware = sa.getBoolean( 4183 R.styleable.AndroidManifestService_encryptionAware, 4184 owner.applicationInfo.isEncryptionAware()); 4185 if (s.info.encryptionAware) { 4186 owner.applicationInfo.privateFlags |= 4187 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE; 4188 } 4189 4190 sa.recycle(); 4191 4192 if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) 4193 != 0) { 4194 // A heavy-weight application can not have services in its main process 4195 // We can do direct compare because we intern all strings. 4196 if (s.info.processName == owner.packageName) { 4197 outError[0] = "Heavy-weight applications can not have services in main process"; 4198 return null; 4199 } 4200 } 4201 4202 int outerDepth = parser.getDepth(); 4203 int type; 4204 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 4205 && (type != XmlPullParser.END_TAG 4206 || parser.getDepth() > outerDepth)) { 4207 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4208 continue; 4209 } 4210 4211 if (parser.getName().equals("intent-filter")) { 4212 ServiceIntentInfo intent = new ServiceIntentInfo(s); 4213 if (!parseIntent(res, parser, true, false, intent, outError)) { 4214 return null; 4215 } 4216 4217 s.intents.add(intent); 4218 } else if (parser.getName().equals("meta-data")) { 4219 if ((s.metaData=parseMetaData(res, parser, s.metaData, 4220 outError)) == null) { 4221 return null; 4222 } 4223 } else { 4224 if (!RIGID_PARSER) { 4225 Slog.w(TAG, "Unknown element under <service>: " 4226 + parser.getName() + " at " + mArchiveSourcePath + " " 4227 + parser.getPositionDescription()); 4228 XmlUtils.skipCurrentTag(parser); 4229 continue; 4230 } else { 4231 outError[0] = "Bad element under <service>: " + parser.getName(); 4232 return null; 4233 } 4234 } 4235 } 4236 4237 if (!setExported) { 4238 s.info.exported = s.intents.size() > 0; 4239 } 4240 4241 return s; 4242 } 4243 4244 private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag, 4245 Component<?> outInfo, String[] outError) throws XmlPullParserException, IOException { 4246 int outerDepth = parser.getDepth(); 4247 int type; 4248 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 4249 && (type != XmlPullParser.END_TAG 4250 || parser.getDepth() > outerDepth)) { 4251 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4252 continue; 4253 } 4254 4255 if (parser.getName().equals("meta-data")) { 4256 if ((outInfo.metaData=parseMetaData(res, parser, 4257 outInfo.metaData, outError)) == null) { 4258 return false; 4259 } 4260 } else { 4261 if (!RIGID_PARSER) { 4262 Slog.w(TAG, "Unknown element under " + tag + ": " 4263 + parser.getName() + " at " + mArchiveSourcePath + " " 4264 + parser.getPositionDescription()); 4265 XmlUtils.skipCurrentTag(parser); 4266 continue; 4267 } else { 4268 outError[0] = "Bad element under " + tag + ": " + parser.getName(); 4269 return false; 4270 } 4271 } 4272 } 4273 return true; 4274 } 4275 4276 private Bundle parseMetaData(Resources res, 4277 XmlResourceParser parser, Bundle data, String[] outError) 4278 throws XmlPullParserException, IOException { 4279 4280 TypedArray sa = res.obtainAttributes(parser, 4281 com.android.internal.R.styleable.AndroidManifestMetaData); 4282 4283 if (data == null) { 4284 data = new Bundle(); 4285 } 4286 4287 String name = sa.getNonConfigurationString( 4288 com.android.internal.R.styleable.AndroidManifestMetaData_name, 0); 4289 if (name == null) { 4290 outError[0] = "<meta-data> requires an android:name attribute"; 4291 sa.recycle(); 4292 return null; 4293 } 4294 4295 name = name.intern(); 4296 4297 TypedValue v = sa.peekValue( 4298 com.android.internal.R.styleable.AndroidManifestMetaData_resource); 4299 if (v != null && v.resourceId != 0) { 4300 //Slog.i(TAG, "Meta data ref " + name + ": " + v); 4301 data.putInt(name, v.resourceId); 4302 } else { 4303 v = sa.peekValue( 4304 com.android.internal.R.styleable.AndroidManifestMetaData_value); 4305 //Slog.i(TAG, "Meta data " + name + ": " + v); 4306 if (v != null) { 4307 if (v.type == TypedValue.TYPE_STRING) { 4308 CharSequence cs = v.coerceToString(); 4309 data.putString(name, cs != null ? cs.toString().intern() : null); 4310 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { 4311 data.putBoolean(name, v.data != 0); 4312 } else if (v.type >= TypedValue.TYPE_FIRST_INT 4313 && v.type <= TypedValue.TYPE_LAST_INT) { 4314 data.putInt(name, v.data); 4315 } else if (v.type == TypedValue.TYPE_FLOAT) { 4316 data.putFloat(name, v.getFloat()); 4317 } else { 4318 if (!RIGID_PARSER) { 4319 Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: " 4320 + parser.getName() + " at " + mArchiveSourcePath + " " 4321 + parser.getPositionDescription()); 4322 } else { 4323 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types"; 4324 data = null; 4325 } 4326 } 4327 } else { 4328 outError[0] = "<meta-data> requires an android:value or android:resource attribute"; 4329 data = null; 4330 } 4331 } 4332 4333 sa.recycle(); 4334 4335 XmlUtils.skipCurrentTag(parser); 4336 4337 return data; 4338 } 4339 4340 private static VerifierInfo parseVerifier(Resources res, XmlPullParser parser, 4341 AttributeSet attrs, int flags) { 4342 final TypedArray sa = res.obtainAttributes(attrs, 4343 com.android.internal.R.styleable.AndroidManifestPackageVerifier); 4344 4345 final String packageName = sa.getNonResourceString( 4346 com.android.internal.R.styleable.AndroidManifestPackageVerifier_name); 4347 4348 final String encodedPublicKey = sa.getNonResourceString( 4349 com.android.internal.R.styleable.AndroidManifestPackageVerifier_publicKey); 4350 4351 sa.recycle(); 4352 4353 if (packageName == null || packageName.length() == 0) { 4354 Slog.i(TAG, "verifier package name was null; skipping"); 4355 return null; 4356 } 4357 4358 final PublicKey publicKey = parsePublicKey(encodedPublicKey); 4359 if (publicKey == null) { 4360 Slog.i(TAG, "Unable to parse verifier public key for " + packageName); 4361 return null; 4362 } 4363 4364 return new VerifierInfo(packageName, publicKey); 4365 } 4366 4367 public static final PublicKey parsePublicKey(final String encodedPublicKey) { 4368 if (encodedPublicKey == null) { 4369 Slog.w(TAG, "Could not parse null public key"); 4370 return null; 4371 } 4372 4373 EncodedKeySpec keySpec; 4374 try { 4375 final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT); 4376 keySpec = new X509EncodedKeySpec(encoded); 4377 } catch (IllegalArgumentException e) { 4378 Slog.w(TAG, "Could not parse verifier public key; invalid Base64"); 4379 return null; 4380 } 4381 4382 /* First try the key as an RSA key. */ 4383 try { 4384 final KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 4385 return keyFactory.generatePublic(keySpec); 4386 } catch (NoSuchAlgorithmException e) { 4387 Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build"); 4388 } catch (InvalidKeySpecException e) { 4389 // Not a RSA public key. 4390 } 4391 4392 /* Now try it as a ECDSA key. */ 4393 try { 4394 final KeyFactory keyFactory = KeyFactory.getInstance("EC"); 4395 return keyFactory.generatePublic(keySpec); 4396 } catch (NoSuchAlgorithmException e) { 4397 Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build"); 4398 } catch (InvalidKeySpecException e) { 4399 // Not a ECDSA public key. 4400 } 4401 4402 /* Now try it as a DSA key. */ 4403 try { 4404 final KeyFactory keyFactory = KeyFactory.getInstance("DSA"); 4405 return keyFactory.generatePublic(keySpec); 4406 } catch (NoSuchAlgorithmException e) { 4407 Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build"); 4408 } catch (InvalidKeySpecException e) { 4409 // Not a DSA public key. 4410 } 4411 4412 /* Not a supported key type */ 4413 return null; 4414 } 4415 4416 private static final String ANDROID_RESOURCES 4417 = "http://schemas.android.com/apk/res/android"; 4418 4419 private boolean parseIntent(Resources res, XmlResourceParser parser, 4420 boolean allowGlobs, boolean allowAutoVerify, IntentInfo outInfo, String[] outError) 4421 throws XmlPullParserException, IOException { 4422 4423 TypedArray sa = res.obtainAttributes(parser, 4424 com.android.internal.R.styleable.AndroidManifestIntentFilter); 4425 4426 int priority = sa.getInt( 4427 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0); 4428 outInfo.setPriority(priority); 4429 4430 TypedValue v = sa.peekValue( 4431 com.android.internal.R.styleable.AndroidManifestIntentFilter_label); 4432 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 4433 outInfo.nonLocalizedLabel = v.coerceToString(); 4434 } 4435 4436 outInfo.icon = sa.getResourceId( 4437 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0); 4438 4439 outInfo.logo = sa.getResourceId( 4440 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0); 4441 4442 outInfo.banner = sa.getResourceId( 4443 com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0); 4444 4445 if (allowAutoVerify) { 4446 outInfo.setAutoVerify(sa.getBoolean( 4447 com.android.internal.R.styleable.AndroidManifestIntentFilter_autoVerify, 4448 false)); 4449 } 4450 4451 sa.recycle(); 4452 4453 int outerDepth = parser.getDepth(); 4454 int type; 4455 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 4456 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 4457 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 4458 continue; 4459 } 4460 4461 String nodeName = parser.getName(); 4462 if (nodeName.equals("action")) { 4463 String value = parser.getAttributeValue( 4464 ANDROID_RESOURCES, "name"); 4465 if (value == null || value == "") { 4466 outError[0] = "No value supplied for <android:name>"; 4467 return false; 4468 } 4469 XmlUtils.skipCurrentTag(parser); 4470 4471 outInfo.addAction(value); 4472 } else if (nodeName.equals("category")) { 4473 String value = parser.getAttributeValue( 4474 ANDROID_RESOURCES, "name"); 4475 if (value == null || value == "") { 4476 outError[0] = "No value supplied for <android:name>"; 4477 return false; 4478 } 4479 XmlUtils.skipCurrentTag(parser); 4480 4481 outInfo.addCategory(value); 4482 4483 } else if (nodeName.equals("data")) { 4484 sa = res.obtainAttributes(parser, 4485 com.android.internal.R.styleable.AndroidManifestData); 4486 4487 String str = sa.getNonConfigurationString( 4488 com.android.internal.R.styleable.AndroidManifestData_mimeType, 0); 4489 if (str != null) { 4490 try { 4491 outInfo.addDataType(str); 4492 } catch (IntentFilter.MalformedMimeTypeException e) { 4493 outError[0] = e.toString(); 4494 sa.recycle(); 4495 return false; 4496 } 4497 } 4498 4499 str = sa.getNonConfigurationString( 4500 com.android.internal.R.styleable.AndroidManifestData_scheme, 0); 4501 if (str != null) { 4502 outInfo.addDataScheme(str); 4503 } 4504 4505 str = sa.getNonConfigurationString( 4506 com.android.internal.R.styleable.AndroidManifestData_ssp, 0); 4507 if (str != null) { 4508 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL); 4509 } 4510 4511 str = sa.getNonConfigurationString( 4512 com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0); 4513 if (str != null) { 4514 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX); 4515 } 4516 4517 str = sa.getNonConfigurationString( 4518 com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0); 4519 if (str != null) { 4520 if (!allowGlobs) { 4521 outError[0] = "sspPattern not allowed here; ssp must be literal"; 4522 return false; 4523 } 4524 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 4525 } 4526 4527 String host = sa.getNonConfigurationString( 4528 com.android.internal.R.styleable.AndroidManifestData_host, 0); 4529 String port = sa.getNonConfigurationString( 4530 com.android.internal.R.styleable.AndroidManifestData_port, 0); 4531 if (host != null) { 4532 outInfo.addDataAuthority(host, port); 4533 } 4534 4535 str = sa.getNonConfigurationString( 4536 com.android.internal.R.styleable.AndroidManifestData_path, 0); 4537 if (str != null) { 4538 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); 4539 } 4540 4541 str = sa.getNonConfigurationString( 4542 com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0); 4543 if (str != null) { 4544 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); 4545 } 4546 4547 str = sa.getNonConfigurationString( 4548 com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0); 4549 if (str != null) { 4550 if (!allowGlobs) { 4551 outError[0] = "pathPattern not allowed here; path must be literal"; 4552 return false; 4553 } 4554 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); 4555 } 4556 4557 sa.recycle(); 4558 XmlUtils.skipCurrentTag(parser); 4559 } else if (!RIGID_PARSER) { 4560 Slog.w(TAG, "Unknown element under <intent-filter>: " 4561 + parser.getName() + " at " + mArchiveSourcePath + " " 4562 + parser.getPositionDescription()); 4563 XmlUtils.skipCurrentTag(parser); 4564 } else { 4565 outError[0] = "Bad element under <intent-filter>: " + parser.getName(); 4566 return false; 4567 } 4568 } 4569 4570 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT); 4571 4572 if (DEBUG_PARSER) { 4573 final StringBuilder cats = new StringBuilder("Intent d="); 4574 cats.append(outInfo.hasDefault); 4575 cats.append(", cat="); 4576 4577 final Iterator<String> it = outInfo.categoriesIterator(); 4578 if (it != null) { 4579 while (it.hasNext()) { 4580 cats.append(' '); 4581 cats.append(it.next()); 4582 } 4583 } 4584 Slog.d(TAG, cats.toString()); 4585 } 4586 4587 return true; 4588 } 4589 4590 /** 4591 * Representation of a full package parsed from APK files on disk. A package 4592 * consists of a single base APK, and zero or more split APKs. 4593 */ 4594 public final static class Package { 4595 4596 public String packageName; 4597 4598 /** Names of any split APKs, ordered by parsed splitName */ 4599 public String[] splitNames; 4600 4601 // TODO: work towards making these paths invariant 4602 4603 public String volumeUuid; 4604 4605 /** 4606 * Path where this package was found on disk. For monolithic packages 4607 * this is path to single base APK file; for cluster packages this is 4608 * path to the cluster directory. 4609 */ 4610 public String codePath; 4611 4612 /** Path of base APK */ 4613 public String baseCodePath; 4614 /** Paths of any split APKs, ordered by parsed splitName */ 4615 public String[] splitCodePaths; 4616 4617 /** Revision code of base APK */ 4618 public int baseRevisionCode; 4619 /** Revision codes of any split APKs, ordered by parsed splitName */ 4620 public int[] splitRevisionCodes; 4621 4622 /** Flags of any split APKs; ordered by parsed splitName */ 4623 public int[] splitFlags; 4624 4625 /** 4626 * Private flags of any split APKs; ordered by parsed splitName. 4627 * 4628 * {@hide} 4629 */ 4630 public int[] splitPrivateFlags; 4631 4632 public boolean baseHardwareAccelerated; 4633 4634 // For now we only support one application per package. 4635 public final ApplicationInfo applicationInfo = new ApplicationInfo(); 4636 4637 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0); 4638 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0); 4639 public final ArrayList<Activity> activities = new ArrayList<Activity>(0); 4640 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0); 4641 public final ArrayList<Provider> providers = new ArrayList<Provider>(0); 4642 public final ArrayList<Service> services = new ArrayList<Service>(0); 4643 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0); 4644 4645 public final ArrayList<String> requestedPermissions = new ArrayList<String>(); 4646 4647 public ArrayList<String> protectedBroadcasts; 4648 4649 public Package parentPackage; 4650 public ArrayList<Package> childPackages; 4651 4652 public ArrayList<String> libraryNames = null; 4653 public ArrayList<String> usesLibraries = null; 4654 public ArrayList<String> usesOptionalLibraries = null; 4655 public String[] usesLibraryFiles = null; 4656 4657 public ArrayList<ActivityIntentInfo> preferredActivityFilters = null; 4658 4659 public ArrayList<String> mOriginalPackages = null; 4660 public String mRealPackage = null; 4661 public ArrayList<String> mAdoptPermissions = null; 4662 4663 // We store the application meta-data independently to avoid multiple unwanted references 4664 public Bundle mAppMetaData = null; 4665 4666 // The version code declared for this package. 4667 public int mVersionCode; 4668 4669 // The version name declared for this package. 4670 public String mVersionName; 4671 4672 // The shared user id that this package wants to use. 4673 public String mSharedUserId; 4674 4675 // The shared user label that this package wants to use. 4676 public int mSharedUserLabel; 4677 4678 // Signatures that were read from the package. 4679 public Signature[] mSignatures; 4680 public Certificate[][] mCertificates; 4681 4682 // For use by package manager service for quick lookup of 4683 // preferred up order. 4684 public int mPreferredOrder = 0; 4685 4686 // For use by package manager to keep track of where it needs to do dexopt. 4687 public final ArraySet<String> mDexOptPerformed = new ArraySet<>(4); 4688 4689 // For use by package manager to keep track of when a package was last used. 4690 public long mLastPackageUsageTimeInMills; 4691 4692 // // User set enabled state. 4693 // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; 4694 // 4695 // // Whether the package has been stopped. 4696 // public boolean mSetStopped = false; 4697 4698 // Additional data supplied by callers. 4699 public Object mExtras; 4700 4701 // Applications hardware preferences 4702 public ArrayList<ConfigurationInfo> configPreferences = null; 4703 4704 // Applications requested features 4705 public ArrayList<FeatureInfo> reqFeatures = null; 4706 4707 // Applications requested feature groups 4708 public ArrayList<FeatureGroupInfo> featureGroups = null; 4709 4710 public int installLocation; 4711 4712 public boolean coreApp; 4713 4714 /* An app that's required for all users and cannot be uninstalled for a user */ 4715 public boolean mRequiredForAllUsers; 4716 4717 /* The restricted account authenticator type that is used by this application */ 4718 public String mRestrictedAccountType; 4719 4720 /* The required account type without which this application will not function */ 4721 public String mRequiredAccountType; 4722 4723 public String mOverlayTarget; 4724 public int mOverlayPriority; 4725 public boolean mTrustedOverlay; 4726 4727 /** 4728 * Data used to feed the KeySetManagerService 4729 */ 4730 public ArraySet<PublicKey> mSigningKeys; 4731 public ArraySet<String> mUpgradeKeySets; 4732 public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping; 4733 4734 /** 4735 * The install time abi override for this package, if any. 4736 * 4737 * TODO: This seems like a horrible place to put the abiOverride because 4738 * this isn't something the packageParser parsers. However, this fits in with 4739 * the rest of the PackageManager where package scanning randomly pushes 4740 * and prods fields out of {@code this.applicationInfo}. 4741 */ 4742 public String cpuAbiOverride; 4743 4744 public Package(String packageName) { 4745 this.packageName = packageName; 4746 applicationInfo.packageName = packageName; 4747 applicationInfo.uid = -1; 4748 } 4749 4750 public void setApplicationVolumeUuid(String volumeUuid) { 4751 this.applicationInfo.volumeUuid = volumeUuid; 4752 if (childPackages != null) { 4753 final int packageCount = childPackages.size(); 4754 for (int i = 0; i < packageCount; i++) { 4755 childPackages.get(i).applicationInfo.volumeUuid = volumeUuid; 4756 } 4757 } 4758 } 4759 4760 public void setApplicationInfoCodePath(String codePath) { 4761 this.applicationInfo.setCodePath(codePath); 4762 if (childPackages != null) { 4763 final int packageCount = childPackages.size(); 4764 for (int i = 0; i < packageCount; i++) { 4765 childPackages.get(i).applicationInfo.setCodePath(codePath); 4766 } 4767 } 4768 } 4769 4770 public void setApplicationInfoResourcePath(String resourcePath) { 4771 this.applicationInfo.setResourcePath(resourcePath); 4772 if (childPackages != null) { 4773 final int packageCount = childPackages.size(); 4774 for (int i = 0; i < packageCount; i++) { 4775 childPackages.get(i).applicationInfo.setResourcePath(resourcePath); 4776 } 4777 } 4778 } 4779 4780 public void setApplicationInfoBaseResourcePath(String resourcePath) { 4781 this.applicationInfo.setBaseResourcePath(resourcePath); 4782 if (childPackages != null) { 4783 final int packageCount = childPackages.size(); 4784 for (int i = 0; i < packageCount; i++) { 4785 childPackages.get(i).applicationInfo.setBaseResourcePath(resourcePath); 4786 } 4787 } 4788 } 4789 4790 public void setApplicationInfoBaseCodePath(String baseCodePath) { 4791 this.applicationInfo.setBaseCodePath(baseCodePath); 4792 if (childPackages != null) { 4793 final int packageCount = childPackages.size(); 4794 for (int i = 0; i < packageCount; i++) { 4795 childPackages.get(i).applicationInfo.setBaseCodePath(baseCodePath); 4796 } 4797 } 4798 } 4799 4800 public boolean hasChildPackage(String packageName) { 4801 final int childCount = (childPackages != null) ? childPackages.size() : 0; 4802 for (int i = 0; i < childCount; i++) { 4803 if (childPackages.get(i).packageName.equals(packageName)) { 4804 return true; 4805 } 4806 } 4807 return false; 4808 } 4809 4810 public void setApplicationInfoSplitCodePaths(String[] splitCodePaths) { 4811 this.applicationInfo.setSplitCodePaths(splitCodePaths); 4812 // Children have no splits 4813 } 4814 4815 public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) { 4816 this.applicationInfo.setSplitResourcePaths(resroucePaths); 4817 // Children have no splits 4818 } 4819 4820 public void setSplitCodePaths(String[] codePaths) { 4821 this.splitCodePaths = codePaths; 4822 } 4823 4824 public void setCodePath(String codePath) { 4825 this.codePath = codePath; 4826 if (childPackages != null) { 4827 final int packageCount = childPackages.size(); 4828 for (int i = 0; i < packageCount; i++) { 4829 childPackages.get(i).codePath = codePath; 4830 } 4831 } 4832 } 4833 4834 public void setBaseCodePath(String baseCodePath) { 4835 this.baseCodePath = baseCodePath; 4836 if (childPackages != null) { 4837 final int packageCount = childPackages.size(); 4838 for (int i = 0; i < packageCount; i++) { 4839 childPackages.get(i).baseCodePath = baseCodePath; 4840 } 4841 } 4842 } 4843 4844 public void setSignatures(Signature[] signatures) { 4845 this.mSignatures = signatures; 4846 if (childPackages != null) { 4847 final int packageCount = childPackages.size(); 4848 for (int i = 0; i < packageCount; i++) { 4849 childPackages.get(i).mSignatures = signatures; 4850 } 4851 } 4852 } 4853 4854 public void setVolumeUuid(String volumeUuid) { 4855 this.volumeUuid = volumeUuid; 4856 if (childPackages != null) { 4857 final int packageCount = childPackages.size(); 4858 for (int i = 0; i < packageCount; i++) { 4859 childPackages.get(i).volumeUuid = volumeUuid; 4860 } 4861 } 4862 } 4863 4864 public void setApplicationInfoFlags(int mask, int flags) { 4865 applicationInfo.flags = (applicationInfo.flags & ~mask) | (mask & flags); 4866 if (childPackages != null) { 4867 final int packageCount = childPackages.size(); 4868 for (int i = 0; i < packageCount; i++) { 4869 childPackages.get(i).applicationInfo.flags = 4870 (applicationInfo.flags & ~mask) | (mask & flags); 4871 } 4872 } 4873 } 4874 4875 public void setCpuAbiOverride(String cpuAbiOverride) { 4876 this.cpuAbiOverride = cpuAbiOverride; 4877 if (childPackages != null) { 4878 final int packageCount = childPackages.size(); 4879 for (int i = 0; i < packageCount; i++) { 4880 childPackages.get(i).cpuAbiOverride = cpuAbiOverride; 4881 } 4882 } 4883 } 4884 4885 public List<String> getAllCodePaths() { 4886 ArrayList<String> paths = new ArrayList<>(); 4887 paths.add(baseCodePath); 4888 if (!ArrayUtils.isEmpty(splitCodePaths)) { 4889 Collections.addAll(paths, splitCodePaths); 4890 } 4891 return paths; 4892 } 4893 4894 /** 4895 * Filtered set of {@link #getAllCodePaths()} that excludes 4896 * resource-only APKs. 4897 */ 4898 public List<String> getAllCodePathsExcludingResourceOnly() { 4899 ArrayList<String> paths = new ArrayList<>(); 4900 if ((applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { 4901 paths.add(baseCodePath); 4902 } 4903 if (!ArrayUtils.isEmpty(splitCodePaths)) { 4904 for (int i = 0; i < splitCodePaths.length; i++) { 4905 if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { 4906 paths.add(splitCodePaths[i]); 4907 } 4908 } 4909 } 4910 return paths; 4911 } 4912 4913 public void setPackageName(String newName) { 4914 packageName = newName; 4915 applicationInfo.packageName = newName; 4916 for (int i=permissions.size()-1; i>=0; i--) { 4917 permissions.get(i).setPackageName(newName); 4918 } 4919 for (int i=permissionGroups.size()-1; i>=0; i--) { 4920 permissionGroups.get(i).setPackageName(newName); 4921 } 4922 for (int i=activities.size()-1; i>=0; i--) { 4923 activities.get(i).setPackageName(newName); 4924 } 4925 for (int i=receivers.size()-1; i>=0; i--) { 4926 receivers.get(i).setPackageName(newName); 4927 } 4928 for (int i=providers.size()-1; i>=0; i--) { 4929 providers.get(i).setPackageName(newName); 4930 } 4931 for (int i=services.size()-1; i>=0; i--) { 4932 services.get(i).setPackageName(newName); 4933 } 4934 for (int i=instrumentation.size()-1; i>=0; i--) { 4935 instrumentation.get(i).setPackageName(newName); 4936 } 4937 } 4938 4939 public boolean hasComponentClassName(String name) { 4940 for (int i=activities.size()-1; i>=0; i--) { 4941 if (name.equals(activities.get(i).className)) { 4942 return true; 4943 } 4944 } 4945 for (int i=receivers.size()-1; i>=0; i--) { 4946 if (name.equals(receivers.get(i).className)) { 4947 return true; 4948 } 4949 } 4950 for (int i=providers.size()-1; i>=0; i--) { 4951 if (name.equals(providers.get(i).className)) { 4952 return true; 4953 } 4954 } 4955 for (int i=services.size()-1; i>=0; i--) { 4956 if (name.equals(services.get(i).className)) { 4957 return true; 4958 } 4959 } 4960 for (int i=instrumentation.size()-1; i>=0; i--) { 4961 if (name.equals(instrumentation.get(i).className)) { 4962 return true; 4963 } 4964 } 4965 return false; 4966 } 4967 4968 /** 4969 * @hide 4970 */ 4971 public boolean isForwardLocked() { 4972 return applicationInfo.isForwardLocked(); 4973 } 4974 4975 /** 4976 * @hide 4977 */ 4978 public boolean isSystemApp() { 4979 return applicationInfo.isSystemApp(); 4980 } 4981 4982 /** 4983 * @hide 4984 */ 4985 public boolean isPrivilegedApp() { 4986 return applicationInfo.isPrivilegedApp(); 4987 } 4988 4989 /** 4990 * @hide 4991 */ 4992 public boolean isUpdatedSystemApp() { 4993 return applicationInfo.isUpdatedSystemApp(); 4994 } 4995 4996 /** 4997 * @hide 4998 */ 4999 public boolean canHaveOatDir() { 5000 // The following app types CANNOT have oat directory 5001 // - non-updated system apps 5002 // - forward-locked apps or apps installed in ASEC containers 5003 return (!isSystemApp() || isUpdatedSystemApp()) 5004 && !isForwardLocked() && !applicationInfo.isExternalAsec(); 5005 } 5006 5007 public boolean isMatch(int flags) { 5008 if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { 5009 return isSystemApp(); 5010 } 5011 return true; 5012 } 5013 5014 public String toString() { 5015 return "Package{" 5016 + Integer.toHexString(System.identityHashCode(this)) 5017 + " " + packageName + "}"; 5018 } 5019 } 5020 5021 public static class Component<II extends IntentInfo> { 5022 public final Package owner; 5023 public final ArrayList<II> intents; 5024 public final String className; 5025 public Bundle metaData; 5026 5027 ComponentName componentName; 5028 String componentShortName; 5029 5030 public Component(Package _owner) { 5031 owner = _owner; 5032 intents = null; 5033 className = null; 5034 } 5035 5036 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) { 5037 owner = args.owner; 5038 intents = new ArrayList<II>(0); 5039 String name = args.sa.getNonConfigurationString(args.nameRes, 0); 5040 if (name == null) { 5041 className = null; 5042 args.outError[0] = args.tag + " does not specify android:name"; 5043 return; 5044 } 5045 5046 outInfo.name 5047 = buildClassName(owner.applicationInfo.packageName, name, args.outError); 5048 if (outInfo.name == null) { 5049 className = null; 5050 args.outError[0] = args.tag + " does not have valid android:name"; 5051 return; 5052 } 5053 5054 className = outInfo.name; 5055 5056 int iconVal = args.sa.getResourceId(args.iconRes, 0); 5057 if (iconVal != 0) { 5058 outInfo.icon = iconVal; 5059 outInfo.nonLocalizedLabel = null; 5060 } 5061 5062 int logoVal = args.sa.getResourceId(args.logoRes, 0); 5063 if (logoVal != 0) { 5064 outInfo.logo = logoVal; 5065 } 5066 5067 int bannerVal = args.sa.getResourceId(args.bannerRes, 0); 5068 if (bannerVal != 0) { 5069 outInfo.banner = bannerVal; 5070 } 5071 5072 TypedValue v = args.sa.peekValue(args.labelRes); 5073 if (v != null && (outInfo.labelRes=v.resourceId) == 0) { 5074 outInfo.nonLocalizedLabel = v.coerceToString(); 5075 } 5076 5077 outInfo.packageName = owner.packageName; 5078 } 5079 5080 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) { 5081 this(args, (PackageItemInfo)outInfo); 5082 if (args.outError[0] != null) { 5083 return; 5084 } 5085 5086 if (args.processRes != 0) { 5087 CharSequence pname; 5088 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) { 5089 pname = args.sa.getNonConfigurationString(args.processRes, 5090 Configuration.NATIVE_CONFIG_VERSION); 5091 } else { 5092 // Some older apps have been seen to use a resource reference 5093 // here that on older builds was ignored (with a warning). We 5094 // need to continue to do this for them so they don't break. 5095 pname = args.sa.getNonResourceString(args.processRes); 5096 } 5097 outInfo.processName = buildProcessName(owner.applicationInfo.packageName, 5098 owner.applicationInfo.processName, pname, 5099 args.flags, args.sepProcesses, args.outError); 5100 } 5101 5102 if (args.descriptionRes != 0) { 5103 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0); 5104 } 5105 5106 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true); 5107 } 5108 5109 public Component(Component<II> clone) { 5110 owner = clone.owner; 5111 intents = clone.intents; 5112 className = clone.className; 5113 componentName = clone.componentName; 5114 componentShortName = clone.componentShortName; 5115 } 5116 5117 public ComponentName getComponentName() { 5118 if (componentName != null) { 5119 return componentName; 5120 } 5121 if (className != null) { 5122 componentName = new ComponentName(owner.applicationInfo.packageName, 5123 className); 5124 } 5125 return componentName; 5126 } 5127 5128 public void appendComponentShortName(StringBuilder sb) { 5129 ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className); 5130 } 5131 5132 public void printComponentShortName(PrintWriter pw) { 5133 ComponentName.printShortString(pw, owner.applicationInfo.packageName, className); 5134 } 5135 5136 public void setPackageName(String packageName) { 5137 componentName = null; 5138 componentShortName = null; 5139 } 5140 } 5141 5142 public final static class Permission extends Component<IntentInfo> { 5143 public final PermissionInfo info; 5144 public boolean tree; 5145 public PermissionGroup group; 5146 5147 public Permission(Package _owner) { 5148 super(_owner); 5149 info = new PermissionInfo(); 5150 } 5151 5152 public Permission(Package _owner, PermissionInfo _info) { 5153 super(_owner); 5154 info = _info; 5155 } 5156 5157 public void setPackageName(String packageName) { 5158 super.setPackageName(packageName); 5159 info.packageName = packageName; 5160 } 5161 5162 public String toString() { 5163 return "Permission{" 5164 + Integer.toHexString(System.identityHashCode(this)) 5165 + " " + info.name + "}"; 5166 } 5167 } 5168 5169 public final static class PermissionGroup extends Component<IntentInfo> { 5170 public final PermissionGroupInfo info; 5171 5172 public PermissionGroup(Package _owner) { 5173 super(_owner); 5174 info = new PermissionGroupInfo(); 5175 } 5176 5177 public PermissionGroup(Package _owner, PermissionGroupInfo _info) { 5178 super(_owner); 5179 info = _info; 5180 } 5181 5182 public void setPackageName(String packageName) { 5183 super.setPackageName(packageName); 5184 info.packageName = packageName; 5185 } 5186 5187 public String toString() { 5188 return "PermissionGroup{" 5189 + Integer.toHexString(System.identityHashCode(this)) 5190 + " " + info.name + "}"; 5191 } 5192 } 5193 5194 private static boolean copyNeeded(int flags, Package p, 5195 PackageUserState state, Bundle metaData, int userId) { 5196 if (userId != UserHandle.USER_SYSTEM) { 5197 // We always need to copy for other users, since we need 5198 // to fix up the uid. 5199 return true; 5200 } 5201 if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { 5202 boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 5203 if (p.applicationInfo.enabled != enabled) { 5204 return true; 5205 } 5206 } 5207 if (!state.installed || state.hidden) { 5208 return true; 5209 } 5210 if (state.stopped) { 5211 return true; 5212 } 5213 if ((flags & PackageManager.GET_META_DATA) != 0 5214 && (metaData != null || p.mAppMetaData != null)) { 5215 return true; 5216 } 5217 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 5218 && p.usesLibraryFiles != null) { 5219 return true; 5220 } 5221 return false; 5222 } 5223 5224 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 5225 PackageUserState state) { 5226 return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId()); 5227 } 5228 5229 private static void updateApplicationInfo(ApplicationInfo ai, int flags, 5230 PackageUserState state) { 5231 // CompatibilityMode is global state. 5232 if (!sCompatibilityModeEnabled) { 5233 ai.disableCompatibilityMode(); 5234 } 5235 if (state.installed) { 5236 ai.flags |= ApplicationInfo.FLAG_INSTALLED; 5237 } else { 5238 ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; 5239 } 5240 if (state.suspended) { 5241 ai.flags |= ApplicationInfo.FLAG_SUSPENDED; 5242 } else { 5243 ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED; 5244 } 5245 if (state.hidden) { 5246 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN; 5247 } else { 5248 ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN; 5249 } 5250 if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { 5251 ai.enabled = true; 5252 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { 5253 ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0; 5254 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED 5255 || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { 5256 ai.enabled = false; 5257 } 5258 ai.enabledSetting = state.enabled; 5259 } 5260 5261 public static ApplicationInfo generateApplicationInfo(Package p, int flags, 5262 PackageUserState state, int userId) { 5263 if (p == null) return null; 5264 if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) { 5265 return null; 5266 } 5267 if (!copyNeeded(flags, p, state, null, userId) 5268 && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0 5269 || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { 5270 // In this case it is safe to directly modify the internal ApplicationInfo state: 5271 // - CompatibilityMode is global state, so will be the same for every call. 5272 // - We only come in to here if the app should reported as installed; this is the 5273 // default state, and we will do a copy otherwise. 5274 // - The enable state will always be reported the same for the application across 5275 // calls; the only exception is for the UNTIL_USED mode, and in that case we will 5276 // be doing a copy. 5277 updateApplicationInfo(p.applicationInfo, flags, state); 5278 return p.applicationInfo; 5279 } 5280 5281 // Make shallow copy so we can store the metadata/libraries safely 5282 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo); 5283 ai.initForUser(userId); 5284 if ((flags & PackageManager.GET_META_DATA) != 0) { 5285 ai.metaData = p.mAppMetaData; 5286 } 5287 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { 5288 ai.sharedLibraryFiles = p.usesLibraryFiles; 5289 } 5290 if (state.stopped) { 5291 ai.flags |= ApplicationInfo.FLAG_STOPPED; 5292 } else { 5293 ai.flags &= ~ApplicationInfo.FLAG_STOPPED; 5294 } 5295 updateApplicationInfo(ai, flags, state); 5296 return ai; 5297 } 5298 5299 public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags, 5300 PackageUserState state, int userId) { 5301 if (ai == null) return null; 5302 if (!checkUseInstalledOrHidden(flags, state)) { 5303 return null; 5304 } 5305 // This is only used to return the ResolverActivity; we will just always 5306 // make a copy. 5307 ai = new ApplicationInfo(ai); 5308 ai.initForUser(userId); 5309 if (state.stopped) { 5310 ai.flags |= ApplicationInfo.FLAG_STOPPED; 5311 } else { 5312 ai.flags &= ~ApplicationInfo.FLAG_STOPPED; 5313 } 5314 updateApplicationInfo(ai, flags, state); 5315 return ai; 5316 } 5317 5318 public static final PermissionInfo generatePermissionInfo( 5319 Permission p, int flags) { 5320 if (p == null) return null; 5321 if ((flags&PackageManager.GET_META_DATA) == 0) { 5322 return p.info; 5323 } 5324 PermissionInfo pi = new PermissionInfo(p.info); 5325 pi.metaData = p.metaData; 5326 return pi; 5327 } 5328 5329 public static final PermissionGroupInfo generatePermissionGroupInfo( 5330 PermissionGroup pg, int flags) { 5331 if (pg == null) return null; 5332 if ((flags&PackageManager.GET_META_DATA) == 0) { 5333 return pg.info; 5334 } 5335 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info); 5336 pgi.metaData = pg.metaData; 5337 return pgi; 5338 } 5339 5340 public final static class Activity extends Component<ActivityIntentInfo> { 5341 public final ActivityInfo info; 5342 5343 public Activity(final ParseComponentArgs args, final ActivityInfo _info) { 5344 super(args, _info); 5345 info = _info; 5346 info.applicationInfo = args.owner.applicationInfo; 5347 } 5348 5349 public void setPackageName(String packageName) { 5350 super.setPackageName(packageName); 5351 info.packageName = packageName; 5352 } 5353 5354 public String toString() { 5355 StringBuilder sb = new StringBuilder(128); 5356 sb.append("Activity{"); 5357 sb.append(Integer.toHexString(System.identityHashCode(this))); 5358 sb.append(' '); 5359 appendComponentShortName(sb); 5360 sb.append('}'); 5361 return sb.toString(); 5362 } 5363 } 5364 5365 public static final ActivityInfo generateActivityInfo(Activity a, int flags, 5366 PackageUserState state, int userId) { 5367 if (a == null) return null; 5368 if (!checkUseInstalledOrHidden(flags, state)) { 5369 return null; 5370 } 5371 if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) { 5372 return a.info; 5373 } 5374 // Make shallow copies so we can store the metadata safely 5375 ActivityInfo ai = new ActivityInfo(a.info); 5376 ai.metaData = a.metaData; 5377 ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId); 5378 return ai; 5379 } 5380 5381 public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags, 5382 PackageUserState state, int userId) { 5383 if (ai == null) return null; 5384 if (!checkUseInstalledOrHidden(flags, state)) { 5385 return null; 5386 } 5387 // This is only used to return the ResolverActivity; we will just always 5388 // make a copy. 5389 ai = new ActivityInfo(ai); 5390 ai.applicationInfo = generateApplicationInfo(ai.applicationInfo, flags, state, userId); 5391 return ai; 5392 } 5393 5394 public final static class Service extends Component<ServiceIntentInfo> { 5395 public final ServiceInfo info; 5396 5397 public Service(final ParseComponentArgs args, final ServiceInfo _info) { 5398 super(args, _info); 5399 info = _info; 5400 info.applicationInfo = args.owner.applicationInfo; 5401 } 5402 5403 public void setPackageName(String packageName) { 5404 super.setPackageName(packageName); 5405 info.packageName = packageName; 5406 } 5407 5408 public String toString() { 5409 StringBuilder sb = new StringBuilder(128); 5410 sb.append("Service{"); 5411 sb.append(Integer.toHexString(System.identityHashCode(this))); 5412 sb.append(' '); 5413 appendComponentShortName(sb); 5414 sb.append('}'); 5415 return sb.toString(); 5416 } 5417 } 5418 5419 public static final ServiceInfo generateServiceInfo(Service s, int flags, 5420 PackageUserState state, int userId) { 5421 if (s == null) return null; 5422 if (!checkUseInstalledOrHidden(flags, state)) { 5423 return null; 5424 } 5425 if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) { 5426 return s.info; 5427 } 5428 // Make shallow copies so we can store the metadata safely 5429 ServiceInfo si = new ServiceInfo(s.info); 5430 si.metaData = s.metaData; 5431 si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId); 5432 return si; 5433 } 5434 5435 public final static class Provider extends Component<ProviderIntentInfo> { 5436 public final ProviderInfo info; 5437 public boolean syncable; 5438 5439 public Provider(final ParseComponentArgs args, final ProviderInfo _info) { 5440 super(args, _info); 5441 info = _info; 5442 info.applicationInfo = args.owner.applicationInfo; 5443 syncable = false; 5444 } 5445 5446 public Provider(Provider existingProvider) { 5447 super(existingProvider); 5448 this.info = existingProvider.info; 5449 this.syncable = existingProvider.syncable; 5450 } 5451 5452 public void setPackageName(String packageName) { 5453 super.setPackageName(packageName); 5454 info.packageName = packageName; 5455 } 5456 5457 public String toString() { 5458 StringBuilder sb = new StringBuilder(128); 5459 sb.append("Provider{"); 5460 sb.append(Integer.toHexString(System.identityHashCode(this))); 5461 sb.append(' '); 5462 appendComponentShortName(sb); 5463 sb.append('}'); 5464 return sb.toString(); 5465 } 5466 } 5467 5468 public static final ProviderInfo generateProviderInfo(Provider p, int flags, 5469 PackageUserState state, int userId) { 5470 if (p == null) return null; 5471 if (!checkUseInstalledOrHidden(flags, state)) { 5472 return null; 5473 } 5474 if (!copyNeeded(flags, p.owner, state, p.metaData, userId) 5475 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 5476 || p.info.uriPermissionPatterns == null)) { 5477 return p.info; 5478 } 5479 // Make shallow copies so we can store the metadata safely 5480 ProviderInfo pi = new ProviderInfo(p.info); 5481 pi.metaData = p.metaData; 5482 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { 5483 pi.uriPermissionPatterns = null; 5484 } 5485 pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId); 5486 return pi; 5487 } 5488 5489 public final static class Instrumentation extends Component { 5490 public final InstrumentationInfo info; 5491 5492 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) { 5493 super(args, _info); 5494 info = _info; 5495 } 5496 5497 public void setPackageName(String packageName) { 5498 super.setPackageName(packageName); 5499 info.packageName = packageName; 5500 } 5501 5502 public String toString() { 5503 StringBuilder sb = new StringBuilder(128); 5504 sb.append("Instrumentation{"); 5505 sb.append(Integer.toHexString(System.identityHashCode(this))); 5506 sb.append(' '); 5507 appendComponentShortName(sb); 5508 sb.append('}'); 5509 return sb.toString(); 5510 } 5511 } 5512 5513 public static final InstrumentationInfo generateInstrumentationInfo( 5514 Instrumentation i, int flags) { 5515 if (i == null) return null; 5516 if ((flags&PackageManager.GET_META_DATA) == 0) { 5517 return i.info; 5518 } 5519 InstrumentationInfo ii = new InstrumentationInfo(i.info); 5520 ii.metaData = i.metaData; 5521 return ii; 5522 } 5523 5524 public static class IntentInfo extends IntentFilter { 5525 public boolean hasDefault; 5526 public int labelRes; 5527 public CharSequence nonLocalizedLabel; 5528 public int icon; 5529 public int logo; 5530 public int banner; 5531 public int preferred; 5532 } 5533 5534 public final static class ActivityIntentInfo extends IntentInfo { 5535 public final Activity activity; 5536 5537 public ActivityIntentInfo(Activity _activity) { 5538 activity = _activity; 5539 } 5540 5541 public String toString() { 5542 StringBuilder sb = new StringBuilder(128); 5543 sb.append("ActivityIntentInfo{"); 5544 sb.append(Integer.toHexString(System.identityHashCode(this))); 5545 sb.append(' '); 5546 activity.appendComponentShortName(sb); 5547 sb.append('}'); 5548 return sb.toString(); 5549 } 5550 } 5551 5552 public final static class ServiceIntentInfo extends IntentInfo { 5553 public final Service service; 5554 5555 public ServiceIntentInfo(Service _service) { 5556 service = _service; 5557 } 5558 5559 public String toString() { 5560 StringBuilder sb = new StringBuilder(128); 5561 sb.append("ServiceIntentInfo{"); 5562 sb.append(Integer.toHexString(System.identityHashCode(this))); 5563 sb.append(' '); 5564 service.appendComponentShortName(sb); 5565 sb.append('}'); 5566 return sb.toString(); 5567 } 5568 } 5569 5570 public static final class ProviderIntentInfo extends IntentInfo { 5571 public final Provider provider; 5572 5573 public ProviderIntentInfo(Provider provider) { 5574 this.provider = provider; 5575 } 5576 5577 public String toString() { 5578 StringBuilder sb = new StringBuilder(128); 5579 sb.append("ProviderIntentInfo{"); 5580 sb.append(Integer.toHexString(System.identityHashCode(this))); 5581 sb.append(' '); 5582 provider.appendComponentShortName(sb); 5583 sb.append('}'); 5584 return sb.toString(); 5585 } 5586 } 5587 5588 /** 5589 * @hide 5590 */ 5591 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) { 5592 sCompatibilityModeEnabled = compatibilityModeEnabled; 5593 } 5594 5595 private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>(); 5596 5597 public static long readFullyIgnoringContents(InputStream in) throws IOException { 5598 byte[] buffer = sBuffer.getAndSet(null); 5599 if (buffer == null) { 5600 buffer = new byte[4096]; 5601 } 5602 5603 int n = 0; 5604 int count = 0; 5605 while ((n = in.read(buffer, 0, buffer.length)) != -1) { 5606 count += n; 5607 } 5608 5609 sBuffer.set(buffer); 5610 return count; 5611 } 5612 5613 public static void closeQuietly(StrictJarFile jarFile) { 5614 if (jarFile != null) { 5615 try { 5616 jarFile.close(); 5617 } catch (Exception ignored) { 5618 } 5619 } 5620 } 5621 5622 public static class PackageParserException extends Exception { 5623 public final int error; 5624 5625 public PackageParserException(int error, String detailMessage) { 5626 super(detailMessage); 5627 this.error = error; 5628 } 5629 5630 public PackageParserException(int error, String detailMessage, Throwable throwable) { 5631 super(detailMessage, throwable); 5632 this.error = error; 5633 } 5634 } 5635} 5636