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