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