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