2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.content.pm;
19 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
20 import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
21 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
22 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
23 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
24 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
25 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
26 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
27 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
28 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
29 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
30 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
31 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
32 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
33 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
34 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
35 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
36 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
37 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
38 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
39 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
40 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
41 import static android.os.Build.VERSION_CODES.O;
42 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
43 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
45 import android.annotation.IntRange;
46 import android.annotation.NonNull;
47 import android.annotation.Nullable;
48 import android.annotation.TestApi;
49 import android.app.ActivityManager;
50 import android.content.ComponentName;
51 import android.content.Intent;
52 import android.content.IntentFilter;
53 import android.content.pm.split.SplitAssetDependencyLoader;
54 import android.content.pm.split.SplitAssetLoader;
55 import android.content.pm.split.DefaultSplitAssetLoader;
56 import android.content.res.AssetManager;
57 import android.content.res.Configuration;
58 import android.content.res.Resources;
59 import android.content.res.TypedArray;
60 import android.content.res.XmlResourceParser;
61 import android.os.Build;
62 import android.os.Bundle;
63 import android.os.FileUtils;
64 import android.os.Parcel;
65 import android.os.Parcelable;
66 import android.os.PatternMatcher;
67 import android.os.SystemProperties;
68 import android.os.Trace;
69 import android.os.UserHandle;
70 import android.os.storage.StorageManager;
71 import android.system.ErrnoException;
72 import android.system.OsConstants;
73 import android.system.StructStat;
74 import android.text.TextUtils;
75 import android.util.ArrayMap;
76 import android.util.ArraySet;
77 import android.util.AttributeSet;
78 import android.util.Base64;
79 import android.util.DisplayMetrics;
80 import android.util.Log;
81 import android.util.Pair;
82 import android.util.Slog;
83 import android.util.SparseArray;
84 import android.util.TypedValue;
85 import android.util.apk.ApkSignatureSchemeV2Verifier;
86 import android.util.jar.StrictJarFile;
87 import android.view.Gravity;
89 import com.android.internal.R;
90 import com.android.internal.annotations.VisibleForTesting;
91 import com.android.internal.util.ArrayUtils;
92 import com.android.internal.util.XmlUtils;
94 import libcore.io.IoUtils;
96 import org.xmlpull.v1.XmlPullParser;
97 import org.xmlpull.v1.XmlPullParserException;
100 import java.io.FileOutputStream;
101 import java.io.IOException;
102 import java.io.InputStream;
103 import java.io.PrintWriter;
104 import java.lang.reflect.Constructor;
105 import java.security.GeneralSecurityException;
106 import java.security.KeyFactory;
107 import java.security.NoSuchAlgorithmException;
108 import java.security.PublicKey;
109 import java.security.cert.Certificate;
110 import java.security.cert.CertificateEncodingException;
111 import java.security.spec.EncodedKeySpec;
112 import java.security.spec.InvalidKeySpecException;
113 import java.security.spec.X509EncodedKeySpec;
114 import java.util.ArrayList;
115 import java.util.Arrays;
116 import java.util.Collections;
117 import java.util.Comparator;
118 import java.util.Iterator;
119 import java.util.List;
120 import java.util.Set;
121 import java.util.UUID;
122 import java.util.concurrent.atomic.AtomicReference;
123 import java.util.zip.ZipEntry;
126 * Parser for package files (APKs) on disk. This supports apps packaged either
127 * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple
128 * APKs in a single directory.
130 * Apps packaged as multiple APKs always consist of a single "base" APK (with a
131 * {@code null} split name) and zero or more "split" APKs (with unique split
132 * names). Any subset of those split APKs are a valid install, as long as the
133 * following constraints are met:
135 * <li>All APKs must have the exact same package name, version code, and signing
137 * <li>All APKs must have unique split names.
138 * <li>All installations must contain a single base APK.
143 public class PackageParser {
144 private static final boolean DEBUG_JAR = false;
145 private static final boolean DEBUG_PARSER = false;
146 private static final boolean DEBUG_BACKUP = false;
148 private static final String PROPERTY_CHILD_PACKAGES_ENABLED =
149 "persist.sys.child_packages_enabled";
151 private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
152 SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
154 private static final int MAX_PACKAGES_PER_APK = 5;
156 public static final int APK_SIGNING_UNKNOWN = 0;
157 public static final int APK_SIGNING_V1 = 1;
158 public static final int APK_SIGNING_V2 = 2;
160 private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
162 // TODO: switch outError users to PackageParserException
163 // TODO: refactor "codePath" to "apkPath"
165 /** File name in an APK for the Android manifest. */
166 private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
168 /** Path prefix for apps on expanded storage */
169 private static final String MNT_EXPAND = "/mnt/expand/";
171 private static final String TAG_MANIFEST = "manifest";
172 private static final String TAG_APPLICATION = "application";
173 private static final String TAG_PACKAGE_VERIFIER = "package-verifier";
174 private static final String TAG_OVERLAY = "overlay";
175 private static final String TAG_KEY_SETS = "key-sets";
176 private static final String TAG_PERMISSION_GROUP = "permission-group";
177 private static final String TAG_PERMISSION = "permission";
178 private static final String TAG_PERMISSION_TREE = "permission-tree";
179 private static final String TAG_USES_PERMISSION = "uses-permission";
180 private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
181 private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";
182 private static final String TAG_USES_CONFIGURATION = "uses-configuration";
183 private static final String TAG_USES_FEATURE = "uses-feature";
184 private static final String TAG_FEATURE_GROUP = "feature-group";
185 private static final String TAG_USES_SDK = "uses-sdk";
186 private static final String TAG_SUPPORT_SCREENS = "supports-screens";
187 private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";
188 private static final String TAG_INSTRUMENTATION = "instrumentation";
189 private static final String TAG_ORIGINAL_PACKAGE = "original-package";
190 private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
191 private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
192 private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";
193 private static final String TAG_SUPPORTS_INPUT = "supports-input";
194 private static final String TAG_EAT_COMMENT = "eat-comment";
195 private static final String TAG_PACKAGE = "package";
196 private static final String TAG_RESTRICT_UPDATE = "restrict-update";
197 private static final String TAG_USES_SPLIT = "uses-split";
199 // [b/36551762] STOPSHIP remove the ability to expose components via meta-data
200 // Temporary workaround; allow meta-data to expose components to instant apps
201 private static final String META_DATA_INSTANT_APPS = "instantapps.clients.allowed";
203 private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
206 * Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
209 private static final int RECREATE_ON_CONFIG_CHANGES_MASK =
210 ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC;
212 // These are the tags supported by child packages
213 private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
215 CHILD_PACKAGE_TAGS.add(TAG_APPLICATION);
216 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION);
217 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M);
218 CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23);
219 CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION);
220 CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE);
221 CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP);
222 CHILD_PACKAGE_TAGS.add(TAG_USES_SDK);
223 CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS);
224 CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION);
225 CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE);
226 CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS);
227 CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT);
228 CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
231 private static final boolean LOG_UNSAFE_BROADCASTS = false;
233 // Set of broadcast actions that are safe for manifest receivers
234 private static final Set<String> SAFE_BROADCASTS = new ArraySet<>();
236 SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED);
240 public static class NewPermissionInfo {
241 public final String name;
242 public final int sdkVersion;
243 public final int fileVersion;
245 public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {
247 this.sdkVersion = sdkVersion;
248 this.fileVersion = fileVersion;
253 public static class SplitPermissionInfo {
254 public final String rootPerm;
255 public final String[] newPerms;
256 public final int targetSdk;
258 public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
259 this.rootPerm = rootPerm;
260 this.newPerms = newPerms;
261 this.targetSdk = targetSdk;
266 * List of new permissions that have been added since 1.0.
267 * NOTE: These must be declared in SDK version order, with permissions
268 * added to older SDKs appearing before those added to newer SDKs.
269 * If sdkVersion is 0, then this is not a permission that we want to
270 * automatically add to older apps, but we do want to allow it to be
271 * granted during a platform update.
274 public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] =
275 new PackageParser.NewPermissionInfo[] {
276 new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
277 android.os.Build.VERSION_CODES.DONUT, 0),
278 new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE,
279 android.os.Build.VERSION_CODES.DONUT, 0)
283 * List of permissions that have been split into more granular or dependent
287 public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] =
288 new PackageParser.SplitPermissionInfo[] {
289 // READ_EXTERNAL_STORAGE is always required when an app requests
290 // WRITE_EXTERNAL_STORAGE, because we can't have an app that has
291 // write access without read access. The hack here with the target
292 // target SDK version ensures that this grant is always done.
293 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
294 new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE },
295 android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1),
296 new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
297 new String[] { android.Manifest.permission.READ_CALL_LOG },
298 android.os.Build.VERSION_CODES.JELLY_BEAN),
299 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
300 new String[] { android.Manifest.permission.WRITE_CALL_LOG },
301 android.os.Build.VERSION_CODES.JELLY_BEAN)
305 * @deprecated callers should move to explicitly passing around source path.
308 private String mArchiveSourcePath;
310 private String[] mSeparateProcesses;
311 private boolean mOnlyCoreApps;
312 private DisplayMetrics mMetrics;
313 private Callback mCallback;
314 private File mCacheDir;
316 private static final int SDK_VERSION = Build.VERSION.SDK_INT;
317 private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
319 private int mParseError = PackageManager.INSTALL_SUCCEEDED;
321 private static boolean sCompatibilityModeEnabled = true;
322 private static final int PARSE_DEFAULT_INSTALL_LOCATION =
323 PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
324 private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
326 static class ParsePackageItemArgs {
328 final String[] outError;
332 final int roundIconRes;
339 ParsePackageItemArgs(Package _owner, String[] _outError,
340 int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
343 outError = _outError;
345 labelRes = _labelRes;
348 bannerRes = _bannerRes;
349 roundIconRes = _roundIconRes;
355 public static class ParseComponentArgs extends ParsePackageItemArgs {
356 final String[] sepProcesses;
357 final int processRes;
358 final int descriptionRes;
359 final int enabledRes;
362 public ParseComponentArgs(Package _owner, String[] _outError,
363 int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
365 String[] _sepProcesses, int _processRes,
366 int _descriptionRes, int _enabledRes) {
367 super(_owner, _outError, _nameRes, _labelRes, _iconRes, _roundIconRes, _logoRes,
369 sepProcesses = _sepProcesses;
370 processRes = _processRes;
371 descriptionRes = _descriptionRes;
372 enabledRes = _enabledRes;
377 * Lightweight parsed details about a single package.
379 public static class PackageLite {
380 public final String packageName;
381 public final int versionCode;
382 public final int installLocation;
383 public final VerifierInfo[] verifiers;
385 /** Names of any split APKs, ordered by parsed splitName */
386 public final String[] splitNames;
388 /** Names of any split APKs that are features. Ordered by splitName */
389 public final boolean[] isFeatureSplits;
391 /** Dependencies of any split APKs, ordered by parsed splitName */
392 public final String[] usesSplitNames;
393 public final String[] configForSplit;
396 * Path where this package was found on disk. For monolithic packages
397 * this is path to single base APK file; for cluster packages this is
398 * path to the cluster directory.
400 public final String codePath;
402 /** Path of base APK */
403 public final String baseCodePath;
404 /** Paths of any split APKs, ordered by parsed splitName */
405 public final String[] splitCodePaths;
407 /** Revision code of base APK */
408 public final int baseRevisionCode;
409 /** Revision codes of any split APKs, ordered by parsed splitName */
410 public final int[] splitRevisionCodes;
412 public final boolean coreApp;
413 public final boolean debuggable;
414 public final boolean multiArch;
415 public final boolean use32bitAbi;
416 public final boolean extractNativeLibs;
417 public final boolean isolatedSplits;
419 public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
420 boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit,
421 String[] splitCodePaths, int[] splitRevisionCodes) {
422 this.packageName = baseApk.packageName;
423 this.versionCode = baseApk.versionCode;
424 this.installLocation = baseApk.installLocation;
425 this.verifiers = baseApk.verifiers;
426 this.splitNames = splitNames;
427 this.isFeatureSplits = isFeatureSplits;
428 this.usesSplitNames = usesSplitNames;
429 this.configForSplit = configForSplit;
430 this.codePath = codePath;
431 this.baseCodePath = baseApk.codePath;
432 this.splitCodePaths = splitCodePaths;
433 this.baseRevisionCode = baseApk.revisionCode;
434 this.splitRevisionCodes = splitRevisionCodes;
435 this.coreApp = baseApk.coreApp;
436 this.debuggable = baseApk.debuggable;
437 this.multiArch = baseApk.multiArch;
438 this.use32bitAbi = baseApk.use32bitAbi;
439 this.extractNativeLibs = baseApk.extractNativeLibs;
440 this.isolatedSplits = baseApk.isolatedSplits;
443 public List<String> getAllCodePaths() {
444 ArrayList<String> paths = new ArrayList<>();
445 paths.add(baseCodePath);
446 if (!ArrayUtils.isEmpty(splitCodePaths)) {
447 Collections.addAll(paths, splitCodePaths);
454 * Lightweight parsed details about a single APK file.
456 public static class ApkLite {
457 public final String codePath;
458 public final String packageName;
459 public final String splitName;
460 public boolean isFeatureSplit;
461 public final String configForSplit;
462 public final String usesSplitName;
463 public final int versionCode;
464 public final int revisionCode;
465 public final int installLocation;
466 public final VerifierInfo[] verifiers;
467 public final Signature[] signatures;
468 public final Certificate[][] certificates;
469 public final boolean coreApp;
470 public final boolean debuggable;
471 public final boolean multiArch;
472 public final boolean use32bitAbi;
473 public final boolean extractNativeLibs;
474 public final boolean isolatedSplits;
476 public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
477 String configForSplit, String usesSplitName, int versionCode, int revisionCode,
478 int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
479 Certificate[][] certificates, boolean coreApp, boolean debuggable,
480 boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs,
481 boolean isolatedSplits) {
482 this.codePath = codePath;
483 this.packageName = packageName;
484 this.splitName = splitName;
485 this.isFeatureSplit = isFeatureSplit;
486 this.configForSplit = configForSplit;
487 this.usesSplitName = usesSplitName;
488 this.versionCode = versionCode;
489 this.revisionCode = revisionCode;
490 this.installLocation = installLocation;
491 this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
492 this.signatures = signatures;
493 this.certificates = certificates;
494 this.coreApp = coreApp;
495 this.debuggable = debuggable;
496 this.multiArch = multiArch;
497 this.use32bitAbi = use32bitAbi;
498 this.extractNativeLibs = extractNativeLibs;
499 this.isolatedSplits = isolatedSplits;
503 private ParsePackageItemArgs mParseInstrumentationArgs;
504 private ParseComponentArgs mParseActivityArgs;
505 private ParseComponentArgs mParseActivityAliasArgs;
506 private ParseComponentArgs mParseServiceArgs;
507 private ParseComponentArgs mParseProviderArgs;
509 /** If set to true, we will only allow package files that exactly match
510 * the DTD. Otherwise, we try to get as much from the package as we
511 * can without failing. This should normally be set to false, to
512 * support extensions to the DTD in future versions. */
513 private static final boolean RIGID_PARSER = false;
515 private static final String TAG = "PackageParser";
517 public PackageParser() {
518 mMetrics = new DisplayMetrics();
519 mMetrics.setToDefaults();
522 public void setSeparateProcesses(String[] procs) {
523 mSeparateProcesses = procs;
527 * Flag indicating this parser should only consider apps with
528 * {@code coreApp} manifest attribute to be valid apps. This is useful when
529 * creating a minimalist boot environment.
531 public void setOnlyCoreApps(boolean onlyCoreApps) {
532 mOnlyCoreApps = onlyCoreApps;
535 public void setDisplayMetrics(DisplayMetrics metrics) {
540 * Sets the cache directory for this package parser.
542 public void setCacheDir(File cacheDir) {
543 mCacheDir = cacheDir;
547 * Callback interface for retrieving information that may be needed while parsing
550 public interface Callback {
551 boolean hasFeature(String feature);
552 String[] getOverlayPaths(String targetPackageName, String targetPath);
553 String[] getOverlayApks(String targetPackageName);
557 * Standard implementation of {@link Callback} on top of the public {@link PackageManager}
560 public static final class CallbackImpl implements Callback {
561 private final PackageManager mPm;
563 public CallbackImpl(PackageManager pm) {
567 @Override public boolean hasFeature(String feature) {
568 return mPm.hasSystemFeature(feature);
571 @Override public String[] getOverlayPaths(String targetPackageName, String targetPath) {
575 @Override public String[] getOverlayApks(String targetPackageName) {
581 * Set the {@link Callback} that can be used while parsing.
583 public void setCallback(Callback cb) {
587 public static final boolean isApkFile(File file) {
588 return isApkPath(file.getName());
591 public static boolean isApkPath(String path) {
592 return path.endsWith(".apk");
596 * Generate and return the {@link PackageInfo} for a parsed package.
598 * @param p the parsed package.
599 * @param flags indicating which optional information is included.
601 public static PackageInfo generatePackageInfo(PackageParser.Package p,
602 int gids[], int flags, long firstInstallTime, long lastUpdateTime,
603 Set<String> grantedPermissions, PackageUserState state) {
605 return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
606 grantedPermissions, state, UserHandle.getCallingUserId());
610 * Returns true if the package is installed and not hidden, or if the caller
611 * explicitly wanted all uninstalled and hidden packages as well.
612 * @param appInfo The applicationInfo of the app being checked.
614 private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state,
615 ApplicationInfo appInfo) {
616 // If available for the target user, or trying to match uninstalled packages and it's
618 return state.isAvailable(flags)
619 || (appInfo != null && appInfo.isSystemApp()
620 && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0);
623 public static boolean isAvailable(PackageUserState state) {
624 return checkUseInstalledOrHidden(0, state, null);
627 public static PackageInfo generatePackageInfo(PackageParser.Package p,
628 int gids[], int flags, long firstInstallTime, long lastUpdateTime,
629 Set<String> grantedPermissions, PackageUserState state, int userId) {
630 if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
633 PackageInfo pi = new PackageInfo();
634 pi.packageName = p.packageName;
635 pi.splitNames = p.splitNames;
636 pi.versionCode = p.mVersionCode;
637 pi.baseRevisionCode = p.baseRevisionCode;
638 pi.splitRevisionCodes = p.splitRevisionCodes;
639 pi.versionName = p.mVersionName;
640 pi.sharedUserId = p.mSharedUserId;
641 pi.sharedUserLabel = p.mSharedUserLabel;
642 pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
643 pi.installLocation = p.installLocation;
644 pi.coreApp = p.coreApp;
645 if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0
646 || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
647 pi.requiredForAllUsers = p.mRequiredForAllUsers;
649 pi.restrictedAccountType = p.mRestrictedAccountType;
650 pi.requiredAccountType = p.mRequiredAccountType;
651 pi.overlayTarget = p.mOverlayTarget;
652 pi.overlayPriority = p.mOverlayPriority;
653 pi.isStaticOverlay = p.mIsStaticOverlay;
654 pi.firstInstallTime = firstInstallTime;
655 pi.lastUpdateTime = lastUpdateTime;
656 if ((flags&PackageManager.GET_GIDS) != 0) {
659 if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) {
660 int N = p.configPreferences != null ? p.configPreferences.size() : 0;
662 pi.configPreferences = new ConfigurationInfo[N];
663 p.configPreferences.toArray(pi.configPreferences);
665 N = p.reqFeatures != null ? p.reqFeatures.size() : 0;
667 pi.reqFeatures = new FeatureInfo[N];
668 p.reqFeatures.toArray(pi.reqFeatures);
670 N = p.featureGroups != null ? p.featureGroups.size() : 0;
672 pi.featureGroups = new FeatureGroupInfo[N];
673 p.featureGroups.toArray(pi.featureGroups);
676 if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
677 final int N = p.activities.size();
680 final ActivityInfo[] res = new ActivityInfo[N];
681 for (int i = 0; i < N; i++) {
682 final Activity a = p.activities.get(i);
683 if (state.isMatch(a.info, flags)) {
684 res[num++] = generateActivityInfo(a, flags, state, userId);
687 pi.activities = ArrayUtils.trimToSize(res, num);
690 if ((flags & PackageManager.GET_RECEIVERS) != 0) {
691 final int N = p.receivers.size();
694 final ActivityInfo[] res = new ActivityInfo[N];
695 for (int i = 0; i < N; i++) {
696 final Activity a = p.receivers.get(i);
697 if (state.isMatch(a.info, flags)) {
698 res[num++] = generateActivityInfo(a, flags, state, userId);
701 pi.receivers = ArrayUtils.trimToSize(res, num);
704 if ((flags & PackageManager.GET_SERVICES) != 0) {
705 final int N = p.services.size();
708 final ServiceInfo[] res = new ServiceInfo[N];
709 for (int i = 0; i < N; i++) {
710 final Service s = p.services.get(i);
711 if (state.isMatch(s.info, flags)) {
712 res[num++] = generateServiceInfo(s, flags, state, userId);
715 pi.services = ArrayUtils.trimToSize(res, num);
718 if ((flags & PackageManager.GET_PROVIDERS) != 0) {
719 final int N = p.providers.size();
722 final ProviderInfo[] res = new ProviderInfo[N];
723 for (int i = 0; i < N; i++) {
724 final Provider pr = p.providers.get(i);
725 if (state.isMatch(pr.info, flags)) {
726 res[num++] = generateProviderInfo(pr, flags, state, userId);
729 pi.providers = ArrayUtils.trimToSize(res, num);
732 if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) {
733 int N = p.instrumentation.size();
735 pi.instrumentation = new InstrumentationInfo[N];
736 for (int i=0; i<N; i++) {
737 pi.instrumentation[i] = generateInstrumentationInfo(
738 p.instrumentation.get(i), flags);
742 if ((flags&PackageManager.GET_PERMISSIONS) != 0) {
743 int N = p.permissions.size();
745 pi.permissions = new PermissionInfo[N];
746 for (int i=0; i<N; i++) {
747 pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags);
750 N = p.requestedPermissions.size();
752 pi.requestedPermissions = new String[N];
753 pi.requestedPermissionsFlags = new int[N];
754 for (int i=0; i<N; i++) {
755 final String perm = p.requestedPermissions.get(i);
756 pi.requestedPermissions[i] = perm;
757 // The notion of required permissions is deprecated but for compatibility.
758 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
759 if (grantedPermissions != null && grantedPermissions.contains(perm)) {
760 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
765 if ((flags&PackageManager.GET_SIGNATURES) != 0) {
766 int N = (p.mSignatures != null) ? p.mSignatures.length : 0;
768 pi.signatures = new Signature[N];
769 System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);
775 private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry)
776 throws PackageParserException {
777 InputStream is = null;
779 // We must read the stream for the JarEntry to retrieve
781 is = jarFile.getInputStream(entry);
782 readFullyIgnoringContents(is);
783 return jarFile.getCertificateChains(entry);
784 } catch (IOException | RuntimeException e) {
785 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
786 "Failed reading " + entry.getName() + " in " + jarFile, e);
788 IoUtils.closeQuietly(is);
792 public final static int PARSE_IS_SYSTEM = 1<<0;
793 public final static int PARSE_CHATTY = 1<<1;
794 public final static int PARSE_MUST_BE_APK = 1<<2;
795 public final static int PARSE_IGNORE_PROCESSES = 1<<3;
796 public final static int PARSE_FORWARD_LOCK = 1<<4;
797 public final static int PARSE_EXTERNAL_STORAGE = 1<<5;
798 public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
799 public final static int PARSE_IS_PRIVILEGED = 1<<7;
800 public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
801 public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
802 public final static int PARSE_ENFORCE_CODE = 1<<10;
803 /** @deprecated remove when fixing b/34761192 */
805 public final static int PARSE_IS_EPHEMERAL = 1<<11;
806 public final static int PARSE_FORCE_SDK = 1<<12;
808 private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
811 * Used to sort a set of APKs based on their split names, always placing the
812 * base APK (with {@code null} split name) first.
814 private static class SplitNameComparator implements Comparator<String> {
816 public int compare(String lhs, String rhs) {
819 } else if (rhs == null) {
822 return lhs.compareTo(rhs);
828 * Parse only lightweight details about the package at the given location.
829 * Automatically detects if the package is a monolithic style (single APK
830 * file) or cluster style (directory of APKs).
832 * This performs sanity checking on cluster style packages, such as
833 * requiring identical package name and version codes, a single base APK,
834 * and unique split names.
836 * @see PackageParser#parsePackage(File, int)
838 public static PackageLite parsePackageLite(File packageFile, int flags)
839 throws PackageParserException {
840 if (packageFile.isDirectory()) {
841 return parseClusterPackageLite(packageFile, flags);
843 return parseMonolithicPackageLite(packageFile, flags);
847 private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)
848 throws PackageParserException {
849 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
850 final ApkLite baseApk = parseApkLite(packageFile, flags);
851 final String packagePath = packageFile.getAbsolutePath();
852 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
853 return new PackageLite(packagePath, baseApk, null, null, null, null, null, null);
856 static PackageLite parseClusterPackageLite(File packageDir, int flags)
857 throws PackageParserException {
858 final File[] files = packageDir.listFiles();
859 if (ArrayUtils.isEmpty(files)) {
860 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
861 "No packages found in split");
864 String packageName = null;
867 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
868 final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
869 for (File file : files) {
870 if (isApkFile(file)) {
871 final ApkLite lite = parseApkLite(file, flags);
873 // Assert that all package names and version codes are
874 // consistent with the first one we encounter.
875 if (packageName == null) {
876 packageName = lite.packageName;
877 versionCode = lite.versionCode;
879 if (!packageName.equals(lite.packageName)) {
880 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
881 "Inconsistent package " + lite.packageName + " in " + file
882 + "; expected " + packageName);
884 if (versionCode != lite.versionCode) {
885 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
886 "Inconsistent version " + lite.versionCode + " in " + file
887 + "; expected " + versionCode);
891 // Assert that each split is defined only once
892 if (apks.put(lite.splitName, lite) != null) {
893 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
894 "Split name " + lite.splitName
895 + " defined more than once; most recent was " + file);
899 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
901 final ApkLite baseApk = apks.remove(null);
902 if (baseApk == null) {
903 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
904 "Missing base APK in " + packageDir);
907 // Always apply deterministic ordering based on splitName
908 final int size = apks.size();
910 String[] splitNames = null;
911 boolean[] isFeatureSplits = null;
912 String[] usesSplitNames = null;
913 String[] configForSplits = null;
914 String[] splitCodePaths = null;
915 int[] splitRevisionCodes = null;
917 splitNames = new String[size];
918 isFeatureSplits = new boolean[size];
919 usesSplitNames = new String[size];
920 configForSplits = new String[size];
921 splitCodePaths = new String[size];
922 splitRevisionCodes = new int[size];
924 splitNames = apks.keySet().toArray(splitNames);
925 Arrays.sort(splitNames, sSplitNameComparator);
927 for (int i = 0; i < size; i++) {
928 final ApkLite apk = apks.get(splitNames[i]);
929 usesSplitNames[i] = apk.usesSplitName;
930 isFeatureSplits[i] = apk.isFeatureSplit;
931 configForSplits[i] = apk.configForSplit;
932 splitCodePaths[i] = apk.codePath;
933 splitRevisionCodes[i] = apk.revisionCode;
937 final String codePath = packageDir.getAbsolutePath();
938 return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
939 configForSplits, splitCodePaths, splitRevisionCodes);
943 * Parse the package at the given location. Automatically detects if the
944 * package is a monolithic style (single APK file) or cluster style
945 * (directory of APKs).
947 * This performs sanity checking on cluster style packages, such as
948 * requiring identical package name and version codes, a single base APK,
949 * and unique split names.
951 * Note that this <em>does not</em> perform signature verification; that
952 * must be done separately in {@link #collectCertificates(Package, int)}.
954 * If {@code useCaches} is true, the package parser might return a cached
955 * result from a previous parse of the same {@code packageFile} with the same
956 * {@code flags}. Note that this method does not check whether {@code packageFile}
957 * has changed since the last parse, it's up to callers to do so.
959 * @see #parsePackageLite(File, int)
961 public Package parsePackage(File packageFile, int flags, boolean useCaches)
962 throws PackageParserException {
963 Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
964 if (parsed != null) {
968 if (packageFile.isDirectory()) {
969 parsed = parseClusterPackage(packageFile, flags);
971 parsed = parseMonolithicPackage(packageFile, flags);
974 cacheResult(packageFile, flags, parsed);
980 * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
982 public Package parsePackage(File packageFile, int flags) throws PackageParserException {
983 return parsePackage(packageFile, flags, false /* useCaches */);
987 * Returns the cache key for a specificied {@code packageFile} and {@code flags}.
989 private String getCacheKey(File packageFile, int flags) {
990 StringBuilder sb = new StringBuilder(packageFile.getName());
994 return sb.toString();
998 protected Package fromCacheEntry(byte[] bytes) throws IOException {
999 Parcel p = Parcel.obtain();
1000 p.unmarshall(bytes, 0, bytes.length);
1001 p.setDataPosition(0);
1003 PackageParser.Package pkg = new PackageParser.Package(p);
1010 protected byte[] toCacheEntry(Package pkg) throws IOException {
1011 Parcel p = Parcel.obtain();
1012 pkg.writeToParcel(p, 0 /* flags */);
1013 byte[] serialized = p.marshall();
1020 * Given a {@code packageFile} and a {@code cacheFile} returns whether the
1021 * cache file is up to date based on the mod-time of both files.
1023 private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
1025 // NOTE: We don't use the File.lastModified API because it has the very
1026 // non-ideal failure mode of returning 0 with no excepions thrown.
1027 // The nio2 Files API is a little better but is considerably more expensive.
1028 final StructStat pkg = android.system.Os.stat(packageFile.getAbsolutePath());
1029 final StructStat cache = android.system.Os.stat(cacheFile.getAbsolutePath());
1030 return pkg.st_mtime < cache.st_mtime;
1031 } catch (ErrnoException ee) {
1032 // The most common reason why stat fails is that a given cache file doesn't
1033 // exist. We ignore that here. It's easy to reason that it's safe to say the
1034 // cache isn't up to date if we see any sort of exception here.
1036 // (1) Exception while stating the package file : This should never happen,
1037 // and if it does, we do a full package parse (which is likely to throw the
1039 // (2) Exception while stating the cache file : If the file doesn't exist, the
1040 // cache is obviously out of date. If the file *does* exist, we can't read it.
1041 // We will attempt to delete and recreate it after parsing the package.
1042 if (ee.errno != OsConstants.ENOENT) {
1043 Slog.w("Error while stating package cache : ", ee);
1051 * Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
1052 * or {@code null} if no cached result exists.
1054 private Package getCachedResult(File packageFile, int flags) {
1055 if (mCacheDir == null) {
1059 final String cacheKey = getCacheKey(packageFile, flags);
1060 final File cacheFile = new File(mCacheDir, cacheKey);
1062 // If the cache is not up to date, return null.
1063 if (!isCacheUpToDate(packageFile, cacheFile)) {
1068 final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
1069 Package p = fromCacheEntry(bytes);
1070 if (mCallback != null) {
1071 String[] overlayApks = mCallback.getOverlayApks(p.packageName);
1072 if (overlayApks != null && overlayApks.length > 0) {
1073 for (String overlayApk : overlayApks) {
1074 // If a static RRO is updated, return null.
1075 if (!isCacheUpToDate(new File(overlayApk), cacheFile)) {
1082 } catch (Exception e) {
1083 Slog.w(TAG, "Error reading package cache: ", e);
1085 // If something went wrong while reading the cache entry, delete the cache file
1086 // so that we regenerate it the next time.
1093 * Caches the parse result for {@code packageFile} with flags {@code flags}.
1095 private void cacheResult(File packageFile, int flags, Package parsed) {
1096 if (mCacheDir == null) {
1100 final String cacheKey = getCacheKey(packageFile, flags);
1101 final File cacheFile = new File(mCacheDir, cacheKey);
1103 if (cacheFile.exists()) {
1104 if (!cacheFile.delete()) {
1105 Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
1109 final byte[] cacheEntry;
1111 cacheEntry = toCacheEntry(parsed);
1112 } catch (IOException ioe) {
1113 Slog.e(TAG, "Unable to serialize parsed package for: " + packageFile);
1117 if (cacheEntry == null) {
1121 try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
1122 fos.write(cacheEntry);
1123 } catch (IOException ioe) {
1124 Slog.w(TAG, "Error writing cache entry.", ioe);
1130 * Parse all APKs contained in the given directory, treating them as a
1131 * single package. This also performs sanity checking, such as requiring
1132 * identical package name and version codes, a single base APK, and unique
1135 * Note that this <em>does not</em> perform signature verification; that
1136 * must be done separately in {@link #collectCertificates(Package, int)}.
1138 private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
1139 final PackageLite lite = parseClusterPackageLite(packageDir, 0);
1140 if (mOnlyCoreApps && !lite.coreApp) {
1141 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1142 "Not a coreApp: " + packageDir);
1145 // Build the split dependency tree.
1146 SparseArray<int[]> splitDependencies = null;
1147 final SplitAssetLoader assetLoader;
1148 if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
1150 splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
1151 assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
1152 } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
1153 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
1156 assetLoader = new DefaultSplitAssetLoader(lite, flags);
1160 final AssetManager assets = assetLoader.getBaseAssetManager();
1161 final File baseApk = new File(lite.baseCodePath);
1162 final Package pkg = parseBaseApk(baseApk, assets, flags);
1164 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
1165 "Failed to parse base APK: " + baseApk);
1168 if (!ArrayUtils.isEmpty(lite.splitNames)) {
1169 final int num = lite.splitNames.length;
1170 pkg.splitNames = lite.splitNames;
1171 pkg.splitCodePaths = lite.splitCodePaths;
1172 pkg.splitRevisionCodes = lite.splitRevisionCodes;
1173 pkg.splitFlags = new int[num];
1174 pkg.splitPrivateFlags = new int[num];
1175 pkg.applicationInfo.splitNames = pkg.splitNames;
1176 pkg.applicationInfo.splitDependencies = splitDependencies;
1178 for (int i = 0; i < num; i++) {
1179 final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
1180 parseSplitApk(pkg, i, splitAssets, flags);
1184 pkg.setCodePath(packageDir.getAbsolutePath());
1185 pkg.setUse32bitAbi(lite.use32bitAbi);
1188 IoUtils.closeQuietly(assetLoader);
1193 * Parse the given APK file, treating it as as a single monolithic package.
1195 * Note that this <em>does not</em> perform signature verification; that
1196 * must be done separately in {@link #collectCertificates(Package, int)}.
1198 * @deprecated external callers should move to
1199 * {@link #parsePackage(File, int)}. Eventually this method will
1200 * be marked private.
1203 public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
1204 final AssetManager assets = newConfiguredAssetManager();
1205 final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
1206 if (mOnlyCoreApps) {
1207 if (!lite.coreApp) {
1208 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1209 "Not a coreApp: " + apkFile);
1214 final Package pkg = parseBaseApk(apkFile, assets, flags);
1215 pkg.setCodePath(apkFile.getAbsolutePath());
1216 pkg.setUse32bitAbi(lite.use32bitAbi);
1219 IoUtils.closeQuietly(assets);
1223 private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
1224 throws PackageParserException {
1225 if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
1226 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
1227 "Invalid package file: " + apkPath);
1230 // The AssetManager guarantees uniqueness for asset paths, so if this asset path
1231 // already exists in the AssetManager, addAssetPath will only return the cookie
1233 int cookie = assets.addAssetPath(apkPath);
1235 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
1236 "Failed adding asset path: " + apkPath);
1241 private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
1242 throws PackageParserException {
1243 final String apkPath = apkFile.getAbsolutePath();
1245 String volumeUuid = null;
1246 if (apkPath.startsWith(MNT_EXPAND)) {
1247 final int end = apkPath.indexOf('/', MNT_EXPAND.length());
1248 volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
1251 mParseError = PackageManager.INSTALL_SUCCEEDED;
1252 mArchiveSourcePath = apkFile.getAbsolutePath();
1254 if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
1256 final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
1258 Resources res = null;
1259 XmlResourceParser parser = null;
1261 res = new Resources(assets, mMetrics, null);
1262 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
1264 final String[] outError = new String[1];
1265 final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
1267 throw new PackageParserException(mParseError,
1268 apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
1271 pkg.setVolumeUuid(volumeUuid);
1272 pkg.setApplicationVolumeUuid(volumeUuid);
1273 pkg.setBaseCodePath(apkPath);
1274 pkg.setSignatures(null);
1278 } catch (PackageParserException e) {
1280 } catch (Exception e) {
1281 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
1282 "Failed to read manifest from " + apkPath, e);
1284 IoUtils.closeQuietly(parser);
1288 private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags)
1289 throws PackageParserException {
1290 final String apkPath = pkg.splitCodePaths[splitIndex];
1292 mParseError = PackageManager.INSTALL_SUCCEEDED;
1293 mArchiveSourcePath = apkPath;
1295 if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
1297 final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
1299 final Resources res;
1300 XmlResourceParser parser = null;
1302 res = new Resources(assets, mMetrics, null);
1303 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1304 Build.VERSION.RESOURCES_SDK_INT);
1305 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
1307 final String[] outError = new String[1];
1308 pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
1310 throw new PackageParserException(mParseError,
1311 apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
1314 } catch (PackageParserException e) {
1316 } catch (Exception e) {
1317 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
1318 "Failed to read manifest from " + apkPath, e);
1320 IoUtils.closeQuietly(parser);
1325 * Parse the manifest of a <em>split APK</em>.
1327 * Note that split APKs have many more restrictions on what they're capable
1328 * of doing, so many valid features of a base APK have been carefully
1331 private Package parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags,
1332 int splitIndex, String[] outError) throws XmlPullParserException, IOException,
1333 PackageParserException {
1334 AttributeSet attrs = parser;
1336 // We parsed manifest tag earlier; just skip past it
1337 parsePackageSplitNames(parser, attrs);
1339 mParseInstrumentationArgs = null;
1340 mParseActivityArgs = null;
1341 mParseServiceArgs = null;
1342 mParseProviderArgs = null;
1346 boolean foundApp = false;
1348 int outerDepth = parser.getDepth();
1349 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1350 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1351 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1355 String tagName = parser.getName();
1356 if (tagName.equals(TAG_APPLICATION)) {
1359 outError[0] = "<manifest> has more than one <application>";
1360 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1363 Slog.w(TAG, "<manifest> has more than one <application>");
1364 XmlUtils.skipCurrentTag(parser);
1370 if (!parseSplitApplication(pkg, res, parser, flags, splitIndex, outError)) {
1374 } else if (RIGID_PARSER) {
1375 outError[0] = "Bad element under <manifest>: "
1377 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1381 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
1382 + " at " + mArchiveSourcePath + " "
1383 + parser.getPositionDescription());
1384 XmlUtils.skipCurrentTag(parser);
1390 outError[0] = "<manifest> does not contain an <application>";
1391 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
1397 public static int getApkSigningVersion(Package pkg) {
1399 if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) {
1400 return APK_SIGNING_V2;
1402 return APK_SIGNING_V1;
1403 } catch (IOException e) {
1405 return APK_SIGNING_UNKNOWN;
1409 * Populates the correct packages fields with the given certificates.
1411 * This is useful when we've already processed the certificates [such as during package
1412 * installation through an installer session]. We don't re-process the archive and
1413 * simply populate the correct fields.
1415 public static void populateCertificates(Package pkg, Certificate[][] certificates)
1416 throws PackageParserException {
1417 pkg.mCertificates = null;
1418 pkg.mSignatures = null;
1419 pkg.mSigningKeys = null;
1421 pkg.mCertificates = certificates;
1423 pkg.mSignatures = convertToSignatures(certificates);
1424 } catch (CertificateEncodingException e) {
1425 // certificates weren't encoded properly; something went wrong
1426 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1427 "Failed to collect certificates from " + pkg.baseCodePath, e);
1429 pkg.mSigningKeys = new ArraySet<>(certificates.length);
1430 for (int i = 0; i < certificates.length; i++) {
1431 Certificate[] signerCerts = certificates[i];
1432 Certificate signerCert = signerCerts[0];
1433 pkg.mSigningKeys.add(signerCert.getPublicKey());
1435 // add signatures to child packages
1436 final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
1437 for (int i = 0; i < childCount; i++) {
1438 Package childPkg = pkg.childPackages.get(i);
1439 childPkg.mCertificates = pkg.mCertificates;
1440 childPkg.mSignatures = pkg.mSignatures;
1441 childPkg.mSigningKeys = pkg.mSigningKeys;
1446 * Collect certificates from all the APKs described in the given package,
1447 * populating {@link Package#mSignatures}. Also asserts that all APK
1448 * contents are signed correctly and consistently.
1450 public static void collectCertificates(Package pkg, int parseFlags)
1451 throws PackageParserException {
1452 collectCertificatesInternal(pkg, parseFlags);
1453 final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
1454 for (int i = 0; i < childCount; i++) {
1455 Package childPkg = pkg.childPackages.get(i);
1456 childPkg.mCertificates = pkg.mCertificates;
1457 childPkg.mSignatures = pkg.mSignatures;
1458 childPkg.mSigningKeys = pkg.mSigningKeys;
1462 private static void collectCertificatesInternal(Package pkg, int parseFlags)
1463 throws PackageParserException {
1464 pkg.mCertificates = null;
1465 pkg.mSignatures = null;
1466 pkg.mSigningKeys = null;
1468 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
1470 collectCertificates(pkg, new File(pkg.baseCodePath), parseFlags);
1472 if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
1473 for (int i = 0; i < pkg.splitCodePaths.length; i++) {
1474 collectCertificates(pkg, new File(pkg.splitCodePaths[i]), parseFlags);
1478 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1482 private static void collectCertificates(Package pkg, File apkFile, int parseFlags)
1483 throws PackageParserException {
1484 final String apkPath = apkFile.getAbsolutePath();
1486 // Try to verify the APK using APK Signature Scheme v2.
1487 boolean verified = false;
1489 Certificate[][] allSignersCerts = null;
1490 Signature[] signatures = null;
1492 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2");
1493 allSignersCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
1494 signatures = convertToSignatures(allSignersCerts);
1495 // APK verified using APK Signature Scheme v2.
1497 } catch (ApkSignatureSchemeV2Verifier.SignatureNotFoundException e) {
1498 // No APK Signature Scheme v2 signature found
1499 if ((parseFlags & PARSE_IS_EPHEMERAL) != 0) {
1500 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1501 "No APK Signature Scheme v2 signature in ephemeral package " + apkPath,
1504 // Static shared libraries must use only the V2 signing scheme
1505 if (pkg.applicationInfo.isStaticSharedLibrary()) {
1506 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1507 "Static shared libs must use v2 signature scheme " + apkPath);
1509 } catch (Exception e) {
1510 // APK Signature Scheme v2 signature was found but did not verify
1511 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1512 "Failed to collect certificates from " + apkPath
1513 + " using APK Signature Scheme v2",
1516 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1520 if (pkg.mCertificates == null) {
1521 pkg.mCertificates = allSignersCerts;
1522 pkg.mSignatures = signatures;
1523 pkg.mSigningKeys = new ArraySet<>(allSignersCerts.length);
1524 for (int i = 0; i < allSignersCerts.length; i++) {
1525 Certificate[] signerCerts = allSignersCerts[i];
1526 Certificate signerCert = signerCerts[0];
1527 pkg.mSigningKeys.add(signerCert.getPublicKey());
1530 if (!Signature.areExactMatch(pkg.mSignatures, signatures)) {
1531 throw new PackageParserException(
1532 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
1533 apkPath + " has mismatched certificates");
1536 // Not yet done, because we need to confirm that AndroidManifest.xml exists and,
1537 // if requested, that classes.dex exists.
1541 StrictJarFile jarFile = null;
1543 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
1544 // Ignore signature stripping protections when verifying APKs from system partition.
1545 // For those APKs we only care about extracting signer certificates, and don't care
1546 // about verifying integrity.
1547 boolean signatureSchemeRollbackProtectionsEnforced =
1548 (parseFlags & PARSE_IS_SYSTEM_DIR) == 0;
1549 jarFile = new StrictJarFile(
1551 !verified, // whether to verify JAR signature
1552 signatureSchemeRollbackProtectionsEnforced);
1553 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1555 // Always verify manifest, regardless of source
1556 final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
1557 if (manifestEntry == null) {
1558 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
1559 "Package " + apkPath + " has no manifest");
1562 // Optimization: early termination when APK already verified
1567 // APK's integrity needs to be verified using JAR signature scheme.
1568 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV1");
1569 final List<ZipEntry> toVerify = new ArrayList<>();
1570 toVerify.add(manifestEntry);
1572 // If we're parsing an untrusted package, verify all contents
1573 if ((parseFlags & PARSE_IS_SYSTEM_DIR) == 0) {
1574 final Iterator<ZipEntry> i = jarFile.iterator();
1575 while (i.hasNext()) {
1576 final ZipEntry entry = i.next();
1578 if (entry.isDirectory()) continue;
1580 final String entryName = entry.getName();
1581 if (entryName.startsWith("META-INF/")) continue;
1582 if (entryName.equals(ANDROID_MANIFEST_FILENAME)) continue;
1584 toVerify.add(entry);
1588 // Verify that entries are signed consistently with the first entry
1589 // we encountered. Note that for splits, certificates may have
1590 // already been populated during an earlier parse of a base APK.
1591 for (ZipEntry entry : toVerify) {
1592 final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
1593 if (ArrayUtils.isEmpty(entryCerts)) {
1594 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1595 "Package " + apkPath + " has no certificates at entry "
1598 final Signature[] entrySignatures = convertToSignatures(entryCerts);
1600 if (pkg.mCertificates == null) {
1601 pkg.mCertificates = entryCerts;
1602 pkg.mSignatures = entrySignatures;
1603 pkg.mSigningKeys = new ArraySet<PublicKey>();
1604 for (int i=0; i < entryCerts.length; i++) {
1605 pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
1608 if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {
1609 throw new PackageParserException(
1610 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath
1611 + " has mismatched certificates at entry "
1616 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1617 } catch (GeneralSecurityException e) {
1618 throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
1619 "Failed to collect certificates from " + apkPath, e);
1620 } catch (IOException | RuntimeException e) {
1621 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1622 "Failed to collect certificates from " + apkPath, e);
1624 closeQuietly(jarFile);
1628 private static Signature[] convertToSignatures(Certificate[][] certs)
1629 throws CertificateEncodingException {
1630 final Signature[] res = new Signature[certs.length];
1631 for (int i = 0; i < certs.length; i++) {
1632 res[i] = new Signature(certs[i]);
1637 private static AssetManager newConfiguredAssetManager() {
1638 AssetManager assetManager = new AssetManager();
1639 assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1640 Build.VERSION.RESOURCES_SDK_INT);
1641 return assetManager;
1645 * Utility method that retrieves lightweight details about a single APK
1646 * file, including package name, split name, and install location.
1648 * @param apkFile path to a single APK
1649 * @param flags optional parse flags, such as
1650 * {@link #PARSE_COLLECT_CERTIFICATES}
1652 public static ApkLite parseApkLite(File apkFile, int flags)
1653 throws PackageParserException {
1654 final String apkPath = apkFile.getAbsolutePath();
1656 AssetManager assets = null;
1657 XmlResourceParser parser = null;
1659 assets = newConfiguredAssetManager();
1660 int cookie = assets.addAssetPath(apkPath);
1662 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
1663 "Failed to parse " + apkPath);
1666 final DisplayMetrics metrics = new DisplayMetrics();
1667 metrics.setToDefaults();
1669 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
1671 final Signature[] signatures;
1672 final Certificate[][] certificates;
1673 if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
1674 // TODO: factor signature related items out of Package object
1675 final Package tempPkg = new Package((String) null);
1676 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
1678 collectCertificates(tempPkg, apkFile, flags);
1680 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1682 signatures = tempPkg.mSignatures;
1683 certificates = tempPkg.mCertificates;
1686 certificates = null;
1689 final AttributeSet attrs = parser;
1690 return parseApkLite(apkPath, parser, attrs, flags, signatures, certificates);
1692 } catch (XmlPullParserException | IOException | RuntimeException e) {
1693 Slog.w(TAG, "Failed to parse " + apkPath, e);
1694 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
1695 "Failed to parse " + apkPath, e);
1697 IoUtils.closeQuietly(parser);
1698 IoUtils.closeQuietly(assets);
1702 private static String validateName(String name, boolean requireSeparator,
1703 boolean requireFilename) {
1704 final int N = name.length();
1705 boolean hasSep = false;
1706 boolean front = true;
1707 for (int i=0; i<N; i++) {
1708 final char c = name.charAt(i);
1709 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
1714 if ((c >= '0' && c <= '9') || c == '_') {
1723 return "bad character '" + c + "'";
1725 if (requireFilename && !FileUtils.isValidExtFilename(name)) {
1726 return "Invalid filename";
1728 return hasSep || !requireSeparator
1729 ? null : "must have at least one '.' separator";
1732 private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
1733 AttributeSet attrs) throws IOException, XmlPullParserException,
1734 PackageParserException {
1737 while ((type = parser.next()) != XmlPullParser.START_TAG
1738 && type != XmlPullParser.END_DOCUMENT) {
1741 if (type != XmlPullParser.START_TAG) {
1742 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1743 "No start tag found");
1745 if (!parser.getName().equals(TAG_MANIFEST)) {
1746 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1747 "No <manifest> tag");
1750 final String packageName = attrs.getAttributeValue(null, "package");
1751 if (!"android".equals(packageName)) {
1752 final String error = validateName(packageName, true, true);
1753 if (error != null) {
1754 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
1755 "Invalid manifest package: " + error);
1759 String splitName = attrs.getAttributeValue(null, "split");
1760 if (splitName != null) {
1761 if (splitName.length() == 0) {
1764 final String error = validateName(splitName, false, false);
1765 if (error != null) {
1766 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
1767 "Invalid manifest split: " + error);
1772 return Pair.create(packageName.intern(),
1773 (splitName != null) ? splitName.intern() : splitName);
1776 private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
1777 int flags, Signature[] signatures, Certificate[][] certificates)
1778 throws IOException, XmlPullParserException, PackageParserException {
1779 final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
1781 int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
1782 int versionCode = 0;
1783 int revisionCode = 0;
1784 boolean coreApp = false;
1785 boolean debuggable = false;
1786 boolean multiArch = false;
1787 boolean use32bitAbi = false;
1788 boolean extractNativeLibs = true;
1789 boolean isolatedSplits = false;
1790 boolean isFeatureSplit = false;
1791 String configForSplit = null;
1792 String usesSplitName = null;
1794 for (int i = 0; i < attrs.getAttributeCount(); i++) {
1795 final String attr = attrs.getAttributeName(i);
1796 if (attr.equals("installLocation")) {
1797 installLocation = attrs.getAttributeIntValue(i,
1798 PARSE_DEFAULT_INSTALL_LOCATION);
1799 } else if (attr.equals("versionCode")) {
1800 versionCode = attrs.getAttributeIntValue(i, 0);
1801 } else if (attr.equals("revisionCode")) {
1802 revisionCode = attrs.getAttributeIntValue(i, 0);
1803 } else if (attr.equals("coreApp")) {
1804 coreApp = attrs.getAttributeBooleanValue(i, false);
1805 } else if (attr.equals("isolatedSplits")) {
1806 isolatedSplits = attrs.getAttributeBooleanValue(i, false);
1807 } else if (attr.equals("configForSplit")) {
1808 configForSplit = attrs.getAttributeValue(i);
1809 } else if (attr.equals("isFeatureSplit")) {
1810 isFeatureSplit = attrs.getAttributeBooleanValue(i, false);
1814 // Only search the tree when the tag is directly below <manifest>
1816 final int searchDepth = parser.getDepth() + 1;
1818 final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
1819 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1820 && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {
1821 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1825 if (parser.getDepth() != searchDepth) {
1829 if (TAG_PACKAGE_VERIFIER.equals(parser.getName())) {
1830 final VerifierInfo verifier = parseVerifier(attrs);
1831 if (verifier != null) {
1832 verifiers.add(verifier);
1834 } else if (TAG_APPLICATION.equals(parser.getName())) {
1835 for (int i = 0; i < attrs.getAttributeCount(); ++i) {
1836 final String attr = attrs.getAttributeName(i);
1837 if ("debuggable".equals(attr)) {
1838 debuggable = attrs.getAttributeBooleanValue(i, false);
1840 if ("multiArch".equals(attr)) {
1841 multiArch = attrs.getAttributeBooleanValue(i, false);
1843 if ("use32bitAbi".equals(attr)) {
1844 use32bitAbi = attrs.getAttributeBooleanValue(i, false);
1846 if ("extractNativeLibs".equals(attr)) {
1847 extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
1850 } else if (TAG_USES_SPLIT.equals(parser.getName())) {
1851 if (usesSplitName != null) {
1852 Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others.");
1856 usesSplitName = attrs.getAttributeValue(ANDROID_RESOURCES, "name");
1857 if (usesSplitName == null) {
1858 throw new PackageParserException(
1859 PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1860 "<uses-split> tag requires 'android:name' attribute");
1865 return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
1866 configForSplit, usesSplitName, versionCode, revisionCode, installLocation,
1867 verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi,
1868 extractNativeLibs, isolatedSplits);
1874 static public Signature stringToSignature(String str) {
1875 final int N = str.length();
1876 byte[] sig = new byte[N];
1877 for (int i=0; i<N; i++) {
1878 sig[i] = (byte)str.charAt(i);
1880 return new Signature(sig);
1884 * Parses a child package and adds it to the parent if successful. If you add
1885 * new tags that need to be supported by child packages make sure to add them
1886 * to {@link #CHILD_PACKAGE_TAGS}.
1888 * @param parentPkg The parent that contains the child
1889 * @param res Resources against which to resolve values
1890 * @param parser Parser of the manifest
1891 * @param flags Flags about how to parse
1892 * @param outError Human readable error if parsing fails
1893 * @return True of parsing succeeded.
1895 * @throws XmlPullParserException
1896 * @throws IOException
1898 private boolean parseBaseApkChild(Package parentPkg, Resources res, XmlResourceParser parser,
1899 int flags, String[] outError) throws XmlPullParserException, IOException {
1900 // Let ppl not abuse this mechanism by limiting the packages per APK
1901 if (parentPkg.childPackages != null && parentPkg.childPackages.size() + 2
1902 > MAX_PACKAGES_PER_APK) {
1903 outError[0] = "Maximum number of packages per APK is: " + MAX_PACKAGES_PER_APK;
1904 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1908 // Make sure we have a valid child package name
1909 String childPackageName = parser.getAttributeValue(null, "package");
1910 if (validateName(childPackageName, true, false) != null) {
1911 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1915 // Child packages must be unique
1916 if (childPackageName.equals(parentPkg.packageName)) {
1917 String message = "Child package name cannot be equal to parent package name: "
1918 + parentPkg.packageName;
1919 Slog.w(TAG, message);
1920 outError[0] = message;
1921 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1925 // Child packages must be unique
1926 if (parentPkg.hasChildPackage(childPackageName)) {
1927 String message = "Duplicate child package:" + childPackageName;
1928 Slog.w(TAG, message);
1929 outError[0] = message;
1930 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1934 // Go ahead and parse the child
1935 Package childPkg = new Package(childPackageName);
1937 // Child package inherits parent version code/name/target SDK
1938 childPkg.mVersionCode = parentPkg.mVersionCode;
1939 childPkg.baseRevisionCode = parentPkg.baseRevisionCode;
1940 childPkg.mVersionName = parentPkg.mVersionName;
1941 childPkg.applicationInfo.targetSdkVersion = parentPkg.applicationInfo.targetSdkVersion;
1942 childPkg.applicationInfo.minSdkVersion = parentPkg.applicationInfo.minSdkVersion;
1944 childPkg = parseBaseApkCommon(childPkg, CHILD_PACKAGE_TAGS, res, parser, flags, outError);
1945 if (childPkg == null) {
1946 // If we got null then error was set during child parsing
1950 // Set the parent-child relation
1951 if (parentPkg.childPackages == null) {
1952 parentPkg.childPackages = new ArrayList<>();
1954 parentPkg.childPackages.add(childPkg);
1955 childPkg.parentPackage = parentPkg;
1961 * Parse the manifest of a <em>base APK</em>. When adding new features you
1962 * need to consider whether they should be supported by split APKs and child
1965 * @param apkPath The package apk file path
1966 * @param res The resources from which to resolve values
1967 * @param parser The manifest parser
1968 * @param flags Flags how to parse
1969 * @param outError Human readable error message
1970 * @return Parsed package or null on error.
1972 * @throws XmlPullParserException
1973 * @throws IOException
1975 private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
1976 String[] outError) throws XmlPullParserException, IOException {
1977 final String splitName;
1978 final String pkgName;
1981 Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser);
1982 pkgName = packageSplit.first;
1983 splitName = packageSplit.second;
1985 if (!TextUtils.isEmpty(splitName)) {
1986 outError[0] = "Expected base APK, but found split " + splitName;
1987 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1990 } catch (PackageParserException e) {
1991 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1995 if (mCallback != null) {
1996 String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath);
1997 if (overlayPaths != null && overlayPaths.length > 0) {
1998 for (String overlayPath : overlayPaths) {
1999 res.getAssets().addOverlayPath(overlayPath);
2004 final Package pkg = new Package(pkgName);
2006 TypedArray sa = res.obtainAttributes(parser,
2007 com.android.internal.R.styleable.AndroidManifest);
2009 pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
2010 com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
2011 pkg.baseRevisionCode = sa.getInteger(
2012 com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
2013 pkg.mVersionName = sa.getNonConfigurationString(
2014 com.android.internal.R.styleable.AndroidManifest_versionName, 0);
2015 if (pkg.mVersionName != null) {
2016 pkg.mVersionName = pkg.mVersionName.intern();
2019 pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
2023 return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
2027 * This is the common parsing routing for handling parent and child
2028 * packages in a base APK. The difference between parent and child
2029 * parsing is that some tags are not supported by child packages as
2030 * well as some manifest attributes are ignored. The implementation
2031 * assumes the calling code has already handled the manifest tag if needed
2032 * (this applies to the parent only).
2034 * @param pkg The package which to populate
2035 * @param acceptedTags Which tags to handle, null to handle all
2036 * @param res Resources against which to resolve values
2037 * @param parser Parser of the manifest
2038 * @param flags Flags about how to parse
2039 * @param outError Human readable error if parsing fails
2040 * @return The package if parsing succeeded or null.
2042 * @throws XmlPullParserException
2043 * @throws IOException
2045 private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
2046 XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
2048 mParseInstrumentationArgs = null;
2049 mParseActivityArgs = null;
2050 mParseServiceArgs = null;
2051 mParseProviderArgs = null;
2054 boolean foundApp = false;
2056 TypedArray sa = res.obtainAttributes(parser,
2057 com.android.internal.R.styleable.AndroidManifest);
2059 String str = sa.getNonConfigurationString(
2060 com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
2061 if (str != null && str.length() > 0) {
2062 if ((flags & PARSE_IS_EPHEMERAL) != 0) {
2063 outError[0] = "sharedUserId not allowed in ephemeral application";
2064 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
2067 String nameError = validateName(str, true, false);
2068 if (nameError != null && !"android".equals(pkg.packageName)) {
2069 outError[0] = "<manifest> specifies bad sharedUserId name \""
2070 + str + "\": " + nameError;
2071 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
2074 pkg.mSharedUserId = str.intern();
2075 pkg.mSharedUserLabel = sa.getResourceId(
2076 com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
2079 pkg.installLocation = sa.getInteger(
2080 com.android.internal.R.styleable.AndroidManifest_installLocation,
2081 PARSE_DEFAULT_INSTALL_LOCATION);
2082 pkg.applicationInfo.installLocation = pkg.installLocation;
2084 final int targetSandboxVersion = sa.getInteger(
2085 com.android.internal.R.styleable.AndroidManifest_targetSandboxVersion,
2086 PARSE_DEFAULT_TARGET_SANDBOX);
2087 pkg.applicationInfo.targetSandboxVersion = targetSandboxVersion;
2089 /* Set the global "forward lock" flag */
2090 if ((flags & PARSE_FORWARD_LOCK) != 0) {
2091 pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
2094 /* Set the global "on SD card" flag */
2095 if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
2096 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
2099 if (sa.getBoolean(com.android.internal.R.styleable.AndroidManifest_isolatedSplits, false)) {
2100 pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
2103 // Resource boolean are -1, so 1 means we don't know the value.
2104 int supportsSmallScreens = 1;
2105 int supportsNormalScreens = 1;
2106 int supportsLargeScreens = 1;
2107 int supportsXLargeScreens = 1;
2111 int outerDepth = parser.getDepth();
2112 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2113 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2114 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2118 String tagName = parser.getName();
2120 if (acceptedTags != null && !acceptedTags.contains(tagName)) {
2121 Slog.w(TAG, "Skipping unsupported element under <manifest>: "
2122 + tagName + " at " + mArchiveSourcePath + " "
2123 + parser.getPositionDescription());
2124 XmlUtils.skipCurrentTag(parser);
2128 if (tagName.equals(TAG_APPLICATION)) {
2131 outError[0] = "<manifest> has more than one <application>";
2132 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2135 Slog.w(TAG, "<manifest> has more than one <application>");
2136 XmlUtils.skipCurrentTag(parser);
2142 if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
2145 } else if (tagName.equals(TAG_OVERLAY)) {
2146 sa = res.obtainAttributes(parser,
2147 com.android.internal.R.styleable.AndroidManifestResourceOverlay);
2148 pkg.mOverlayTarget = sa.getString(
2149 com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
2150 pkg.mOverlayPriority = sa.getInt(
2151 com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
2153 pkg.mIsStaticOverlay = sa.getBoolean(
2154 com.android.internal.R.styleable.AndroidManifestResourceOverlay_isStatic,
2156 final String propName = sa.getString(
2157 com.android.internal.R.styleable
2158 .AndroidManifestResourceOverlay_requiredSystemPropertyName);
2159 final String propValue = sa.getString(
2160 com.android.internal.R.styleable
2161 .AndroidManifestResourceOverlay_requiredSystemPropertyValue);
2164 if (pkg.mOverlayTarget == null) {
2165 outError[0] = "<overlay> does not specify a target package";
2166 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2170 if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
2171 outError[0] = "<overlay> priority must be between 0 and 9999";
2173 PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2177 // check to see if overlay should be excluded based on system property condition
2178 if (!checkOverlayRequiredSystemProperty(propName, propValue)) {
2179 Slog.i(TAG, "Skipping target and overlay pair " + pkg.mOverlayTarget + " and "
2180 + pkg.baseCodePath+ ": overlay ignored due to required system property: "
2181 + propName + " with value: " + propValue);
2185 XmlUtils.skipCurrentTag(parser);
2187 } else if (tagName.equals(TAG_KEY_SETS)) {
2188 if (!parseKeySets(pkg, res, parser, outError)) {
2191 } else if (tagName.equals(TAG_PERMISSION_GROUP)) {
2192 if (!parsePermissionGroup(pkg, flags, res, parser, outError)) {
2195 } else if (tagName.equals(TAG_PERMISSION)) {
2196 if (!parsePermission(pkg, res, parser, outError)) {
2199 } else if (tagName.equals(TAG_PERMISSION_TREE)) {
2200 if (!parsePermissionTree(pkg, res, parser, outError)) {
2203 } else if (tagName.equals(TAG_USES_PERMISSION)) {
2204 if (!parseUsesPermission(pkg, res, parser)) {
2207 } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)
2208 || tagName.equals(TAG_USES_PERMISSION_SDK_23)) {
2209 if (!parseUsesPermission(pkg, res, parser)) {
2212 } else if (tagName.equals(TAG_USES_CONFIGURATION)) {
2213 ConfigurationInfo cPref = new ConfigurationInfo();
2214 sa = res.obtainAttributes(parser,
2215 com.android.internal.R.styleable.AndroidManifestUsesConfiguration);
2216 cPref.reqTouchScreen = sa.getInt(
2217 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
2218 Configuration.TOUCHSCREEN_UNDEFINED);
2219 cPref.reqKeyboardType = sa.getInt(
2220 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
2221 Configuration.KEYBOARD_UNDEFINED);
2223 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
2225 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
2227 cPref.reqNavigation = sa.getInt(
2228 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
2229 Configuration.NAVIGATION_UNDEFINED);
2231 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
2233 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
2236 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
2238 XmlUtils.skipCurrentTag(parser);
2240 } else if (tagName.equals(TAG_USES_FEATURE)) {
2241 FeatureInfo fi = parseUsesFeature(res, parser);
2242 pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi);
2244 if (fi.name == null) {
2245 ConfigurationInfo cPref = new ConfigurationInfo();
2246 cPref.reqGlEsVersion = fi.reqGlEsVersion;
2247 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
2250 XmlUtils.skipCurrentTag(parser);
2252 } else if (tagName.equals(TAG_FEATURE_GROUP)) {
2253 FeatureGroupInfo group = new FeatureGroupInfo();
2254 ArrayList<FeatureInfo> features = null;
2255 final int innerDepth = parser.getDepth();
2256 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2257 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
2258 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2262 final String innerTagName = parser.getName();
2263 if (innerTagName.equals("uses-feature")) {
2264 FeatureInfo featureInfo = parseUsesFeature(res, parser);
2265 // FeatureGroups are stricter and mandate that
2266 // any <uses-feature> declared are mandatory.
2267 featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
2268 features = ArrayUtils.add(features, featureInfo);
2270 Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName +
2271 " at " + mArchiveSourcePath + " " +
2272 parser.getPositionDescription());
2274 XmlUtils.skipCurrentTag(parser);
2277 if (features != null) {
2278 group.features = new FeatureInfo[features.size()];
2279 group.features = features.toArray(group.features);
2281 pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group);
2283 } else if (tagName.equals(TAG_USES_SDK)) {
2284 if (SDK_VERSION > 0) {
2285 sa = res.obtainAttributes(parser,
2286 com.android.internal.R.styleable.AndroidManifestUsesSdk);
2289 String minCode = null;
2291 String targetCode = null;
2293 TypedValue val = sa.peekValue(
2294 com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
2296 if (val.type == TypedValue.TYPE_STRING && val.string != null) {
2297 targetCode = minCode = val.string.toString();
2299 // If it's not a string, it's an integer.
2300 targetVers = minVers = val.data;
2305 com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
2307 if (val.type == TypedValue.TYPE_STRING && val.string != null) {
2308 targetCode = val.string.toString();
2309 if (minCode == null) {
2310 minCode = targetCode;
2313 // If it's not a string, it's an integer.
2314 targetVers = val.data;
2320 final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode,
2321 SDK_VERSION, SDK_CODENAMES, outError);
2322 if (minSdkVersion < 0) {
2323 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
2327 final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers,
2328 targetCode, SDK_VERSION, SDK_CODENAMES, outError);
2329 if (targetSdkVersion < 0) {
2330 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
2334 pkg.applicationInfo.minSdkVersion = minSdkVersion;
2335 pkg.applicationInfo.targetSdkVersion = targetSdkVersion;
2338 XmlUtils.skipCurrentTag(parser);
2340 } else if (tagName.equals(TAG_SUPPORT_SCREENS)) {
2341 sa = res.obtainAttributes(parser,
2342 com.android.internal.R.styleable.AndroidManifestSupportsScreens);
2344 pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger(
2345 com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp,
2347 pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger(
2348 com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp,
2350 pkg.applicationInfo.largestWidthLimitDp = sa.getInteger(
2351 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp,
2354 // This is a trick to get a boolean and still able to detect
2355 // if a value was actually set.
2356 supportsSmallScreens = sa.getInteger(
2357 com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens,
2358 supportsSmallScreens);
2359 supportsNormalScreens = sa.getInteger(
2360 com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens,
2361 supportsNormalScreens);
2362 supportsLargeScreens = sa.getInteger(
2363 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens,
2364 supportsLargeScreens);
2365 supportsXLargeScreens = sa.getInteger(
2366 com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens,
2367 supportsXLargeScreens);
2368 resizeable = sa.getInteger(
2369 com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable,
2371 anyDensity = sa.getInteger(
2372 com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity,
2377 XmlUtils.skipCurrentTag(parser);
2379 } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) {
2380 sa = res.obtainAttributes(parser,
2381 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
2383 // Note: don't allow this value to be a reference to a resource
2385 String name = sa.getNonResourceString(
2386 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name);
2390 if (name != null && (flags&PARSE_IS_SYSTEM) != 0) {
2391 if (pkg.protectedBroadcasts == null) {
2392 pkg.protectedBroadcasts = new ArrayList<String>();
2394 if (!pkg.protectedBroadcasts.contains(name)) {
2395 pkg.protectedBroadcasts.add(name.intern());
2399 XmlUtils.skipCurrentTag(parser);
2401 } else if (tagName.equals(TAG_INSTRUMENTATION)) {
2402 if (parseInstrumentation(pkg, res, parser, outError) == null) {
2405 } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) {
2406 sa = res.obtainAttributes(parser,
2407 com.android.internal.R.styleable.AndroidManifestOriginalPackage);
2409 String orig =sa.getNonConfigurationString(
2410 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
2411 if (!pkg.packageName.equals(orig)) {
2412 if (pkg.mOriginalPackages == null) {
2413 pkg.mOriginalPackages = new ArrayList<String>();
2414 pkg.mRealPackage = pkg.packageName;
2416 pkg.mOriginalPackages.add(orig);
2421 XmlUtils.skipCurrentTag(parser);
2423 } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) {
2424 sa = res.obtainAttributes(parser,
2425 com.android.internal.R.styleable.AndroidManifestOriginalPackage);
2427 String name = sa.getNonConfigurationString(
2428 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
2433 if (pkg.mAdoptPermissions == null) {
2434 pkg.mAdoptPermissions = new ArrayList<String>();
2436 pkg.mAdoptPermissions.add(name);
2439 XmlUtils.skipCurrentTag(parser);
2441 } else if (tagName.equals(TAG_USES_GL_TEXTURE)) {
2442 // Just skip this tag
2443 XmlUtils.skipCurrentTag(parser);
2446 } else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) {
2447 // Just skip this tag
2448 XmlUtils.skipCurrentTag(parser);
2450 } else if (tagName.equals(TAG_SUPPORTS_INPUT)) {//
2451 XmlUtils.skipCurrentTag(parser);
2454 } else if (tagName.equals(TAG_EAT_COMMENT)) {
2455 // Just skip this tag
2456 XmlUtils.skipCurrentTag(parser);
2459 } else if (tagName.equals(TAG_PACKAGE)) {
2460 if (!MULTI_PACKAGE_APK_ENABLED) {
2461 XmlUtils.skipCurrentTag(parser);
2464 if (!parseBaseApkChild(pkg, res, parser, flags, outError)) {
2465 // If parsing a child failed the error is already set
2469 } else if (tagName.equals(TAG_RESTRICT_UPDATE)) {
2470 if ((flags & PARSE_IS_SYSTEM_DIR) != 0) {
2471 sa = res.obtainAttributes(parser,
2472 com.android.internal.R.styleable.AndroidManifestRestrictUpdate);
2473 final String hash = sa.getNonConfigurationString(
2474 com.android.internal.R.styleable.AndroidManifestRestrictUpdate_hash, 0);
2477 pkg.restrictUpdateHash = null;
2479 final int hashLength = hash.length();
2480 final byte[] hashBytes = new byte[hashLength / 2];
2481 for (int i = 0; i < hashLength; i += 2){
2482 hashBytes[i/2] = (byte) ((Character.digit(hash.charAt(i), 16) << 4)
2483 + Character.digit(hash.charAt(i + 1), 16));
2485 pkg.restrictUpdateHash = hashBytes;
2489 XmlUtils.skipCurrentTag(parser);
2491 } else if (RIGID_PARSER) {
2492 outError[0] = "Bad element under <manifest>: "
2494 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2498 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
2499 + " at " + mArchiveSourcePath + " "
2500 + parser.getPositionDescription());
2501 XmlUtils.skipCurrentTag(parser);
2506 if (!foundApp && pkg.instrumentation.size() == 0) {
2507 outError[0] = "<manifest> does not contain an <application> or <instrumentation>";
2508 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
2511 final int NP = PackageParser.NEW_PERMISSIONS.length;
2512 StringBuilder implicitPerms = null;
2513 for (int ip=0; ip<NP; ip++) {
2514 final PackageParser.NewPermissionInfo npi
2515 = PackageParser.NEW_PERMISSIONS[ip];
2516 if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
2519 if (!pkg.requestedPermissions.contains(npi.name)) {
2520 if (implicitPerms == null) {
2521 implicitPerms = new StringBuilder(128);
2522 implicitPerms.append(pkg.packageName);
2523 implicitPerms.append(": compat added ");
2525 implicitPerms.append(' ');
2527 implicitPerms.append(npi.name);
2528 pkg.requestedPermissions.add(npi.name);
2531 if (implicitPerms != null) {
2532 Slog.i(TAG, implicitPerms.toString());
2535 final int NS = PackageParser.SPLIT_PERMISSIONS.length;
2536 for (int is=0; is<NS; is++) {
2537 final PackageParser.SplitPermissionInfo spi
2538 = PackageParser.SPLIT_PERMISSIONS[is];
2539 if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
2540 || !pkg.requestedPermissions.contains(spi.rootPerm)) {
2543 for (int in=0; in<spi.newPerms.length; in++) {
2544 final String perm = spi.newPerms[in];
2545 if (!pkg.requestedPermissions.contains(perm)) {
2546 pkg.requestedPermissions.add(perm);
2551 if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
2552 && pkg.applicationInfo.targetSdkVersion
2553 >= android.os.Build.VERSION_CODES.DONUT)) {
2554 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
2556 if (supportsNormalScreens != 0) {
2557 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
2559 if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
2560 && pkg.applicationInfo.targetSdkVersion
2561 >= android.os.Build.VERSION_CODES.DONUT)) {
2562 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
2564 if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
2565 && pkg.applicationInfo.targetSdkVersion
2566 >= android.os.Build.VERSION_CODES.GINGERBREAD)) {
2567 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
2569 if (resizeable < 0 || (resizeable > 0
2570 && pkg.applicationInfo.targetSdkVersion
2571 >= android.os.Build.VERSION_CODES.DONUT)) {
2572 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
2574 if (anyDensity < 0 || (anyDensity > 0
2575 && pkg.applicationInfo.targetSdkVersion
2576 >= android.os.Build.VERSION_CODES.DONUT)) {
2577 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
2580 // At this point we can check if an application is not supporting densities and hence
2581 // cannot be windowed / resized. Note that an SDK version of 0 is common for
2582 // pre-Doughnut applications.
2583 if (pkg.applicationInfo.usesCompatibilityMode()) {
2584 adjustPackageToBeUnresizeableAndUnpipable(pkg);
2589 private boolean checkOverlayRequiredSystemProperty(String propName, String propValue) {
2591 if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) {
2592 if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) {
2593 // malformed condition - incomplete
2594 Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName
2595 + "=" + propValue + "' - require both requiredSystemPropertyName"
2596 + " AND requiredSystemPropertyValue to be specified.");
2599 // no valid condition set - so no exclusion criteria, overlay will be included.
2603 // check property value - make sure it is both set and equal to expected value
2604 final String currValue = SystemProperties.get(propName);
2605 return (currValue != null && currValue.equals(propValue));
2609 * This is a pre-density application which will get scaled - instead of being pixel perfect.
2610 * This type of application is not resizable.
2612 * @param pkg The package which needs to be marked as unresizable.
2614 private void adjustPackageToBeUnresizeableAndUnpipable(Package pkg) {
2615 for (Activity a : pkg.activities) {
2616 a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
2617 a.info.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE;
2622 * Computes the targetSdkVersion to use at runtime. If the package is not
2623 * compatible with this platform, populates {@code outError[0]} with an
2626 * If {@code targetCode} is not specified, e.g. the value is {@code null},
2627 * then the {@code targetVers} will be returned unmodified.
2629 * Otherwise, the behavior varies based on whether the current platform
2630 * is a pre-release version, e.g. the {@code platformSdkCodenames} array
2633 * <li>If this is a pre-release platform and the value specified by
2634 * {@code targetCode} is contained within the array of allowed pre-release
2635 * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
2636 * <li>If this is a released platform, this method will return -1 to
2637 * indicate that the package is not compatible with this platform.
2640 * @param targetVers targetSdkVersion number, if specified in the
2641 * application manifest, or 0 otherwise
2642 * @param targetCode targetSdkVersion code, if specified in the application
2643 * manifest, or {@code null} otherwise
2644 * @param platformSdkVersion platform SDK version number, typically
2645 * Build.VERSION.SDK_INT
2646 * @param platformSdkCodenames array of allowed pre-release SDK codenames
2648 * @param outError output array to populate with error, if applicable
2649 * @return the targetSdkVersion to use at runtime, or -1 if the package is
2650 * not compatible with this platform
2651 * @hide Exposed for unit testing only.
2654 public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
2655 @Nullable String targetCode, @IntRange(from = 1) int platformSdkVersion,
2656 @NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
2657 // If it's a release SDK, return the version number unmodified.
2658 if (targetCode == null) {
2662 // If it's a pre-release SDK and the codename matches this platform, it
2663 // definitely targets this SDK.
2664 if (ArrayUtils.contains(platformSdkCodenames, targetCode)) {
2665 return Build.VERSION_CODES.CUR_DEVELOPMENT;
2668 // Otherwise, we're looking at an incompatible pre-release SDK.
2669 if (platformSdkCodenames.length > 0) {
2670 outError[0] = "Requires development platform " + targetCode
2671 + " (current platform is any of "
2672 + Arrays.toString(platformSdkCodenames) + ")";
2674 outError[0] = "Requires development platform " + targetCode
2675 + " but this is a release platform.";
2681 * Computes the minSdkVersion to use at runtime. If the package is not
2682 * compatible with this platform, populates {@code outError[0]} with an
2685 * If {@code minCode} is not specified, e.g. the value is {@code null},
2686 * then behavior varies based on the {@code platformSdkVersion}:
2688 * <li>If the platform SDK version is greater than or equal to the
2689 * {@code minVers}, returns the {@code mniVers} unmodified.
2690 * <li>Otherwise, returns -1 to indicate that the package is not
2691 * compatible with this platform.
2694 * Otherwise, the behavior varies based on whether the current platform
2695 * is a pre-release version, e.g. the {@code platformSdkCodenames} array
2698 * <li>If this is a pre-release platform and the value specified by
2699 * {@code targetCode} is contained within the array of allowed pre-release
2700 * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
2701 * <li>If this is a released platform, this method will return -1 to
2702 * indicate that the package is not compatible with this platform.
2705 * @param minVers minSdkVersion number, if specified in the application
2706 * manifest, or 1 otherwise
2707 * @param minCode minSdkVersion code, if specified in the application
2708 * manifest, or {@code null} otherwise
2709 * @param platformSdkVersion platform SDK version number, typically
2710 * Build.VERSION.SDK_INT
2711 * @param platformSdkCodenames array of allowed prerelease SDK codenames
2713 * @param outError output array to populate with error, if applicable
2714 * @return the minSdkVersion to use at runtime, or -1 if the package is not
2715 * compatible with this platform
2716 * @hide Exposed for unit testing only.
2719 public static int computeMinSdkVersion(@IntRange(from = 1) int minVers,
2720 @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
2721 @NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
2722 // If it's a release SDK, make sure we meet the minimum SDK requirement.
2723 if (minCode == null) {
2724 if (minVers <= platformSdkVersion) {
2728 // We don't meet the minimum SDK requirement.
2729 outError[0] = "Requires newer sdk version #" + minVers
2730 + " (current version is #" + platformSdkVersion + ")";
2734 // If it's a pre-release SDK and the codename matches this platform, we
2735 // definitely meet the minimum SDK requirement.
2736 if (ArrayUtils.contains(platformSdkCodenames, minCode)) {
2737 return Build.VERSION_CODES.CUR_DEVELOPMENT;
2740 // Otherwise, we're looking at an incompatible pre-release SDK.
2741 if (platformSdkCodenames.length > 0) {
2742 outError[0] = "Requires development platform " + minCode
2743 + " (current platform is any of "
2744 + Arrays.toString(platformSdkCodenames) + ")";
2746 outError[0] = "Requires development platform " + minCode
2747 + " but this is a release platform.";
2752 private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs) {
2753 FeatureInfo fi = new FeatureInfo();
2754 TypedArray sa = res.obtainAttributes(attrs,
2755 com.android.internal.R.styleable.AndroidManifestUsesFeature);
2756 // Note: don't allow this value to be a reference to a resource
2758 fi.name = sa.getNonResourceString(
2759 com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
2760 fi.version = sa.getInt(
2761 com.android.internal.R.styleable.AndroidManifestUsesFeature_version, 0);
2762 if (fi.name == null) {
2763 fi.reqGlEsVersion = sa.getInt(
2764 com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
2765 FeatureInfo.GL_ES_VERSION_UNDEFINED);
2768 com.android.internal.R.styleable.AndroidManifestUsesFeature_required, true)) {
2769 fi.flags |= FeatureInfo.FLAG_REQUIRED;
2775 private boolean parseUsesStaticLibrary(Package pkg, Resources res, XmlResourceParser parser,
2776 String[] outError) throws XmlPullParserException, IOException {
2777 TypedArray sa = res.obtainAttributes(parser,
2778 com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary);
2780 // Note: don't allow this value to be a reference to a resource that may change.
2781 String lname = sa.getNonResourceString(
2782 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
2783 final int version = sa.getInt(
2784 com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary_version, -1);
2785 String certSha256 = sa.getNonResourceString(com.android.internal.R.styleable
2786 .AndroidManifestUsesStaticLibrary_certDigest);
2789 // Since an APK providing a static shared lib can only provide the lib - fail if malformed
2790 if (lname == null || version < 0 || certSha256 == null) {
2791 outError[0] = "Bad uses-static-library declaration name: " + lname + " version: "
2792 + version + " certDigest" + certSha256;
2793 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2794 XmlUtils.skipCurrentTag(parser);
2798 // Can depend only on one version of the same library
2799 if (pkg.usesStaticLibraries != null && pkg.usesStaticLibraries.contains(lname)) {
2800 outError[0] = "Depending on multiple versions of static library " + lname;
2801 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2802 XmlUtils.skipCurrentTag(parser);
2806 lname = lname.intern();
2807 // We allow ":" delimiters in the SHA declaration as this is the format
2808 // emitted by the certtool making it easy for developers to copy/paste.
2809 certSha256 = certSha256.replace(":", "").toLowerCase();
2810 pkg.usesStaticLibraries = ArrayUtils.add(pkg.usesStaticLibraries, lname);
2811 pkg.usesStaticLibrariesVersions = ArrayUtils.appendInt(
2812 pkg.usesStaticLibrariesVersions, version, true);
2813 pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String.class,
2814 pkg.usesStaticLibrariesCertDigests, certSha256, true);
2816 XmlUtils.skipCurrentTag(parser);
2821 private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser)
2822 throws XmlPullParserException, IOException {
2823 TypedArray sa = res.obtainAttributes(parser,
2824 com.android.internal.R.styleable.AndroidManifestUsesPermission);
2826 // Note: don't allow this value to be a reference to a resource
2828 String name = sa.getNonResourceString(
2829 com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
2831 int maxSdkVersion = 0;
2832 TypedValue val = sa.peekValue(
2833 com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
2835 if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
2836 maxSdkVersion = val.data;
2840 final String requiredFeature = sa.getNonConfigurationString(
2841 com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
2843 final String requiredNotfeature = sa.getNonConfigurationString(
2844 com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredNotFeature, 0);
2848 XmlUtils.skipCurrentTag(parser);
2854 if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
2858 // Only allow requesting this permission if the platform supports the given feature.
2859 if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(requiredFeature)) {
2863 // Only allow requesting this permission if the platform doesn't support the given feature.
2864 if (requiredNotfeature != null && mCallback != null
2865 && mCallback.hasFeature(requiredNotfeature)) {
2869 int index = pkg.requestedPermissions.indexOf(name);
2871 pkg.requestedPermissions.add(name.intern());
2873 Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
2874 + name + " in package: " + pkg.packageName + " at: "
2875 + parser.getPositionDescription());
2881 private static String buildClassName(String pkg, CharSequence clsSeq,
2882 String[] outError) {
2883 if (clsSeq == null || clsSeq.length() <= 0) {
2884 outError[0] = "Empty class name in package " + pkg;
2887 String cls = clsSeq.toString();
2888 char c = cls.charAt(0);
2892 if (cls.indexOf('.') < 0) {
2893 StringBuilder b = new StringBuilder(pkg);
2896 return b.toString();
2901 private static String buildCompoundName(String pkg,
2902 CharSequence procSeq, String type, String[] outError) {
2903 String proc = procSeq.toString();
2904 char c = proc.charAt(0);
2905 if (pkg != null && c == ':') {
2906 if (proc.length() < 2) {
2907 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg
2908 + ": must be at least two characters";
2911 String subName = proc.substring(1);
2912 String nameError = validateName(subName, false, false);
2913 if (nameError != null) {
2914 outError[0] = "Invalid " + type + " name " + proc + " in package "
2915 + pkg + ": " + nameError;
2920 String nameError = validateName(proc, true, false);
2921 if (nameError != null && !"system".equals(proc)) {
2922 outError[0] = "Invalid " + type + " name " + proc + " in package "
2923 + pkg + ": " + nameError;
2929 private static String buildProcessName(String pkg, String defProc,
2930 CharSequence procSeq, int flags, String[] separateProcesses,
2931 String[] outError) {
2932 if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
2933 return defProc != null ? defProc : pkg;
2935 if (separateProcesses != null) {
2936 for (int i=separateProcesses.length-1; i>=0; i--) {
2937 String sp = separateProcesses[i];
2938 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) {
2943 if (procSeq == null || procSeq.length() <= 0) {
2946 return buildCompoundName(pkg, procSeq, "process", outError);
2949 private static String buildTaskAffinityName(String pkg, String defProc,
2950 CharSequence procSeq, String[] outError) {
2951 if (procSeq == null) {
2954 if (procSeq.length() <= 0) {
2957 return buildCompoundName(pkg, procSeq, "taskAffinity", outError);
2960 private boolean parseKeySets(Package owner, Resources res,
2961 XmlResourceParser parser, String[] outError)
2962 throws XmlPullParserException, IOException {
2963 // we've encountered the 'key-sets' tag
2964 // all the keys and keysets that we want must be defined here
2965 // so we're going to iterate over the parser and pull out the things we want
2966 int outerDepth = parser.getDepth();
2967 int currentKeySetDepth = -1;
2969 String currentKeySet = null;
2970 ArrayMap<String, PublicKey> publicKeys = new ArrayMap<String, PublicKey>();
2971 ArraySet<String> upgradeKeySets = new ArraySet<String>();
2972 ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<String, ArraySet<String>>();
2973 ArraySet<String> improperKeySets = new ArraySet<String>();
2974 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2975 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2976 if (type == XmlPullParser.END_TAG) {
2977 if (parser.getDepth() == currentKeySetDepth) {
2978 currentKeySet = null;
2979 currentKeySetDepth = -1;
2983 String tagName = parser.getName();
2984 if (tagName.equals("key-set")) {
2985 if (currentKeySet != null) {
2986 outError[0] = "Improperly nested 'key-set' tag at "
2987 + parser.getPositionDescription();
2988 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2991 final TypedArray sa = res.obtainAttributes(parser,
2992 com.android.internal.R.styleable.AndroidManifestKeySet);
2993 final String keysetName = sa.getNonResourceString(
2994 com.android.internal.R.styleable.AndroidManifestKeySet_name);
2995 definedKeySets.put(keysetName, new ArraySet<String>());
2996 currentKeySet = keysetName;
2997 currentKeySetDepth = parser.getDepth();
2999 } else if (tagName.equals("public-key")) {
3000 if (currentKeySet == null) {
3001 outError[0] = "Improperly nested 'key-set' tag at "
3002 + parser.getPositionDescription();
3003 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3006 final TypedArray sa = res.obtainAttributes(parser,
3007 com.android.internal.R.styleable.AndroidManifestPublicKey);
3008 final String publicKeyName = sa.getNonResourceString(
3009 com.android.internal.R.styleable.AndroidManifestPublicKey_name);
3010 final String encodedKey = sa.getNonResourceString(
3011 com.android.internal.R.styleable.AndroidManifestPublicKey_value);
3012 if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
3013 outError[0] = "'public-key' " + publicKeyName + " must define a public-key value"
3014 + " on first use at " + parser.getPositionDescription();
3015 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3018 } else if (encodedKey != null) {
3019 PublicKey currentKey = parsePublicKey(encodedKey);
3020 if (currentKey == null) {
3021 Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
3022 + parser.getPositionDescription() + " key-set " + currentKeySet
3023 + " will not be added to the package's defined key-sets.");
3025 improperKeySets.add(currentKeySet);
3026 XmlUtils.skipCurrentTag(parser);
3029 if (publicKeys.get(publicKeyName) == null
3030 || publicKeys.get(publicKeyName).equals(currentKey)) {
3032 /* public-key first definition, or matches old definition */
3033 publicKeys.put(publicKeyName, currentKey);
3035 outError[0] = "Value of 'public-key' " + publicKeyName
3036 + " conflicts with previously defined value at "
3037 + parser.getPositionDescription();
3038 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3043 definedKeySets.get(currentKeySet).add(publicKeyName);
3045 XmlUtils.skipCurrentTag(parser);
3046 } else if (tagName.equals("upgrade-key-set")) {
3047 final TypedArray sa = res.obtainAttributes(parser,
3048 com.android.internal.R.styleable.AndroidManifestUpgradeKeySet);
3049 String name = sa.getNonResourceString(
3050 com.android.internal.R.styleable.AndroidManifestUpgradeKeySet_name);
3051 upgradeKeySets.add(name);
3053 XmlUtils.skipCurrentTag(parser);
3054 } else if (RIGID_PARSER) {
3055 outError[0] = "Bad element under <key-sets>: " + parser.getName()
3056 + " at " + mArchiveSourcePath + " "
3057 + parser.getPositionDescription();
3058 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3061 Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName()
3062 + " at " + mArchiveSourcePath + " "
3063 + parser.getPositionDescription());
3064 XmlUtils.skipCurrentTag(parser);
3068 Set<String> publicKeyNames = publicKeys.keySet();
3069 if (publicKeyNames.removeAll(definedKeySets.keySet())) {
3070 outError[0] = "Package" + owner.packageName + " AndroidManifext.xml "
3071 + "'key-set' and 'public-key' names must be distinct.";
3072 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3075 owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>();
3076 for (ArrayMap.Entry<String, ArraySet<String>> e: definedKeySets.entrySet()) {
3077 final String keySetName = e.getKey();
3078 if (e.getValue().size() == 0) {
3079 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
3080 + "'key-set' " + keySetName + " has no valid associated 'public-key'."
3081 + " Not including in package's defined key-sets.");
3083 } else if (improperKeySets.contains(keySetName)) {
3084 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
3085 + "'key-set' " + keySetName + " contained improper 'public-key'"
3086 + " tags. Not including in package's defined key-sets.");
3089 owner.mKeySetMapping.put(keySetName, new ArraySet<PublicKey>());
3090 for (String s : e.getValue()) {
3091 owner.mKeySetMapping.get(keySetName).add(publicKeys.get(s));
3094 if (owner.mKeySetMapping.keySet().containsAll(upgradeKeySets)) {
3095 owner.mUpgradeKeySets = upgradeKeySets;
3097 outError[0] ="Package" + owner.packageName + " AndroidManifext.xml "
3098 + "does not define all 'upgrade-key-set's .";
3099 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3105 private boolean parsePermissionGroup(Package owner, int flags, Resources res,
3106 XmlResourceParser parser, String[] outError)
3107 throws XmlPullParserException, IOException {
3108 PermissionGroup perm = new PermissionGroup(owner);
3110 TypedArray sa = res.obtainAttributes(parser,
3111 com.android.internal.R.styleable.AndroidManifestPermissionGroup);
3112 if (!parsePackageItemInfo(owner, perm.info, outError,
3113 "<permission-group>", sa, true /*nameRequired*/,
3114 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
3115 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
3116 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
3117 com.android.internal.R.styleable.AndroidManifestPermissionGroup_roundIcon,
3118 com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
3119 com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
3121 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3125 perm.info.descriptionRes = sa.getResourceId(
3126 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description,
3128 perm.info.flags = sa.getInt(
3129 com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0);
3130 perm.info.priority = sa.getInt(
3131 com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0);
3132 if (perm.info.priority > 0 && (flags&PARSE_IS_SYSTEM) == 0) {
3133 perm.info.priority = 0;
3138 if (!parseAllMetaData(res, parser, "<permission-group>", perm,
3140 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3144 owner.permissionGroups.add(perm);
3149 private boolean parsePermission(Package owner, Resources res,
3150 XmlResourceParser parser, String[] outError)
3151 throws XmlPullParserException, IOException {
3153 TypedArray sa = res.obtainAttributes(parser,
3154 com.android.internal.R.styleable.AndroidManifestPermission);
3156 Permission perm = new Permission(owner);
3157 if (!parsePackageItemInfo(owner, perm.info, outError,
3158 "<permission>", sa, true /*nameRequired*/,
3159 com.android.internal.R.styleable.AndroidManifestPermission_name,
3160 com.android.internal.R.styleable.AndroidManifestPermission_label,
3161 com.android.internal.R.styleable.AndroidManifestPermission_icon,
3162 com.android.internal.R.styleable.AndroidManifestPermission_roundIcon,
3163 com.android.internal.R.styleable.AndroidManifestPermission_logo,
3164 com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
3166 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3170 // Note: don't allow this value to be a reference to a resource
3172 perm.info.group = sa.getNonResourceString(
3173 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup);
3174 if (perm.info.group != null) {
3175 perm.info.group = perm.info.group.intern();
3178 perm.info.descriptionRes = sa.getResourceId(
3179 com.android.internal.R.styleable.AndroidManifestPermission_description,
3182 perm.info.protectionLevel = sa.getInt(
3183 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel,
3184 PermissionInfo.PROTECTION_NORMAL);
3186 perm.info.flags = sa.getInt(
3187 com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0);
3191 if (perm.info.protectionLevel == -1) {
3192 outError[0] = "<permission> does not specify protectionLevel";
3193 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3197 perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
3199 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) {
3200 if ( (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_EPHEMERAL) == 0
3201 && (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) == 0
3202 && (perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=
3203 PermissionInfo.PROTECTION_SIGNATURE) {
3204 outError[0] = "<permission> protectionLevel specifies a non-ephemeral flag but is "
3205 + "not based on signature type";
3206 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3211 if (!parseAllMetaData(res, parser, "<permission>", perm, outError)) {
3212 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3216 owner.permissions.add(perm);
3221 private boolean parsePermissionTree(Package owner, Resources res,
3222 XmlResourceParser parser, String[] outError)
3223 throws XmlPullParserException, IOException {
3224 Permission perm = new Permission(owner);
3226 TypedArray sa = res.obtainAttributes(parser,
3227 com.android.internal.R.styleable.AndroidManifestPermissionTree);
3229 if (!parsePackageItemInfo(owner, perm.info, outError,
3230 "<permission-tree>", sa, true /*nameRequired*/,
3231 com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
3232 com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
3233 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
3234 com.android.internal.R.styleable.AndroidManifestPermissionTree_roundIcon,
3235 com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,
3236 com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
3238 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3244 int index = perm.info.name.indexOf('.');
3246 index = perm.info.name.indexOf('.', index+1);
3249 outError[0] = "<permission-tree> name has less than three segments: "
3251 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3255 perm.info.descriptionRes = 0;
3256 perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
3259 if (!parseAllMetaData(res, parser, "<permission-tree>", perm,
3261 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3265 owner.permissions.add(perm);
3270 private Instrumentation parseInstrumentation(Package owner, Resources res,
3271 XmlResourceParser parser, String[] outError)
3272 throws XmlPullParserException, IOException {
3273 TypedArray sa = res.obtainAttributes(parser,
3274 com.android.internal.R.styleable.AndroidManifestInstrumentation);
3276 if (mParseInstrumentationArgs == null) {
3277 mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError,
3278 com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
3279 com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
3280 com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
3281 com.android.internal.R.styleable.AndroidManifestInstrumentation_roundIcon,
3282 com.android.internal.R.styleable.AndroidManifestInstrumentation_logo,
3283 com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
3284 mParseInstrumentationArgs.tag = "<instrumentation>";
3287 mParseInstrumentationArgs.sa = sa;
3289 Instrumentation a = new Instrumentation(mParseInstrumentationArgs,
3290 new InstrumentationInfo());
3291 if (outError[0] != null) {
3293 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3298 // Note: don't allow this value to be a reference to a resource
3300 str = sa.getNonResourceString(
3301 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage);
3302 a.info.targetPackage = str != null ? str.intern() : null;
3304 str = sa.getNonResourceString(
3305 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetProcesses);
3306 a.info.targetProcesses = str != null ? str.intern() : null;
3308 a.info.handleProfiling = sa.getBoolean(
3309 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling,
3312 a.info.functionalTest = sa.getBoolean(
3313 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest,
3318 if (a.info.targetPackage == null) {
3319 outError[0] = "<instrumentation> does not specify targetPackage";
3320 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3324 if (!parseAllMetaData(res, parser, "<instrumentation>", a,
3326 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3330 owner.instrumentation.add(a);
3336 * Parse the {@code application} XML tree at the current parse location in a
3337 * <em>base APK</em> manifest.
3339 * When adding new features, carefully consider if they should also be
3340 * supported by split APKs.
3342 private boolean parseBaseApplication(Package owner, Resources res,
3343 XmlResourceParser parser, int flags, String[] outError)
3344 throws XmlPullParserException, IOException {
3345 final ApplicationInfo ai = owner.applicationInfo;
3346 final String pkgName = owner.applicationInfo.packageName;
3348 TypedArray sa = res.obtainAttributes(parser,
3349 com.android.internal.R.styleable.AndroidManifestApplication);
3351 if (!parsePackageItemInfo(owner, ai, outError,
3352 "<application>", sa, false /*nameRequired*/,
3353 com.android.internal.R.styleable.AndroidManifestApplication_name,
3354 com.android.internal.R.styleable.AndroidManifestApplication_label,
3355 com.android.internal.R.styleable.AndroidManifestApplication_icon,
3356 com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,
3357 com.android.internal.R.styleable.AndroidManifestApplication_logo,
3358 com.android.internal.R.styleable.AndroidManifestApplication_banner)) {
3360 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3364 if (ai.name != null) {
3365 ai.className = ai.name;
3368 String manageSpaceActivity = sa.getNonConfigurationString(
3369 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
3370 Configuration.NATIVE_CONFIG_VERSION);
3371 if (manageSpaceActivity != null) {
3372 ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
3376 boolean allowBackup = sa.getBoolean(
3377 com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
3379 ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
3381 // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
3382 // and restoreAnyVersion are only relevant if backup is possible for the
3383 // given application.
3384 String backupAgent = sa.getNonConfigurationString(
3385 com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
3386 Configuration.NATIVE_CONFIG_VERSION);
3387 if (backupAgent != null) {
3388 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
3390 Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName
3391 + " from " + pkgName + "+" + backupAgent);
3395 com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore,
3397 ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
3400 com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion,
3402 ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
3405 com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly,
3407 ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
3410 com.android.internal.R.styleable.AndroidManifestApplication_backupInForeground,
3412 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
3416 TypedValue v = sa.peekValue(
3417 com.android.internal.R.styleable.AndroidManifestApplication_fullBackupContent);
3418 if (v != null && (ai.fullBackupContent = v.resourceId) == 0) {
3420 Slog.v(TAG, "fullBackupContent specified as boolean=" +
3421 (v.data == 0 ? "false" : "true"));
3423 // "false" => -1, "true" => 0
3424 ai.fullBackupContent = (v.data == 0 ? -1 : 0);
3427 Slog.v(TAG, "fullBackupContent=" + ai.fullBackupContent + " for " + pkgName);
3431 ai.theme = sa.getResourceId(
3432 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
3433 ai.descriptionRes = sa.getResourceId(
3434 com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
3436 if ((flags&PARSE_IS_SYSTEM) != 0) {
3438 com.android.internal.R.styleable.AndroidManifestApplication_persistent,
3440 // Check if persistence is based on a feature being present
3441 final String requiredFeature = sa.getNonResourceString(
3442 com.android.internal.R.styleable.
3443 AndroidManifestApplication_persistentWhenFeatureAvailable);
3444 if (requiredFeature == null || mCallback.hasFeature(requiredFeature)) {
3445 ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
3451 com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers,
3453 owner.mRequiredForAllUsers = true;
3456 String restrictedAccountType = sa.getString(com.android.internal.R.styleable
3457 .AndroidManifestApplication_restrictedAccountType);
3458 if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
3459 owner.mRestrictedAccountType = restrictedAccountType;
3462 String requiredAccountType = sa.getString(com.android.internal.R.styleable
3463 .AndroidManifestApplication_requiredAccountType);
3464 if (requiredAccountType != null && requiredAccountType.length() > 0) {
3465 owner.mRequiredAccountType = requiredAccountType;
3469 com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
3471 ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
3475 com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode,
3477 ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE;
3480 owner.baseHardwareAccelerated = sa.getBoolean(
3481 com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
3482 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
3483 if (owner.baseHardwareAccelerated) {
3484 ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
3488 com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
3490 ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
3494 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
3496 ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
3500 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
3502 ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
3505 // The parent package controls installation, hence specify test only installs.
3506 if (owner.parentPackage == null) {
3508 com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
3510 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
3515 com.android.internal.R.styleable.AndroidManifestApplication_largeHeap,
3517 ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP;
3521 com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic,
3523 ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
3527 com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl,
3528 false /* default is no RTL support*/)) {
3529 ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
3533 com.android.internal.R.styleable.AndroidManifestApplication_multiArch,
3535 ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
3539 com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
3541 ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
3545 R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
3547 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
3550 R.styleable.AndroidManifestApplication_directBootAware,
3552 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
3555 if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
3556 if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity, true)) {
3557 ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
3559 ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
3561 } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
3562 ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
3565 ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0);
3567 ai.networkSecurityConfigRes = sa.getResourceId(
3568 com.android.internal.R.styleable.AndroidManifestApplication_networkSecurityConfig,
3570 ai.category = sa.getInt(
3571 com.android.internal.R.styleable.AndroidManifestApplication_appCategory,
3572 ApplicationInfo.CATEGORY_UNDEFINED);
3575 str = sa.getNonConfigurationString(
3576 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
3577 ai.permission = (str != null && str.length() > 0) ? str.intern() : null;
3579 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
3580 str = sa.getNonConfigurationString(
3581 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity,
3582 Configuration.NATIVE_CONFIG_VERSION);
3584 // Some older apps have been seen to use a resource reference
3585 // here that on older builds was ignored (with a warning). We
3586 // need to continue to do this for them so they don't break.
3587 str = sa.getNonResourceString(
3588 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
3590 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
3593 if (outError[0] == null) {
3595 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
3596 pname = sa.getNonConfigurationString(
3597 com.android.internal.R.styleable.AndroidManifestApplication_process,
3598 Configuration.NATIVE_CONFIG_VERSION);
3600 // Some older apps have been seen to use a resource reference
3601 // here that on older builds was ignored (with a warning). We
3602 // need to continue to do this for them so they don't break.
3603 pname = sa.getNonResourceString(
3604 com.android.internal.R.styleable.AndroidManifestApplication_process);
3606 ai.processName = buildProcessName(ai.packageName, null, pname,
3607 flags, mSeparateProcesses, outError);
3609 ai.enabled = sa.getBoolean(
3610 com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
3613 com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) {
3614 ai.flags |= ApplicationInfo.FLAG_IS_GAME;
3619 com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
3621 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
3623 // A heavy-weight application can not be in a custom process.
3624 // We can do direct compare because we intern all strings.
3625 if (ai.processName != null && ai.processName != ai.packageName) {
3626 outError[0] = "cantSaveState applications can not use custom processes";
3632 ai.uiOptions = sa.getInt(
3633 com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);
3637 if (outError[0] != null) {
3638 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3642 final int innerDepth = parser.getDepth();
3645 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3646 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
3647 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3651 String tagName = parser.getName();
3652 if (tagName.equals("activity")) {
3653 Activity a = parseActivity(owner, res, parser, flags, outError, false,
3654 owner.baseHardwareAccelerated);
3656 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3660 owner.activities.add(a);
3662 } else if (tagName.equals("receiver")) {
3663 Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
3665 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3669 owner.receivers.add(a);
3671 } else if (tagName.equals("service")) {
3672 Service s = parseService(owner, res, parser, flags, outError);
3674 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3678 owner.services.add(s);
3680 } else if (tagName.equals("provider")) {
3681 Provider p = parseProvider(owner, res, parser, flags, outError);
3683 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3687 owner.providers.add(p);
3689 } else if (tagName.equals("activity-alias")) {
3690 Activity a = parseActivityAlias(owner, res, parser, flags, outError);
3692 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3696 owner.activities.add(a);
3698 } else if (parser.getName().equals("meta-data")) {
3699 // note: application meta-data is stored off to the side, so it can
3700 // remain null in the primary copy (we like to avoid extra copies because
3702 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
3703 outError)) == null) {
3704 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3707 } else if (tagName.equals("static-library")) {
3708 sa = res.obtainAttributes(parser,
3709 com.android.internal.R.styleable.AndroidManifestStaticLibrary);
3711 // Note: don't allow this value to be a reference to a resource
3713 final String lname = sa.getNonResourceString(
3714 com.android.internal.R.styleable.AndroidManifestStaticLibrary_name);
3715 final int version = sa.getInt(
3716 com.android.internal.R.styleable.AndroidManifestStaticLibrary_version, -1);
3720 // Since the app canot run without a static lib - fail if malformed
3721 if (lname == null || version < 0) {
3722 outError[0] = "Bad static-library declaration name: " + lname
3723 + " version: " + version;
3724 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3725 XmlUtils.skipCurrentTag(parser);
3729 if (owner.mSharedUserId != null) {
3730 outError[0] = "sharedUserId not allowed in static shared library";
3731 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
3732 XmlUtils.skipCurrentTag(parser);
3736 if (owner.staticSharedLibName != null) {
3737 outError[0] = "Multiple static-shared libs for package " + pkgName;
3738 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3739 XmlUtils.skipCurrentTag(parser);
3743 owner.staticSharedLibName = lname.intern();
3744 owner.staticSharedLibVersion = version;
3745 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY;
3747 XmlUtils.skipCurrentTag(parser);
3749 } else if (tagName.equals("library")) {
3750 sa = res.obtainAttributes(parser,
3751 com.android.internal.R.styleable.AndroidManifestLibrary);
3753 // Note: don't allow this value to be a reference to a resource
3755 String lname = sa.getNonResourceString(
3756 com.android.internal.R.styleable.AndroidManifestLibrary_name);
3760 if (lname != null) {
3761 lname = lname.intern();
3762 if (!ArrayUtils.contains(owner.libraryNames, lname)) {
3763 owner.libraryNames = ArrayUtils.add(
3764 owner.libraryNames, lname);
3768 XmlUtils.skipCurrentTag(parser);
3770 } else if (tagName.equals("uses-static-library")) {
3771 if (!parseUsesStaticLibrary(owner, res, parser, outError)) {
3775 } else if (tagName.equals("uses-library")) {
3776 sa = res.obtainAttributes(parser,
3777 com.android.internal.R.styleable.AndroidManifestUsesLibrary);
3779 // Note: don't allow this value to be a reference to a resource
3781 String lname = sa.getNonResourceString(
3782 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
3783 boolean req = sa.getBoolean(
3784 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
3789 if (lname != null) {
3790 lname = lname.intern();
3792 owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
3794 owner.usesOptionalLibraries = ArrayUtils.add(
3795 owner.usesOptionalLibraries, lname);
3799 XmlUtils.skipCurrentTag(parser);
3801 } else if (tagName.equals("uses-package")) {
3802 // Dependencies for app installers; we don't currently try to
3804 XmlUtils.skipCurrentTag(parser);
3807 if (!RIGID_PARSER) {
3808 Slog.w(TAG, "Unknown element under <application>: " + tagName
3809 + " at " + mArchiveSourcePath + " "
3810 + parser.getPositionDescription());
3811 XmlUtils.skipCurrentTag(parser);
3814 outError[0] = "Bad element under <application>: " + tagName;
3815 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3821 // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after
3822 // every activity info has had a chance to set it from its attributes.
3823 setMaxAspectRatio(owner);
3825 modifySharedLibrariesForBackwardCompatibility(owner);
3827 if (hasDomainURLs(owner)) {
3828 owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
3830 owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
3836 private static void modifySharedLibrariesForBackwardCompatibility(Package owner) {
3837 // "org.apache.http.legacy" is now a part of the boot classpath so it doesn't need
3838 // to be an explicit dependency.
3840 // A future change will remove this library from the boot classpath, at which point
3841 // all apps that target SDK 21 and earlier will have it automatically added to their
3842 // dependency lists.
3843 owner.usesLibraries = ArrayUtils.remove(owner.usesLibraries, "org.apache.http.legacy");
3844 owner.usesOptionalLibraries = ArrayUtils.remove(owner.usesOptionalLibraries,
3845 "org.apache.http.legacy");
3849 * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
3851 private static boolean hasDomainURLs(Package pkg) {
3852 if (pkg == null || pkg.activities == null) return false;
3853 final ArrayList<Activity> activities = pkg.activities;
3854 final int countActivities = activities.size();
3855 for (int n=0; n<countActivities; n++) {
3856 Activity activity = activities.get(n);
3857 ArrayList<ActivityIntentInfo> filters = activity.intents;
3858 if (filters == null) continue;
3859 final int countFilters = filters.size();
3860 for (int m=0; m<countFilters; m++) {
3861 ActivityIntentInfo aii = filters.get(m);
3862 if (!aii.hasAction(Intent.ACTION_VIEW)) continue;
3863 if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue;
3864 if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
3865 aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
3874 * Parse the {@code application} XML tree at the current parse location in a
3875 * <em>split APK</em> manifest.
3877 * Note that split APKs have many more restrictions on what they're capable
3878 * of doing, so many valid features of a base APK have been carefully
3881 private boolean parseSplitApplication(Package owner, Resources res, XmlResourceParser parser,
3882 int flags, int splitIndex, String[] outError)
3883 throws XmlPullParserException, IOException {
3884 TypedArray sa = res.obtainAttributes(parser,
3885 com.android.internal.R.styleable.AndroidManifestApplication);
3888 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, true)) {
3889 owner.splitFlags[splitIndex] |= ApplicationInfo.FLAG_HAS_CODE;
3892 final int innerDepth = parser.getDepth();
3894 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3895 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
3896 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3900 ComponentInfo parsedComponent = null;
3902 String tagName = parser.getName();
3903 if (tagName.equals("activity")) {
3904 Activity a = parseActivity(owner, res, parser, flags, outError, false,
3905 owner.baseHardwareAccelerated);
3907 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3911 owner.activities.add(a);
3912 parsedComponent = a.info;
3914 } else if (tagName.equals("receiver")) {
3915 Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
3917 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3921 owner.receivers.add(a);
3922 parsedComponent = a.info;
3924 } else if (tagName.equals("service")) {
3925 Service s = parseService(owner, res, parser, flags, outError);
3927 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3931 owner.services.add(s);
3932 parsedComponent = s.info;
3934 } else if (tagName.equals("provider")) {
3935 Provider p = parseProvider(owner, res, parser, flags, outError);
3937 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3941 owner.providers.add(p);
3942 parsedComponent = p.info;
3944 } else if (tagName.equals("activity-alias")) {
3945 Activity a = parseActivityAlias(owner, res, parser, flags, outError);
3947 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3951 owner.activities.add(a);
3952 parsedComponent = a.info;
3954 } else if (parser.getName().equals("meta-data")) {
3955 // note: application meta-data is stored off to the side, so it can
3956 // remain null in the primary copy (we like to avoid extra copies because
3958 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
3959 outError)) == null) {
3960 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3964 } else if (tagName.equals("uses-static-library")) {
3965 if (!parseUsesStaticLibrary(owner, res, parser, outError)) {
3969 } else if (tagName.equals("uses-library")) {
3970 sa = res.obtainAttributes(parser,
3971 com.android.internal.R.styleable.AndroidManifestUsesLibrary);
3973 // Note: don't allow this value to be a reference to a resource
3975 String lname = sa.getNonResourceString(
3976 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
3977 boolean req = sa.getBoolean(
3978 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
3983 if (lname != null) {
3984 lname = lname.intern();
3986 // Upgrade to treat as stronger constraint
3987 owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
3988 owner.usesOptionalLibraries = ArrayUtils.remove(
3989 owner.usesOptionalLibraries, lname);
3991 // Ignore if someone already defined as required
3992 if (!ArrayUtils.contains(owner.usesLibraries, lname)) {
3993 owner.usesOptionalLibraries = ArrayUtils.add(
3994 owner.usesOptionalLibraries, lname);
3999 XmlUtils.skipCurrentTag(parser);
4001 } else if (tagName.equals("uses-package")) {
4002 // Dependencies for app installers; we don't currently try to
4004 XmlUtils.skipCurrentTag(parser);
4007 if (!RIGID_PARSER) {
4008 Slog.w(TAG, "Unknown element under <application>: " + tagName
4009 + " at " + mArchiveSourcePath + " "
4010 + parser.getPositionDescription());
4011 XmlUtils.skipCurrentTag(parser);
4014 outError[0] = "Bad element under <application>: " + tagName;
4015 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
4020 if (parsedComponent != null && parsedComponent.splitName == null) {
4021 // If the loaded component did not specify a split, inherit the split name
4022 // based on the split it is defined in.
4023 // This is used to later load the correct split when starting this
4025 parsedComponent.splitName = owner.splitNames[splitIndex];
4032 private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
4033 String[] outError, String tag, TypedArray sa, boolean nameRequired,
4034 int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
4035 // This case can only happen in unit tests where we sometimes need to create fakes
4036 // of various package parser data structures.
4038 outError[0] = tag + " does not contain any attributes";
4042 String name = sa.getNonConfigurationString(nameRes, 0);
4045 outError[0] = tag + " does not specify android:name";
4050 = buildClassName(owner.applicationInfo.packageName, name, outError);
4051 if (outInfo.name == null) {
4056 final boolean useRoundIcon =
4057 Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
4058 int roundIconVal = useRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
4059 if (roundIconVal != 0) {
4060 outInfo.icon = roundIconVal;
4061 outInfo.nonLocalizedLabel = null;
4063 int iconVal = sa.getResourceId(iconRes, 0);
4065 outInfo.icon = iconVal;
4066 outInfo.nonLocalizedLabel = null;
4070 int logoVal = sa.getResourceId(logoRes, 0);
4072 outInfo.logo = logoVal;
4075 int bannerVal = sa.getResourceId(bannerRes, 0);
4076 if (bannerVal != 0) {
4077 outInfo.banner = bannerVal;
4080 TypedValue v = sa.peekValue(labelRes);
4081 if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
4082 outInfo.nonLocalizedLabel = v.coerceToString();
4085 outInfo.packageName = owner.packageName;
4090 private Activity parseActivity(Package owner, Resources res,
4091 XmlResourceParser parser, int flags, String[] outError,
4092 boolean receiver, boolean hardwareAccelerated)
4093 throws XmlPullParserException, IOException {
4094 TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
4096 if (mParseActivityArgs == null) {
4097 mParseActivityArgs = new ParseComponentArgs(owner, outError,
4098 R.styleable.AndroidManifestActivity_name,
4099 R.styleable.AndroidManifestActivity_label,
4100 R.styleable.AndroidManifestActivity_icon,
4101 R.styleable.AndroidManifestActivity_roundIcon,
4102 R.styleable.AndroidManifestActivity_logo,
4103 R.styleable.AndroidManifestActivity_banner,
4105 R.styleable.AndroidManifestActivity_process,
4106 R.styleable.AndroidManifestActivity_description,
4107 R.styleable.AndroidManifestActivity_enabled);
4110 mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
4111 mParseActivityArgs.sa = sa;
4112 mParseActivityArgs.flags = flags;
4114 Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
4115 if (outError[0] != null) {
4120 boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
4122 a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false);
4125 a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
4127 a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
4128 a.info.applicationInfo.uiOptions);
4130 String parentName = sa.getNonConfigurationString(
4131 R.styleable.AndroidManifestActivity_parentActivityName,
4132 Configuration.NATIVE_CONFIG_VERSION);
4133 if (parentName != null) {
4134 String parentClassName = buildClassName(a.info.packageName, parentName, outError);
4135 if (outError[0] == null) {
4136 a.info.parentActivityName = parentClassName;
4138 Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " +
4145 str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
4147 a.info.permission = owner.applicationInfo.permission;
4149 a.info.permission = str.length() > 0 ? str.toString().intern() : null;
4152 str = sa.getNonConfigurationString(
4153 R.styleable.AndroidManifestActivity_taskAffinity,
4154 Configuration.NATIVE_CONFIG_VERSION);
4155 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
4156 owner.applicationInfo.taskAffinity, str, outError);
4159 sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0);
4163 R.styleable.AndroidManifestActivity_multiprocess, false)) {
4164 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
4167 if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
4168 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
4171 if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
4172 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
4175 if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
4176 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
4179 if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
4180 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
4183 if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
4184 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
4187 if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
4188 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
4191 if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
4192 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
4193 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
4196 if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) {
4197 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
4200 if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
4201 || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
4202 a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
4205 if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
4206 a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
4209 if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
4210 a.info.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
4214 if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
4215 hardwareAccelerated)) {
4216 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
4219 a.info.launchMode = sa.getInt(
4220 R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
4221 a.info.documentLaunchMode = sa.getInt(
4222 R.styleable.AndroidManifestActivity_documentLaunchMode,
4223 ActivityInfo.DOCUMENT_LAUNCH_NONE);
4224 a.info.maxRecents = sa.getInt(
4225 R.styleable.AndroidManifestActivity_maxRecents,
4226 ActivityManager.getDefaultAppRecentsLimitStatic());
4227 a.info.configChanges = getActivityConfigChanges(
4228 sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
4229 sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
4230 a.info.softInputMode = sa.getInt(
4231 R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
4233 a.info.persistableMode = sa.getInteger(
4234 R.styleable.AndroidManifestActivity_persistableMode,
4235 ActivityInfo.PERSIST_ROOT_ONLY);
4237 if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
4238 a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
4241 if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) {
4242 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
4245 if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) {
4246 a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
4249 if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
4250 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
4253 a.info.screenOrientation = sa.getInt(
4254 R.styleable.AndroidManifestActivity_screenOrientation,
4255 SCREEN_ORIENTATION_UNSPECIFIED);
4257 setActivityResizeMode(a.info, sa, owner);
4259 if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
4261 a.info.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE;
4264 if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
4265 a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
4268 if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
4269 && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
4270 == TypedValue.TYPE_FLOAT) {
4271 a.setMaxAspectRatio(sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
4275 a.info.lockTaskLaunchMode =
4276 sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
4278 a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
4279 R.styleable.AndroidManifestActivity_directBootAware,
4282 a.info.requestedVrComponent =
4283 sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
4285 a.info.rotationAnimation =
4286 sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, ROTATION_ANIMATION_ROTATE);
4288 a.info.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
4289 ActivityInfo.COLOR_MODE_DEFAULT);
4291 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
4292 a.info.configChanges = 0;
4294 if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
4295 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
4296 if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
4297 Slog.w(TAG, "Activity exported request ignored due to singleUser: "
4298 + a.className + " at " + mArchiveSourcePath + " "
4299 + parser.getPositionDescription());
4300 a.info.exported = false;
4305 a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
4306 R.styleable.AndroidManifestActivity_directBootAware,
4310 if (a.info.directBootAware) {
4311 owner.applicationInfo.privateFlags |=
4312 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
4315 // can't make this final; we may set it later via meta-data
4316 boolean visibleToEphemeral =
4317 sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
4318 if (visibleToEphemeral) {
4319 a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4320 owner.visibleToInstantApps = true;
4325 if (receiver && (owner.applicationInfo.privateFlags
4326 &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
4327 // A heavy-weight application can not have receives in its main process
4328 // We can do direct compare because we intern all strings.
4329 if (a.info.processName == owner.packageName) {
4330 outError[0] = "Heavy-weight applications can not have receivers in main process";
4334 if (outError[0] != null) {
4338 int outerDepth = parser.getDepth();
4340 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4341 && (type != XmlPullParser.END_TAG
4342 || parser.getDepth() > outerDepth)) {
4343 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4347 if (parser.getName().equals("intent-filter")) {
4348 ActivityIntentInfo intent = new ActivityIntentInfo(a);
4349 if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
4350 intent, outError)) {
4353 if (intent.countActions() == 0) {
4354 Slog.w(TAG, "No actions in intent filter at "
4355 + mArchiveSourcePath + " "
4356 + parser.getPositionDescription());
4358 a.intents.add(intent);
4360 // adjust activity flags when we implicitly expose it via a browsable filter
4361 final int visibility = visibleToEphemeral
4362 ? IntentFilter.VISIBILITY_EXPLICIT
4363 : !receiver && isImplicitlyExposedIntent(intent)
4364 ? IntentFilter.VISIBILITY_IMPLICIT
4365 : IntentFilter.VISIBILITY_NONE;
4366 intent.setVisibilityToInstantApp(visibility);
4367 if (intent.isVisibleToInstantApp()) {
4368 a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4370 if (intent.isImplicitlyVisibleToInstantApp()) {
4371 a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
4373 if (LOG_UNSAFE_BROADCASTS && receiver
4374 && (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O)) {
4375 for (int i = 0; i < intent.countActions(); i++) {
4376 final String action = intent.getAction(i);
4377 if (action == null || !action.startsWith("android.")) continue;
4378 if (!SAFE_BROADCASTS.contains(action)) {
4379 Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
4380 + owner.packageName + " as requested at: "
4381 + parser.getPositionDescription());
4385 } else if (!receiver && parser.getName().equals("preferred")) {
4386 ActivityIntentInfo intent = new ActivityIntentInfo(a);
4387 if (!parseIntent(res, parser, false /*allowGlobs*/, false /*allowAutoVerify*/,
4388 intent, outError)) {
4391 if (intent.countActions() == 0) {
4392 Slog.w(TAG, "No actions in preferred at "
4393 + mArchiveSourcePath + " "
4394 + parser.getPositionDescription());
4396 if (owner.preferredActivityFilters == null) {
4397 owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
4399 owner.preferredActivityFilters.add(intent);
4401 // adjust activity flags when we implicitly expose it via a browsable filter
4402 final int visibility = visibleToEphemeral
4403 ? IntentFilter.VISIBILITY_EXPLICIT
4404 : !receiver && isImplicitlyExposedIntent(intent)
4405 ? IntentFilter.VISIBILITY_IMPLICIT
4406 : IntentFilter.VISIBILITY_NONE;
4407 intent.setVisibilityToInstantApp(visibility);
4408 if (intent.isVisibleToInstantApp()) {
4409 a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4411 if (intent.isImplicitlyVisibleToInstantApp()) {
4412 a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
4414 } else if (parser.getName().equals("meta-data")) {
4415 if ((a.metaData = parseMetaData(res, parser, a.metaData,
4416 outError)) == null) {
4419 // we don't have an attribute [or it's false], but, we have meta-data
4420 if (!visibleToEphemeral && a.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
4421 visibleToEphemeral = true; // set in case there are more intent filters
4422 a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4423 a.info.flags &= ~ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
4424 owner.visibleToInstantApps = true;
4425 // cycle through any filters already seen
4426 for (int i = a.intents.size() - 1; i >= 0; --i) {
4428 .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
4430 if (owner.preferredActivityFilters != null) {
4431 for (int i = owner.preferredActivityFilters.size() - 1; i >= 0; --i) {
4432 owner.preferredActivityFilters.get(i)
4433 .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
4437 } else if (!receiver && parser.getName().equals("layout")) {
4438 parseLayout(res, parser, a);
4440 if (!RIGID_PARSER) {
4441 Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
4443 Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
4444 + " at " + mArchiveSourcePath + " "
4445 + parser.getPositionDescription());
4447 Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
4448 + " at " + mArchiveSourcePath + " "
4449 + parser.getPositionDescription());
4451 XmlUtils.skipCurrentTag(parser);
4455 outError[0] = "Bad element under <receiver>: " + parser.getName();
4457 outError[0] = "Bad element under <activity>: " + parser.getName();
4465 a.info.exported = a.intents.size() > 0;
4471 private void setActivityResizeMode(ActivityInfo aInfo, TypedArray sa, Package owner) {
4472 final boolean appExplicitDefault = (owner.applicationInfo.privateFlags
4473 & (PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
4474 | PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0;
4476 if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity)
4477 || appExplicitDefault) {
4478 // Activity or app explicitly set if it is resizeable or not;
4479 final boolean appResizeable = (owner.applicationInfo.privateFlags
4480 & PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0;
4481 if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
4483 aInfo.resizeMode = RESIZE_MODE_RESIZEABLE;
4485 aInfo.resizeMode = RESIZE_MODE_UNRESIZEABLE;
4490 if ((owner.applicationInfo.privateFlags
4491 & PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) != 0) {
4492 // The activity or app didn't explicitly set the resizing option, however we want to
4493 // make it resize due to the sdk version it is targeting.
4494 aInfo.resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
4498 // resize preference isn't set and target sdk version doesn't support resizing apps by
4499 // default. For the app to be resizeable if it isn't fixed orientation or immersive.
4500 if (aInfo.isFixedOrientationPortrait()) {
4501 aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
4502 } else if (aInfo.isFixedOrientationLandscape()) {
4503 aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
4504 } else if (aInfo.isFixedOrientation()) {
4505 aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
4507 aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
4512 * Sets every the max aspect ratio of every child activity that doesn't already have an aspect
4515 private void setMaxAspectRatio(Package owner) {
4516 // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater.
4517 // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD.
4518 float maxAspectRatio = owner.applicationInfo.targetSdkVersion < O
4519 ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
4521 if (owner.applicationInfo.maxAspectRatio != 0) {
4522 // Use the application max aspect ration as default if set.
4523 maxAspectRatio = owner.applicationInfo.maxAspectRatio;
4524 } else if (owner.mAppMetaData != null
4525 && owner.mAppMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) {
4526 maxAspectRatio = owner.mAppMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio);
4529 for (Activity activity : owner.activities) {
4530 // If the max aspect ratio for the activity has already been set, skip.
4531 if (activity.hasMaxAspectRatio()) {
4535 // By default we prefer to use a values defined on the activity directly than values
4536 // defined on the application. We do not check the styled attributes on the activity
4537 // as it would have already been set when we processed the activity. We wait to process
4538 // the meta data here since this method is called at the end of processing the
4539 // application and all meta data is guaranteed.
4540 final float activityAspectRatio = activity.metaData != null
4541 ? activity.metaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio)
4544 activity.setMaxAspectRatio(activityAspectRatio);
4549 * @param configChanges The bit mask of configChanges fetched from AndroidManifest.xml.
4550 * @param recreateOnConfigChanges The bit mask recreateOnConfigChanges fetched from
4551 * AndroidManifest.xml.
4552 * @hide Exposed for unit testing only.
4555 public static int getActivityConfigChanges(int configChanges, int recreateOnConfigChanges) {
4556 return configChanges | ((~recreateOnConfigChanges) & RECREATE_ON_CONFIG_CHANGES_MASK);
4559 private void parseLayout(Resources res, AttributeSet attrs, Activity a) {
4560 TypedArray sw = res.obtainAttributes(attrs,
4561 com.android.internal.R.styleable.AndroidManifestLayout);
4563 float widthFraction = -1f;
4565 float heightFraction = -1f;
4566 final int widthType = sw.getType(
4567 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth);
4568 if (widthType == TypedValue.TYPE_FRACTION) {
4569 widthFraction = sw.getFraction(
4570 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth,
4572 } else if (widthType == TypedValue.TYPE_DIMENSION) {
4573 width = sw.getDimensionPixelSize(
4574 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth,
4577 final int heightType = sw.getType(
4578 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight);
4579 if (heightType == TypedValue.TYPE_FRACTION) {
4580 heightFraction = sw.getFraction(
4581 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight,
4583 } else if (heightType == TypedValue.TYPE_DIMENSION) {
4584 height = sw.getDimensionPixelSize(
4585 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight,
4588 int gravity = sw.getInt(
4589 com.android.internal.R.styleable.AndroidManifestLayout_gravity,
4591 int minWidth = sw.getDimensionPixelSize(
4592 com.android.internal.R.styleable.AndroidManifestLayout_minWidth,
4594 int minHeight = sw.getDimensionPixelSize(
4595 com.android.internal.R.styleable.AndroidManifestLayout_minHeight,
4598 a.info.windowLayout = new ActivityInfo.WindowLayout(width, widthFraction,
4599 height, heightFraction, gravity, minWidth, minHeight);
4602 private Activity parseActivityAlias(Package owner, Resources res,
4603 XmlResourceParser parser, int flags, String[] outError)
4604 throws XmlPullParserException, IOException {
4605 TypedArray sa = res.obtainAttributes(parser,
4606 com.android.internal.R.styleable.AndroidManifestActivityAlias);
4608 String targetActivity = sa.getNonConfigurationString(
4609 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity,
4610 Configuration.NATIVE_CONFIG_VERSION);
4611 if (targetActivity == null) {
4612 outError[0] = "<activity-alias> does not specify android:targetActivity";
4617 targetActivity = buildClassName(owner.applicationInfo.packageName,
4618 targetActivity, outError);
4619 if (targetActivity == null) {
4624 if (mParseActivityAliasArgs == null) {
4625 mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
4626 com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
4627 com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
4628 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
4629 com.android.internal.R.styleable.AndroidManifestActivityAlias_roundIcon,
4630 com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
4631 com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
4634 com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
4635 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
4636 mParseActivityAliasArgs.tag = "<activity-alias>";
4639 mParseActivityAliasArgs.sa = sa;
4640 mParseActivityAliasArgs.flags = flags;
4642 Activity target = null;
4644 final int NA = owner.activities.size();
4645 for (int i=0; i<NA; i++) {
4646 Activity t = owner.activities.get(i);
4647 if (targetActivity.equals(t.info.name)) {
4653 if (target == null) {
4654 outError[0] = "<activity-alias> target activity " + targetActivity
4655 + " not found in manifest";
4660 ActivityInfo info = new ActivityInfo();
4661 info.targetActivity = targetActivity;
4662 info.configChanges = target.info.configChanges;
4663 info.flags = target.info.flags;
4664 info.icon = target.info.icon;
4665 info.logo = target.info.logo;
4666 info.banner = target.info.banner;
4667 info.labelRes = target.info.labelRes;
4668 info.nonLocalizedLabel = target.info.nonLocalizedLabel;
4669 info.launchMode = target.info.launchMode;
4670 info.lockTaskLaunchMode = target.info.lockTaskLaunchMode;
4671 info.processName = target.info.processName;
4672 if (info.descriptionRes == 0) {
4673 info.descriptionRes = target.info.descriptionRes;
4675 info.screenOrientation = target.info.screenOrientation;
4676 info.taskAffinity = target.info.taskAffinity;
4677 info.theme = target.info.theme;
4678 info.softInputMode = target.info.softInputMode;
4679 info.uiOptions = target.info.uiOptions;
4680 info.parentActivityName = target.info.parentActivityName;
4681 info.maxRecents = target.info.maxRecents;
4682 info.windowLayout = target.info.windowLayout;
4683 info.resizeMode = target.info.resizeMode;
4684 info.maxAspectRatio = target.info.maxAspectRatio;
4686 info.encryptionAware = info.directBootAware = target.info.directBootAware;
4688 Activity a = new Activity(mParseActivityAliasArgs, info);
4689 if (outError[0] != null) {
4694 final boolean setExported = sa.hasValue(
4695 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported);
4697 a.info.exported = sa.getBoolean(
4698 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false);
4702 str = sa.getNonConfigurationString(
4703 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0);
4705 a.info.permission = str.length() > 0 ? str.toString().intern() : null;
4708 String parentName = sa.getNonConfigurationString(
4709 com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName,
4710 Configuration.NATIVE_CONFIG_VERSION);
4711 if (parentName != null) {
4712 String parentClassName = buildClassName(a.info.packageName, parentName, outError);
4713 if (outError[0] == null) {
4714 a.info.parentActivityName = parentClassName;
4716 Log.e(TAG, "Activity alias " + a.info.name +
4717 " specified invalid parentActivityName " + parentName);
4722 // TODO add visibleToInstantApps attribute to activity alias
4723 final boolean visibleToEphemeral =
4724 ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0);
4728 if (outError[0] != null) {
4732 int outerDepth = parser.getDepth();
4734 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4735 && (type != XmlPullParser.END_TAG
4736 || parser.getDepth() > outerDepth)) {
4737 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4741 if (parser.getName().equals("intent-filter")) {
4742 ActivityIntentInfo intent = new ActivityIntentInfo(a);
4743 if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
4744 intent, outError)) {
4747 if (intent.countActions() == 0) {
4748 Slog.w(TAG, "No actions in intent filter at "
4749 + mArchiveSourcePath + " "
4750 + parser.getPositionDescription());
4752 a.intents.add(intent);
4754 // adjust activity flags when we implicitly expose it via a browsable filter
4755 final int visibility = visibleToEphemeral
4756 ? IntentFilter.VISIBILITY_EXPLICIT
4757 : isImplicitlyExposedIntent(intent)
4758 ? IntentFilter.VISIBILITY_IMPLICIT
4759 : IntentFilter.VISIBILITY_NONE;
4760 intent.setVisibilityToInstantApp(visibility);
4761 if (intent.isVisibleToInstantApp()) {
4762 a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4764 if (intent.isImplicitlyVisibleToInstantApp()) {
4765 a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
4767 } else if (parser.getName().equals("meta-data")) {
4768 if ((a.metaData=parseMetaData(res, parser, a.metaData,
4769 outError)) == null) {
4773 if (!RIGID_PARSER) {
4774 Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName()
4775 + " at " + mArchiveSourcePath + " "
4776 + parser.getPositionDescription());
4777 XmlUtils.skipCurrentTag(parser);
4780 outError[0] = "Bad element under <activity-alias>: " + parser.getName();
4787 a.info.exported = a.intents.size() > 0;
4793 private Provider parseProvider(Package owner, Resources res,
4794 XmlResourceParser parser, int flags, String[] outError)
4795 throws XmlPullParserException, IOException {
4796 TypedArray sa = res.obtainAttributes(parser,
4797 com.android.internal.R.styleable.AndroidManifestProvider);
4799 if (mParseProviderArgs == null) {
4800 mParseProviderArgs = new ParseComponentArgs(owner, outError,
4801 com.android.internal.R.styleable.AndroidManifestProvider_name,
4802 com.android.internal.R.styleable.AndroidManifestProvider_label,
4803 com.android.internal.R.styleable.AndroidManifestProvider_icon,
4804 com.android.internal.R.styleable.AndroidManifestProvider_roundIcon,
4805 com.android.internal.R.styleable.AndroidManifestProvider_logo,
4806 com.android.internal.R.styleable.AndroidManifestProvider_banner,
4808 com.android.internal.R.styleable.AndroidManifestProvider_process,
4809 com.android.internal.R.styleable.AndroidManifestProvider_description,
4810 com.android.internal.R.styleable.AndroidManifestProvider_enabled);
4811 mParseProviderArgs.tag = "<provider>";
4814 mParseProviderArgs.sa = sa;
4815 mParseProviderArgs.flags = flags;
4817 Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
4818 if (outError[0] != null) {
4823 boolean providerExportedDefault = false;
4825 if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
4826 // For compatibility, applications targeting API level 16 or lower
4827 // should have their content providers exported by default, unless they
4828 // specify otherwise.
4829 providerExportedDefault = true;
4832 p.info.exported = sa.getBoolean(
4833 com.android.internal.R.styleable.AndroidManifestProvider_exported,
4834 providerExportedDefault);
4836 String cpname = sa.getNonConfigurationString(
4837 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0);
4839 p.info.isSyncable = sa.getBoolean(
4840 com.android.internal.R.styleable.AndroidManifestProvider_syncable,
4843 String permission = sa.getNonConfigurationString(
4844 com.android.internal.R.styleable.AndroidManifestProvider_permission, 0);
4845 String str = sa.getNonConfigurationString(
4846 com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0);
4851 p.info.readPermission = owner.applicationInfo.permission;
4853 p.info.readPermission =
4854 str.length() > 0 ? str.toString().intern() : null;
4856 str = sa.getNonConfigurationString(
4857 com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0);
4862 p.info.writePermission = owner.applicationInfo.permission;
4864 p.info.writePermission =
4865 str.length() > 0 ? str.toString().intern() : null;
4868 p.info.grantUriPermissions = sa.getBoolean(
4869 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
4872 p.info.multiprocess = sa.getBoolean(
4873 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
4876 p.info.initOrder = sa.getInt(
4877 com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
4881 sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0);
4886 com.android.internal.R.styleable.AndroidManifestProvider_singleUser,
4888 p.info.flags |= ProviderInfo.FLAG_SINGLE_USER;
4889 if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
4890 Slog.w(TAG, "Provider exported request ignored due to singleUser: "
4891 + p.className + " at " + mArchiveSourcePath + " "
4892 + parser.getPositionDescription());
4893 p.info.exported = false;
4897 p.info.encryptionAware = p.info.directBootAware = sa.getBoolean(
4898 R.styleable.AndroidManifestProvider_directBootAware,
4900 if (p.info.directBootAware) {
4901 owner.applicationInfo.privateFlags |=
4902 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
4905 final boolean visibleToEphemeral =
4906 sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
4907 if (visibleToEphemeral) {
4908 p.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4909 owner.visibleToInstantApps = true;
4914 if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
4916 // A heavy-weight application can not have providers in its main process
4917 // We can do direct compare because we intern all strings.
4918 if (p.info.processName == owner.packageName) {
4919 outError[0] = "Heavy-weight applications can not have providers in main process";
4924 if (cpname == null) {
4925 outError[0] = "<provider> does not include authorities attribute";
4928 if (cpname.length() <= 0) {
4929 outError[0] = "<provider> has empty authorities attribute";
4932 p.info.authority = cpname.intern();
4934 if (!parseProviderTags(
4935 res, parser, visibleToEphemeral, owner, p, outError)) {
4942 private boolean parseProviderTags(Resources res, XmlResourceParser parser,
4943 boolean visibleToEphemeral, Package owner, Provider outInfo, String[] outError)
4944 throws XmlPullParserException, IOException {
4945 int outerDepth = parser.getDepth();
4947 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4948 && (type != XmlPullParser.END_TAG
4949 || parser.getDepth() > outerDepth)) {
4950 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4954 if (parser.getName().equals("intent-filter")) {
4955 ProviderIntentInfo intent = new ProviderIntentInfo(outInfo);
4956 if (!parseIntent(res, parser, true /*allowGlobs*/, false /*allowAutoVerify*/,
4957 intent, outError)) {
4960 if (visibleToEphemeral) {
4961 intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
4962 outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4964 outInfo.intents.add(intent);
4966 } else if (parser.getName().equals("meta-data")) {
4967 if ((outInfo.metaData=parseMetaData(res, parser,
4968 outInfo.metaData, outError)) == null) {
4971 // we don't have an attribute [or it's false], but, we have meta-data
4972 if (!visibleToEphemeral && outInfo.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
4973 visibleToEphemeral = true; // set in case there are more intent filters
4974 outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4975 owner.visibleToInstantApps = true;
4976 // cycle through any filters already seen
4977 for (int i = outInfo.intents.size() - 1; i >= 0; --i) {
4978 outInfo.intents.get(i)
4979 .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
4983 } else if (parser.getName().equals("grant-uri-permission")) {
4984 TypedArray sa = res.obtainAttributes(parser,
4985 com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
4987 PatternMatcher pa = null;
4989 String str = sa.getNonConfigurationString(
4990 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0);
4992 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
4995 str = sa.getNonConfigurationString(
4996 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
4998 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
5001 str = sa.getNonConfigurationString(
5002 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
5004 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
5010 if (outInfo.info.uriPermissionPatterns == null) {
5011 outInfo.info.uriPermissionPatterns = new PatternMatcher[1];
5012 outInfo.info.uriPermissionPatterns[0] = pa;
5014 final int N = outInfo.info.uriPermissionPatterns.length;
5015 PatternMatcher[] newp = new PatternMatcher[N+1];
5016 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N);
5018 outInfo.info.uriPermissionPatterns = newp;
5020 outInfo.info.grantUriPermissions = true;
5022 if (!RIGID_PARSER) {
5023 Slog.w(TAG, "Unknown element under <path-permission>: "
5024 + parser.getName() + " at " + mArchiveSourcePath + " "
5025 + parser.getPositionDescription());
5026 XmlUtils.skipCurrentTag(parser);
5029 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
5033 XmlUtils.skipCurrentTag(parser);
5035 } else if (parser.getName().equals("path-permission")) {
5036 TypedArray sa = res.obtainAttributes(parser,
5037 com.android.internal.R.styleable.AndroidManifestPathPermission);
5039 PathPermission pa = null;
5041 String permission = sa.getNonConfigurationString(
5042 com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0);
5043 String readPermission = sa.getNonConfigurationString(
5044 com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0);
5045 if (readPermission == null) {
5046 readPermission = permission;
5048 String writePermission = sa.getNonConfigurationString(
5049 com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0);
5050 if (writePermission == null) {
5051 writePermission = permission;
5054 boolean havePerm = false;
5055 if (readPermission != null) {
5056 readPermission = readPermission.intern();
5059 if (writePermission != null) {
5060 writePermission = writePermission.intern();
5065 if (!RIGID_PARSER) {
5066 Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
5067 + parser.getName() + " at " + mArchiveSourcePath + " "
5068 + parser.getPositionDescription());
5069 XmlUtils.skipCurrentTag(parser);
5072 outError[0] = "No readPermission or writePermssion for <path-permission>";
5077 String path = sa.getNonConfigurationString(
5078 com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0);
5080 pa = new PathPermission(path,
5081 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
5084 path = sa.getNonConfigurationString(
5085 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
5087 pa = new PathPermission(path,
5088 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
5091 path = sa.getNonConfigurationString(
5092 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0);
5094 pa = new PathPermission(path,
5095 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
5098 path = sa.getNonConfigurationString(
5099 com.android.internal.R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0);
5101 pa = new PathPermission(path,
5102 PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission);
5108 if (outInfo.info.pathPermissions == null) {
5109 outInfo.info.pathPermissions = new PathPermission[1];
5110 outInfo.info.pathPermissions[0] = pa;
5112 final int N = outInfo.info.pathPermissions.length;
5113 PathPermission[] newp = new PathPermission[N+1];
5114 System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
5116 outInfo.info.pathPermissions = newp;
5119 if (!RIGID_PARSER) {
5120 Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
5121 + parser.getName() + " at " + mArchiveSourcePath + " "
5122 + parser.getPositionDescription());
5123 XmlUtils.skipCurrentTag(parser);
5126 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
5129 XmlUtils.skipCurrentTag(parser);
5132 if (!RIGID_PARSER) {
5133 Slog.w(TAG, "Unknown element under <provider>: "
5134 + parser.getName() + " at " + mArchiveSourcePath + " "
5135 + parser.getPositionDescription());
5136 XmlUtils.skipCurrentTag(parser);
5139 outError[0] = "Bad element under <provider>: " + parser.getName();
5147 private Service parseService(Package owner, Resources res,
5148 XmlResourceParser parser, int flags, String[] outError)
5149 throws XmlPullParserException, IOException {
5150 TypedArray sa = res.obtainAttributes(parser,
5151 com.android.internal.R.styleable.AndroidManifestService);
5153 if (mParseServiceArgs == null) {
5154 mParseServiceArgs = new ParseComponentArgs(owner, outError,
5155 com.android.internal.R.styleable.AndroidManifestService_name,
5156 com.android.internal.R.styleable.AndroidManifestService_label,
5157 com.android.internal.R.styleable.AndroidManifestService_icon,
5158 com.android.internal.R.styleable.AndroidManifestService_roundIcon,
5159 com.android.internal.R.styleable.AndroidManifestService_logo,
5160 com.android.internal.R.styleable.AndroidManifestService_banner,
5162 com.android.internal.R.styleable.AndroidManifestService_process,
5163 com.android.internal.R.styleable.AndroidManifestService_description,
5164 com.android.internal.R.styleable.AndroidManifestService_enabled);
5165 mParseServiceArgs.tag = "<service>";
5168 mParseServiceArgs.sa = sa;
5169 mParseServiceArgs.flags = flags;
5171 Service s = new Service(mParseServiceArgs, new ServiceInfo());
5172 if (outError[0] != null) {
5177 boolean setExported = sa.hasValue(
5178 com.android.internal.R.styleable.AndroidManifestService_exported);
5180 s.info.exported = sa.getBoolean(
5181 com.android.internal.R.styleable.AndroidManifestService_exported, false);
5184 String str = sa.getNonConfigurationString(
5185 com.android.internal.R.styleable.AndroidManifestService_permission, 0);
5187 s.info.permission = owner.applicationInfo.permission;
5189 s.info.permission = str.length() > 0 ? str.toString().intern() : null;
5193 sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0);
5197 com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
5199 s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
5202 com.android.internal.R.styleable.AndroidManifestService_isolatedProcess,
5204 s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
5207 com.android.internal.R.styleable.AndroidManifestService_externalService,
5209 s.info.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
5212 com.android.internal.R.styleable.AndroidManifestService_singleUser,
5214 s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
5215 if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
5216 Slog.w(TAG, "Service exported request ignored due to singleUser: "
5217 + s.className + " at " + mArchiveSourcePath + " "
5218 + parser.getPositionDescription());
5219 s.info.exported = false;
5224 s.info.encryptionAware = s.info.directBootAware = sa.getBoolean(
5225 R.styleable.AndroidManifestService_directBootAware,
5227 if (s.info.directBootAware) {
5228 owner.applicationInfo.privateFlags |=
5229 ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
5232 boolean visibleToEphemeral =
5233 sa.getBoolean(R.styleable.AndroidManifestService_visibleToInstantApps, false);
5234 if (visibleToEphemeral) {
5235 s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
5236 owner.visibleToInstantApps = true;
5241 if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
5243 // A heavy-weight application can not have services in its main process
5244 // We can do direct compare because we intern all strings.
5245 if (s.info.processName == owner.packageName) {
5246 outError[0] = "Heavy-weight applications can not have services in main process";
5251 int outerDepth = parser.getDepth();
5253 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
5254 && (type != XmlPullParser.END_TAG
5255 || parser.getDepth() > outerDepth)) {
5256 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
5260 if (parser.getName().equals("intent-filter")) {
5261 ServiceIntentInfo intent = new ServiceIntentInfo(s);
5262 if (!parseIntent(res, parser, true /*allowGlobs*/, false /*allowAutoVerify*/,
5263 intent, outError)) {
5266 if (visibleToEphemeral) {
5267 intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
5268 s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
5270 s.intents.add(intent);
5271 } else if (parser.getName().equals("meta-data")) {
5272 if ((s.metaData=parseMetaData(res, parser, s.metaData,
5273 outError)) == null) {
5276 // we don't have an attribute [or it's false], but, we have meta-data
5277 if (!visibleToEphemeral && s.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
5278 visibleToEphemeral = true; // set in case there are more intent filters
5279 s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
5280 owner.visibleToInstantApps = true;
5281 // cycle through any filters already seen
5282 for (int i = s.intents.size() - 1; i >= 0; --i) {
5284 .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
5288 if (!RIGID_PARSER) {
5289 Slog.w(TAG, "Unknown element under <service>: "
5290 + parser.getName() + " at " + mArchiveSourcePath + " "
5291 + parser.getPositionDescription());
5292 XmlUtils.skipCurrentTag(parser);
5295 outError[0] = "Bad element under <service>: " + parser.getName();
5302 s.info.exported = s.intents.size() > 0;
5308 private boolean isImplicitlyExposedIntent(IntentInfo intent) {
5309 return intent.hasCategory(Intent.CATEGORY_BROWSABLE)
5310 || intent.hasAction(Intent.ACTION_SEND)
5311 || intent.hasAction(Intent.ACTION_SENDTO)
5312 || intent.hasAction(Intent.ACTION_SEND_MULTIPLE);
5315 private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag,
5316 Component<?> outInfo, String[] outError) throws XmlPullParserException, IOException {
5317 int outerDepth = parser.getDepth();
5319 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
5320 && (type != XmlPullParser.END_TAG
5321 || parser.getDepth() > outerDepth)) {
5322 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
5326 if (parser.getName().equals("meta-data")) {
5327 if ((outInfo.metaData=parseMetaData(res, parser,
5328 outInfo.metaData, outError)) == null) {
5332 if (!RIGID_PARSER) {
5333 Slog.w(TAG, "Unknown element under " + tag + ": "
5334 + parser.getName() + " at " + mArchiveSourcePath + " "
5335 + parser.getPositionDescription());
5336 XmlUtils.skipCurrentTag(parser);
5339 outError[0] = "Bad element under " + tag + ": " + parser.getName();
5347 private Bundle parseMetaData(Resources res,
5348 XmlResourceParser parser, Bundle data, String[] outError)
5349 throws XmlPullParserException, IOException {
5351 TypedArray sa = res.obtainAttributes(parser,
5352 com.android.internal.R.styleable.AndroidManifestMetaData);
5355 data = new Bundle();
5358 String name = sa.getNonConfigurationString(
5359 com.android.internal.R.styleable.AndroidManifestMetaData_name, 0);
5361 outError[0] = "<meta-data> requires an android:name attribute";
5366 name = name.intern();
5368 TypedValue v = sa.peekValue(
5369 com.android.internal.R.styleable.AndroidManifestMetaData_resource);
5370 if (v != null && v.resourceId != 0) {
5371 //Slog.i(TAG, "Meta data ref " + name + ": " + v);
5372 data.putInt(name, v.resourceId);
5375 com.android.internal.R.styleable.AndroidManifestMetaData_value);
5376 //Slog.i(TAG, "Meta data " + name + ": " + v);
5378 if (v.type == TypedValue.TYPE_STRING) {
5379 CharSequence cs = v.coerceToString();
5380 data.putString(name, cs != null ? cs.toString() : null);
5381 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
5382 data.putBoolean(name, v.data != 0);
5383 } else if (v.type >= TypedValue.TYPE_FIRST_INT
5384 && v.type <= TypedValue.TYPE_LAST_INT) {
5385 data.putInt(name, v.data);
5386 } else if (v.type == TypedValue.TYPE_FLOAT) {
5387 data.putFloat(name, v.getFloat());
5389 if (!RIGID_PARSER) {
5390 Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: "
5391 + parser.getName() + " at " + mArchiveSourcePath + " "
5392 + parser.getPositionDescription());
5394 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types";
5399 outError[0] = "<meta-data> requires an android:value or android:resource attribute";
5406 XmlUtils.skipCurrentTag(parser);
5411 private static VerifierInfo parseVerifier(AttributeSet attrs) {
5412 String packageName = null;
5413 String encodedPublicKey = null;
5415 final int attrCount = attrs.getAttributeCount();
5416 for (int i = 0; i < attrCount; i++) {
5417 final int attrResId = attrs.getAttributeNameResource(i);
5418 switch (attrResId) {
5419 case com.android.internal.R.attr.name:
5420 packageName = attrs.getAttributeValue(i);
5423 case com.android.internal.R.attr.publicKey:
5424 encodedPublicKey = attrs.getAttributeValue(i);
5429 if (packageName == null || packageName.length() == 0) {
5430 Slog.i(TAG, "verifier package name was null; skipping");
5434 final PublicKey publicKey = parsePublicKey(encodedPublicKey);
5435 if (publicKey == null) {
5436 Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
5440 return new VerifierInfo(packageName, publicKey);
5443 public static final PublicKey parsePublicKey(final String encodedPublicKey) {
5444 if (encodedPublicKey == null) {
5445 Slog.w(TAG, "Could not parse null public key");
5449 EncodedKeySpec keySpec;
5451 final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT);
5452 keySpec = new X509EncodedKeySpec(encoded);
5453 } catch (IllegalArgumentException e) {
5454 Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
5458 /* First try the key as an RSA key. */
5460 final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
5461 return keyFactory.generatePublic(keySpec);
5462 } catch (NoSuchAlgorithmException e) {
5463 Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build");
5464 } catch (InvalidKeySpecException e) {
5465 // Not a RSA public key.
5468 /* Now try it as a ECDSA key. */
5470 final KeyFactory keyFactory = KeyFactory.getInstance("EC");
5471 return keyFactory.generatePublic(keySpec);
5472 } catch (NoSuchAlgorithmException e) {
5473 Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build");
5474 } catch (InvalidKeySpecException e) {
5475 // Not a ECDSA public key.
5478 /* Now try it as a DSA key. */
5480 final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
5481 return keyFactory.generatePublic(keySpec);
5482 } catch (NoSuchAlgorithmException e) {
5483 Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build");
5484 } catch (InvalidKeySpecException e) {
5485 // Not a DSA public key.
5488 /* Not a supported key type */
5492 private static final String ANDROID_RESOURCES
5493 = "http://schemas.android.com/apk/res/android";
5495 private boolean parseIntent(Resources res, XmlResourceParser parser, boolean allowGlobs,
5496 boolean allowAutoVerify, IntentInfo outInfo, String[] outError)
5497 throws XmlPullParserException, IOException {
5499 TypedArray sa = res.obtainAttributes(parser,
5500 com.android.internal.R.styleable.AndroidManifestIntentFilter);
5502 int priority = sa.getInt(
5503 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
5504 outInfo.setPriority(priority);
5506 TypedValue v = sa.peekValue(
5507 com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
5508 if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
5509 outInfo.nonLocalizedLabel = v.coerceToString();
5512 final boolean useRoundIcon =
5513 Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
5514 int roundIconVal = useRoundIcon ? sa.getResourceId(
5515 com.android.internal.R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0;
5516 if (roundIconVal != 0) {
5517 outInfo.icon = roundIconVal;
5519 outInfo.icon = sa.getResourceId(
5520 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
5523 outInfo.logo = sa.getResourceId(
5524 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
5526 outInfo.banner = sa.getResourceId(
5527 com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0);
5529 if (allowAutoVerify) {
5530 outInfo.setAutoVerify(sa.getBoolean(
5531 com.android.internal.R.styleable.AndroidManifestIntentFilter_autoVerify,
5537 int outerDepth = parser.getDepth();
5539 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
5540 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
5541 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
5545 String nodeName = parser.getName();
5546 if (nodeName.equals("action")) {
5547 String value = parser.getAttributeValue(
5548 ANDROID_RESOURCES, "name");
5549 if (value == null || value == "") {
5550 outError[0] = "No value supplied for <android:name>";
5553 XmlUtils.skipCurrentTag(parser);
5555 outInfo.addAction(value);
5556 } else if (nodeName.equals("category")) {
5557 String value = parser.getAttributeValue(
5558 ANDROID_RESOURCES, "name");
5559 if (value == null || value == "") {
5560 outError[0] = "No value supplied for <android:name>";
5563 XmlUtils.skipCurrentTag(parser);
5565 outInfo.addCategory(value);
5567 } else if (nodeName.equals("data")) {
5568 sa = res.obtainAttributes(parser,
5569 com.android.internal.R.styleable.AndroidManifestData);
5571 String str = sa.getNonConfigurationString(
5572 com.android.internal.R.styleable.AndroidManifestData_mimeType, 0);
5575 outInfo.addDataType(str);
5576 } catch (IntentFilter.MalformedMimeTypeException e) {
5577 outError[0] = e.toString();
5583 str = sa.getNonConfigurationString(
5584 com.android.internal.R.styleable.AndroidManifestData_scheme, 0);
5586 outInfo.addDataScheme(str);
5589 str = sa.getNonConfigurationString(
5590 com.android.internal.R.styleable.AndroidManifestData_ssp, 0);
5592 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
5595 str = sa.getNonConfigurationString(
5596 com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0);
5598 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
5601 str = sa.getNonConfigurationString(
5602 com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0);
5605 outError[0] = "sspPattern not allowed here; ssp must be literal";
5608 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
5611 String host = sa.getNonConfigurationString(
5612 com.android.internal.R.styleable.AndroidManifestData_host, 0);
5613 String port = sa.getNonConfigurationString(
5614 com.android.internal.R.styleable.AndroidManifestData_port, 0);
5616 outInfo.addDataAuthority(host, port);
5619 str = sa.getNonConfigurationString(
5620 com.android.internal.R.styleable.AndroidManifestData_path, 0);
5622 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
5625 str = sa.getNonConfigurationString(
5626 com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0);
5628 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
5631 str = sa.getNonConfigurationString(
5632 com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
5635 outError[0] = "pathPattern not allowed here; path must be literal";
5638 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
5641 str = sa.getNonConfigurationString(
5642 com.android.internal.R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
5645 outError[0] = "pathAdvancedPattern not allowed here; path must be literal";
5648 outInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB);
5652 XmlUtils.skipCurrentTag(parser);
5653 } else if (!RIGID_PARSER) {
5654 Slog.w(TAG, "Unknown element under <intent-filter>: "
5655 + parser.getName() + " at " + mArchiveSourcePath + " "
5656 + parser.getPositionDescription());
5657 XmlUtils.skipCurrentTag(parser);
5659 outError[0] = "Bad element under <intent-filter>: " + parser.getName();
5664 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
5667 final StringBuilder cats = new StringBuilder("Intent d=");
5668 cats.append(outInfo.hasDefault);
5669 cats.append(", cat=");
5671 final Iterator<String> it = outInfo.categoriesIterator();
5673 while (it.hasNext()) {
5675 cats.append(it.next());
5678 Slog.d(TAG, cats.toString());
5685 * Representation of a full package parsed from APK files on disk. A package
5686 * consists of a single base APK, and zero or more split APKs.
5688 public final static class Package implements Parcelable {
5690 public String packageName;
5692 // The package name declared in the manifest as the package can be
5693 // renamed, for example static shared libs use synthetic package names.
5694 public String manifestPackageName;
5696 /** Names of any split APKs, ordered by parsed splitName */
5697 public String[] splitNames;
5699 // TODO: work towards making these paths invariant
5701 public String volumeUuid;
5704 * Path where this package was found on disk. For monolithic packages
5705 * this is path to single base APK file; for cluster packages this is
5706 * path to the cluster directory.
5708 public String codePath;
5710 /** Path of base APK */
5711 public String baseCodePath;
5712 /** Paths of any split APKs, ordered by parsed splitName */
5713 public String[] splitCodePaths;
5715 /** Revision code of base APK */
5716 public int baseRevisionCode;
5717 /** Revision codes of any split APKs, ordered by parsed splitName */
5718 public int[] splitRevisionCodes;
5720 /** Flags of any split APKs; ordered by parsed splitName */
5721 public int[] splitFlags;
5724 * Private flags of any split APKs; ordered by parsed splitName.
5728 public int[] splitPrivateFlags;
5730 public boolean baseHardwareAccelerated;
5732 // For now we only support one application per package.
5733 public ApplicationInfo applicationInfo = new ApplicationInfo();
5735 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
5736 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
5737 public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
5738 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
5739 public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
5740 public final ArrayList<Service> services = new ArrayList<Service>(0);
5741 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
5743 public final ArrayList<String> requestedPermissions = new ArrayList<String>();
5745 public ArrayList<String> protectedBroadcasts;
5747 public Package parentPackage;
5748 public ArrayList<Package> childPackages;
5750 public String staticSharedLibName = null;
5751 public int staticSharedLibVersion = 0;
5752 public ArrayList<String> libraryNames = null;
5753 public ArrayList<String> usesLibraries = null;
5754 public ArrayList<String> usesStaticLibraries = null;
5755 public int[] usesStaticLibrariesVersions = null;
5756 public String[] usesStaticLibrariesCertDigests = null;
5757 public ArrayList<String> usesOptionalLibraries = null;
5758 public String[] usesLibraryFiles = null;
5760 public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
5762 public ArrayList<String> mOriginalPackages = null;
5763 public String mRealPackage = null;
5764 public ArrayList<String> mAdoptPermissions = null;
5766 // We store the application meta-data independently to avoid multiple unwanted references
5767 public Bundle mAppMetaData = null;
5769 // The version code declared for this package.
5770 public int mVersionCode;
5772 // The version name declared for this package.
5773 public String mVersionName;
5775 // The shared user id that this package wants to use.
5776 public String mSharedUserId;
5778 // The shared user label that this package wants to use.
5779 public int mSharedUserLabel;
5781 // Signatures that were read from the package.
5782 public Signature[] mSignatures;
5783 public Certificate[][] mCertificates;
5785 // For use by package manager service for quick lookup of
5786 // preferred up order.
5787 public int mPreferredOrder = 0;
5789 // For use by package manager to keep track of when a package was last used.
5790 public long[] mLastPackageUsageTimeInMills =
5791 new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];
5793 // // User set enabled state.
5794 // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
5796 // // Whether the package has been stopped.
5797 // public boolean mSetStopped = false;
5799 // Additional data supplied by callers.
5800 public Object mExtras;
5802 // Applications hardware preferences
5803 public ArrayList<ConfigurationInfo> configPreferences = null;
5805 // Applications requested features
5806 public ArrayList<FeatureInfo> reqFeatures = null;
5808 // Applications requested feature groups
5809 public ArrayList<FeatureGroupInfo> featureGroups = null;
5811 public int installLocation;
5813 public boolean coreApp;
5815 /* An app that's required for all users and cannot be uninstalled for a user */
5816 public boolean mRequiredForAllUsers;
5818 /* The restricted account authenticator type that is used by this application */
5819 public String mRestrictedAccountType;
5821 /* The required account type without which this application will not function */
5822 public String mRequiredAccountType;
5824 public String mOverlayTarget;
5825 public int mOverlayPriority;
5826 public boolean mIsStaticOverlay;
5827 public boolean mTrustedOverlay;
5830 * Data used to feed the KeySetManagerService
5832 public ArraySet<PublicKey> mSigningKeys;
5833 public ArraySet<String> mUpgradeKeySets;
5834 public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
5837 * The install time abi override for this package, if any.
5839 * TODO: This seems like a horrible place to put the abiOverride because
5840 * this isn't something the packageParser parsers. However, this fits in with
5841 * the rest of the PackageManager where package scanning randomly pushes
5842 * and prods fields out of {@code this.applicationInfo}.
5844 public String cpuAbiOverride;
5846 * The install time abi override to choose 32bit abi's when multiple abi's
5847 * are present. This is only meaningfull for multiarch applications.
5848 * The use32bitAbi attribute is ignored if cpuAbiOverride is also set.
5850 public boolean use32bitAbi;
5852 public byte[] restrictUpdateHash;
5855 * Set if the app or any of its components are visible to Instant Apps.
5857 public boolean visibleToInstantApps;
5859 public Package(String packageName) {
5860 this.packageName = packageName;
5861 this.manifestPackageName = packageName;
5862 applicationInfo.packageName = packageName;
5863 applicationInfo.uid = -1;
5866 public void setApplicationVolumeUuid(String volumeUuid) {
5867 final UUID storageUuid = StorageManager.convert(volumeUuid);
5868 this.applicationInfo.volumeUuid = volumeUuid;
5869 this.applicationInfo.storageUuid = storageUuid;
5870 if (childPackages != null) {
5871 final int packageCount = childPackages.size();
5872 for (int i = 0; i < packageCount; i++) {
5873 childPackages.get(i).applicationInfo.volumeUuid = volumeUuid;
5874 childPackages.get(i).applicationInfo.storageUuid = storageUuid;
5879 public void setApplicationInfoCodePath(String codePath) {
5880 this.applicationInfo.setCodePath(codePath);
5881 if (childPackages != null) {
5882 final int packageCount = childPackages.size();
5883 for (int i = 0; i < packageCount; i++) {
5884 childPackages.get(i).applicationInfo.setCodePath(codePath);
5889 public void setApplicationInfoResourcePath(String resourcePath) {
5890 this.applicationInfo.setResourcePath(resourcePath);
5891 if (childPackages != null) {
5892 final int packageCount = childPackages.size();
5893 for (int i = 0; i < packageCount; i++) {
5894 childPackages.get(i).applicationInfo.setResourcePath(resourcePath);
5899 public void setApplicationInfoBaseResourcePath(String resourcePath) {
5900 this.applicationInfo.setBaseResourcePath(resourcePath);
5901 if (childPackages != null) {
5902 final int packageCount = childPackages.size();
5903 for (int i = 0; i < packageCount; i++) {
5904 childPackages.get(i).applicationInfo.setBaseResourcePath(resourcePath);
5909 public void setApplicationInfoBaseCodePath(String baseCodePath) {
5910 this.applicationInfo.setBaseCodePath(baseCodePath);
5911 if (childPackages != null) {
5912 final int packageCount = childPackages.size();
5913 for (int i = 0; i < packageCount; i++) {
5914 childPackages.get(i).applicationInfo.setBaseCodePath(baseCodePath);
5919 public List<String> getChildPackageNames() {
5920 if (childPackages == null) {
5923 final int childCount = childPackages.size();
5924 final List<String> childPackageNames = new ArrayList<>(childCount);
5925 for (int i = 0; i < childCount; i++) {
5926 String childPackageName = childPackages.get(i).packageName;
5927 childPackageNames.add(childPackageName);
5929 return childPackageNames;
5932 public boolean hasChildPackage(String packageName) {
5933 final int childCount = (childPackages != null) ? childPackages.size() : 0;
5934 for (int i = 0; i < childCount; i++) {
5935 if (childPackages.get(i).packageName.equals(packageName)) {
5942 public void setApplicationInfoSplitCodePaths(String[] splitCodePaths) {
5943 this.applicationInfo.setSplitCodePaths(splitCodePaths);
5944 // Children have no splits
5947 public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) {
5948 this.applicationInfo.setSplitResourcePaths(resroucePaths);
5949 // Children have no splits
5952 public void setSplitCodePaths(String[] codePaths) {
5953 this.splitCodePaths = codePaths;
5956 public void setCodePath(String codePath) {
5957 this.codePath = codePath;
5958 if (childPackages != null) {
5959 final int packageCount = childPackages.size();
5960 for (int i = 0; i < packageCount; i++) {
5961 childPackages.get(i).codePath = codePath;
5966 public void setBaseCodePath(String baseCodePath) {
5967 this.baseCodePath = baseCodePath;
5968 if (childPackages != null) {
5969 final int packageCount = childPackages.size();
5970 for (int i = 0; i < packageCount; i++) {
5971 childPackages.get(i).baseCodePath = baseCodePath;
5976 public void setSignatures(Signature[] signatures) {
5977 this.mSignatures = signatures;
5978 if (childPackages != null) {
5979 final int packageCount = childPackages.size();
5980 for (int i = 0; i < packageCount; i++) {
5981 childPackages.get(i).mSignatures = signatures;
5986 public void setVolumeUuid(String volumeUuid) {
5987 this.volumeUuid = volumeUuid;
5988 if (childPackages != null) {
5989 final int packageCount = childPackages.size();
5990 for (int i = 0; i < packageCount; i++) {
5991 childPackages.get(i).volumeUuid = volumeUuid;
5996 public void setApplicationInfoFlags(int mask, int flags) {
5997 applicationInfo.flags = (applicationInfo.flags & ~mask) | (mask & flags);
5998 if (childPackages != null) {
5999 final int packageCount = childPackages.size();
6000 for (int i = 0; i < packageCount; i++) {
6001 childPackages.get(i).applicationInfo.flags =
6002 (applicationInfo.flags & ~mask) | (mask & flags);
6007 public void setUse32bitAbi(boolean use32bitAbi) {
6008 this.use32bitAbi = use32bitAbi;
6009 if (childPackages != null) {
6010 final int packageCount = childPackages.size();
6011 for (int i = 0; i < packageCount; i++) {
6012 childPackages.get(i).use32bitAbi = use32bitAbi;
6017 public boolean isLibrary() {
6018 return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames);
6021 public List<String> getAllCodePaths() {
6022 ArrayList<String> paths = new ArrayList<>();
6023 paths.add(baseCodePath);
6024 if (!ArrayUtils.isEmpty(splitCodePaths)) {
6025 Collections.addAll(paths, splitCodePaths);
6031 * Filtered set of {@link #getAllCodePaths()} that excludes
6032 * resource-only APKs.
6034 public List<String> getAllCodePathsExcludingResourceOnly() {
6035 ArrayList<String> paths = new ArrayList<>();
6036 if ((applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
6037 paths.add(baseCodePath);
6039 if (!ArrayUtils.isEmpty(splitCodePaths)) {
6040 for (int i = 0; i < splitCodePaths.length; i++) {
6041 if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
6042 paths.add(splitCodePaths[i]);
6049 public void setPackageName(String newName) {
6050 packageName = newName;
6051 applicationInfo.packageName = newName;
6052 for (int i=permissions.size()-1; i>=0; i--) {
6053 permissions.get(i).setPackageName(newName);
6055 for (int i=permissionGroups.size()-1; i>=0; i--) {
6056 permissionGroups.get(i).setPackageName(newName);
6058 for (int i=activities.size()-1; i>=0; i--) {
6059 activities.get(i).setPackageName(newName);
6061 for (int i=receivers.size()-1; i>=0; i--) {
6062 receivers.get(i).setPackageName(newName);
6064 for (int i=providers.size()-1; i>=0; i--) {
6065 providers.get(i).setPackageName(newName);
6067 for (int i=services.size()-1; i>=0; i--) {
6068 services.get(i).setPackageName(newName);
6070 for (int i=instrumentation.size()-1; i>=0; i--) {
6071 instrumentation.get(i).setPackageName(newName);
6075 public boolean hasComponentClassName(String name) {
6076 for (int i=activities.size()-1; i>=0; i--) {
6077 if (name.equals(activities.get(i).className)) {
6081 for (int i=receivers.size()-1; i>=0; i--) {
6082 if (name.equals(receivers.get(i).className)) {
6086 for (int i=providers.size()-1; i>=0; i--) {
6087 if (name.equals(providers.get(i).className)) {
6091 for (int i=services.size()-1; i>=0; i--) {
6092 if (name.equals(services.get(i).className)) {
6096 for (int i=instrumentation.size()-1; i>=0; i--) {
6097 if (name.equals(instrumentation.get(i).className)) {
6107 public boolean isForwardLocked() {
6108 return applicationInfo.isForwardLocked();
6114 public boolean isSystemApp() {
6115 return applicationInfo.isSystemApp();
6121 public boolean isPrivilegedApp() {
6122 return applicationInfo.isPrivilegedApp();
6128 public boolean isUpdatedSystemApp() {
6129 return applicationInfo.isUpdatedSystemApp();
6135 public boolean canHaveOatDir() {
6136 // The following app types CANNOT have oat directory
6137 // - non-updated system apps
6138 // - forward-locked apps or apps installed in ASEC containers
6139 return (!isSystemApp() || isUpdatedSystemApp())
6140 && !isForwardLocked() && !applicationInfo.isExternalAsec();
6143 public boolean isMatch(int flags) {
6144 if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
6145 return isSystemApp();
6150 public long getLatestPackageUseTimeInMills() {
6151 long latestUse = 0L;
6152 for (long use : mLastPackageUsageTimeInMills) {
6153 latestUse = Math.max(latestUse, use);
6158 public long getLatestForegroundPackageUseTimeInMills() {
6159 int[] foregroundReasons = {
6160 PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY,
6161 PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE
6164 long latestUse = 0L;
6165 for (int reason : foregroundReasons) {
6166 latestUse = Math.max(latestUse, mLastPackageUsageTimeInMills[reason]);
6171 public String toString() {
6173 + Integer.toHexString(System.identityHashCode(this))
6174 + " " + packageName + "}";
6178 public int describeContents() {
6182 public Package(Parcel dest) {
6183 // We use the boot classloader for all classes that we load.
6184 final ClassLoader boot = Object.class.getClassLoader();
6186 packageName = dest.readString().intern();
6187 manifestPackageName = dest.readString();
6188 splitNames = dest.readStringArray();
6189 volumeUuid = dest.readString();
6190 codePath = dest.readString();
6191 baseCodePath = dest.readString();
6192 splitCodePaths = dest.readStringArray();
6193 baseRevisionCode = dest.readInt();
6194 splitRevisionCodes = dest.createIntArray();
6195 splitFlags = dest.createIntArray();
6196 splitPrivateFlags = dest.createIntArray();
6197 baseHardwareAccelerated = (dest.readInt() == 1);
6198 applicationInfo = dest.readParcelable(boot);
6199 if (applicationInfo.permission != null) {
6200 applicationInfo.permission = applicationInfo.permission.intern();
6203 // We don't serialize the "owner" package and the application info object for each of
6204 // these components, in order to save space and to avoid circular dependencies while
6205 // serialization. We need to fix them all up here.
6206 dest.readParcelableList(permissions, boot);
6207 fixupOwner(permissions);
6208 dest.readParcelableList(permissionGroups, boot);
6209 fixupOwner(permissionGroups);
6210 dest.readParcelableList(activities, boot);
6211 fixupOwner(activities);
6212 dest.readParcelableList(receivers, boot);
6213 fixupOwner(receivers);
6214 dest.readParcelableList(providers, boot);
6215 fixupOwner(providers);
6216 dest.readParcelableList(services, boot);
6217 fixupOwner(services);
6218 dest.readParcelableList(instrumentation, boot);
6219 fixupOwner(instrumentation);
6221 dest.readStringList(requestedPermissions);
6222 internStringArrayList(requestedPermissions);
6223 protectedBroadcasts = dest.createStringArrayList();
6224 internStringArrayList(protectedBroadcasts);
6226 parentPackage = dest.readParcelable(boot);
6228 childPackages = new ArrayList<>();
6229 dest.readParcelableList(childPackages, boot);
6230 if (childPackages.size() == 0) {
6231 childPackages = null;
6234 staticSharedLibName = dest.readString();
6235 if (staticSharedLibName != null) {
6236 staticSharedLibName = staticSharedLibName.intern();
6238 staticSharedLibVersion = dest.readInt();
6239 libraryNames = dest.createStringArrayList();
6240 internStringArrayList(libraryNames);
6241 usesLibraries = dest.createStringArrayList();
6242 internStringArrayList(usesLibraries);
6243 usesOptionalLibraries = dest.createStringArrayList();
6244 internStringArrayList(usesOptionalLibraries);
6245 usesLibraryFiles = dest.readStringArray();
6247 final int libCount = dest.readInt();
6249 usesStaticLibraries = new ArrayList<>(libCount);
6250 dest.readStringList(usesStaticLibraries);
6251 internStringArrayList(usesStaticLibraries);
6252 usesStaticLibrariesVersions = new int[libCount];
6253 dest.readIntArray(usesStaticLibrariesVersions);
6254 usesStaticLibrariesCertDigests = new String[libCount];
6255 dest.readStringArray(usesStaticLibrariesCertDigests);
6258 preferredActivityFilters = new ArrayList<>();
6259 dest.readParcelableList(preferredActivityFilters, boot);
6260 if (preferredActivityFilters.size() == 0) {
6261 preferredActivityFilters = null;
6264 mOriginalPackages = dest.createStringArrayList();
6265 mRealPackage = dest.readString();
6266 mAdoptPermissions = dest.createStringArrayList();
6267 mAppMetaData = dest.readBundle();
6268 mVersionCode = dest.readInt();
6269 mVersionName = dest.readString();
6270 if (mVersionName != null) {
6271 mVersionName = mVersionName.intern();
6273 mSharedUserId = dest.readString();
6274 if (mSharedUserId != null) {
6275 mSharedUserId = mSharedUserId.intern();
6277 mSharedUserLabel = dest.readInt();
6279 mSignatures = (Signature[]) dest.readParcelableArray(boot, Signature.class);
6280 mCertificates = (Certificate[][]) dest.readSerializable();
6282 mPreferredOrder = dest.readInt();
6284 // long[] packageUsageTimeMillis is not persisted because it isn't information that
6285 // is parsed from the APK.
6287 // Object mExtras is not persisted because it is not information that is read from
6288 // the APK, rather, it is supplied by callers.
6291 configPreferences = new ArrayList<>();
6292 dest.readParcelableList(configPreferences, boot);
6293 if (configPreferences.size() == 0) {
6294 configPreferences = null;
6297 reqFeatures = new ArrayList<>();
6298 dest.readParcelableList(reqFeatures, boot);
6299 if (reqFeatures.size() == 0) {
6303 featureGroups = new ArrayList<>();
6304 dest.readParcelableList(featureGroups, boot);
6305 if (featureGroups.size() == 0) {
6306 featureGroups = null;
6309 installLocation = dest.readInt();
6310 coreApp = (dest.readInt() == 1);
6311 mRequiredForAllUsers = (dest.readInt() == 1);
6312 mRestrictedAccountType = dest.readString();
6313 mRequiredAccountType = dest.readString();
6314 mOverlayTarget = dest.readString();
6315 mOverlayPriority = dest.readInt();
6316 mIsStaticOverlay = (dest.readInt() == 1);
6317 mTrustedOverlay = (dest.readInt() == 1);
6318 mSigningKeys = (ArraySet<PublicKey>) dest.readArraySet(boot);
6319 mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);
6321 mKeySetMapping = readKeySetMapping(dest);
6323 cpuAbiOverride = dest.readString();
6324 use32bitAbi = (dest.readInt() == 1);
6325 restrictUpdateHash = dest.createByteArray();
6326 visibleToInstantApps = dest.readInt() == 1;
6329 private static void internStringArrayList(List<String> list) {
6331 final int N = list.size();
6332 for (int i = 0; i < N; ++i) {
6333 list.set(i, list.get(i).intern());
6339 * Sets the package owner and the the {@code applicationInfo} for every component
6340 * owner by this package.
6342 private void fixupOwner(List<? extends Component<?>> list) {
6344 for (Component<?> c : list) {
6346 if (c instanceof Activity) {
6347 ((Activity) c).info.applicationInfo = this.applicationInfo;
6348 } else if (c instanceof Service) {
6349 ((Service) c).info.applicationInfo = this.applicationInfo;
6350 } else if (c instanceof Provider) {
6351 ((Provider) c).info.applicationInfo = this.applicationInfo;
6358 public void writeToParcel(Parcel dest, int flags) {
6359 dest.writeString(packageName);
6360 dest.writeString(manifestPackageName);
6361 dest.writeStringArray(splitNames);
6362 dest.writeString(volumeUuid);
6363 dest.writeString(codePath);
6364 dest.writeString(baseCodePath);
6365 dest.writeStringArray(splitCodePaths);
6366 dest.writeInt(baseRevisionCode);
6367 dest.writeIntArray(splitRevisionCodes);
6368 dest.writeIntArray(splitFlags);
6369 dest.writeIntArray(splitPrivateFlags);
6370 dest.writeInt(baseHardwareAccelerated ? 1 : 0);
6371 dest.writeParcelable(applicationInfo, flags);
6373 dest.writeParcelableList(permissions, flags);
6374 dest.writeParcelableList(permissionGroups, flags);
6375 dest.writeParcelableList(activities, flags);
6376 dest.writeParcelableList(receivers, flags);
6377 dest.writeParcelableList(providers, flags);
6378 dest.writeParcelableList(services, flags);
6379 dest.writeParcelableList(instrumentation, flags);
6381 dest.writeStringList(requestedPermissions);
6382 dest.writeStringList(protectedBroadcasts);
6383 dest.writeParcelable(parentPackage, flags);
6384 dest.writeParcelableList(childPackages, flags);
6385 dest.writeString(staticSharedLibName);
6386 dest.writeInt(staticSharedLibVersion);
6387 dest.writeStringList(libraryNames);
6388 dest.writeStringList(usesLibraries);
6389 dest.writeStringList(usesOptionalLibraries);
6390 dest.writeStringArray(usesLibraryFiles);
6392 if (ArrayUtils.isEmpty(usesStaticLibraries)) {
6395 dest.writeInt(usesStaticLibraries.size());
6396 dest.writeStringList(usesStaticLibraries);
6397 dest.writeIntArray(usesStaticLibrariesVersions);
6398 dest.writeStringArray(usesStaticLibrariesCertDigests);
6401 dest.writeParcelableList(preferredActivityFilters, flags);
6403 dest.writeStringList(mOriginalPackages);
6404 dest.writeString(mRealPackage);
6405 dest.writeStringList(mAdoptPermissions);
6406 dest.writeBundle(mAppMetaData);
6407 dest.writeInt(mVersionCode);
6408 dest.writeString(mVersionName);
6409 dest.writeString(mSharedUserId);
6410 dest.writeInt(mSharedUserLabel);
6412 dest.writeParcelableArray(mSignatures, flags);
6413 dest.writeSerializable(mCertificates);
6415 dest.writeInt(mPreferredOrder);
6417 // long[] packageUsageTimeMillis is not persisted because it isn't information that
6418 // is parsed from the APK.
6420 // Object mExtras is not persisted because it is not information that is read from
6421 // the APK, rather, it is supplied by callers.
6423 dest.writeParcelableList(configPreferences, flags);
6424 dest.writeParcelableList(reqFeatures, flags);
6425 dest.writeParcelableList(featureGroups, flags);
6427 dest.writeInt(installLocation);
6428 dest.writeInt(coreApp ? 1 : 0);
6429 dest.writeInt(mRequiredForAllUsers ? 1 : 0);
6430 dest.writeString(mRestrictedAccountType);
6431 dest.writeString(mRequiredAccountType);
6432 dest.writeString(mOverlayTarget);
6433 dest.writeInt(mOverlayPriority);
6434 dest.writeInt(mIsStaticOverlay ? 1 : 0);
6435 dest.writeInt(mTrustedOverlay ? 1 : 0);
6436 dest.writeArraySet(mSigningKeys);
6437 dest.writeArraySet(mUpgradeKeySets);
6438 writeKeySetMapping(dest, mKeySetMapping);
6439 dest.writeString(cpuAbiOverride);
6440 dest.writeInt(use32bitAbi ? 1 : 0);
6441 dest.writeByteArray(restrictUpdateHash);
6442 dest.writeInt(visibleToInstantApps ? 1 : 0);
6447 * Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
6449 private static void writeKeySetMapping(
6450 Parcel dest, ArrayMap<String, ArraySet<PublicKey>> keySetMapping) {
6451 if (keySetMapping == null) {
6456 final int N = keySetMapping.size();
6459 for (int i = 0; i < N; i++) {
6460 dest.writeString(keySetMapping.keyAt(i));
6461 ArraySet<PublicKey> keys = keySetMapping.valueAt(i);
6467 final int M = keys.size();
6469 for (int j = 0; j < M; j++) {
6470 dest.writeSerializable(keys.valueAt(j));
6476 * Reads a keyset mapping from the given parcel at the given data position. May return
6477 * {@code null} if the serialized mapping was {@code null}.
6479 private static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(Parcel in) {
6480 final int N = in.readInt();
6485 ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>();
6486 for (int i = 0; i < N; ++i) {
6487 String key = in.readString();
6488 final int M = in.readInt();
6490 keySetMapping.put(key, null);
6494 ArraySet<PublicKey> keys = new ArraySet<>(M);
6495 for (int j = 0; j < M; ++j) {
6496 PublicKey pk = (PublicKey) in.readSerializable();
6500 keySetMapping.put(key, keys);
6503 return keySetMapping;
6506 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Package>() {
6507 public Package createFromParcel(Parcel in) {
6508 return new Package(in);
6511 public Package[] newArray(int size) {
6512 return new Package[size];
6517 public static abstract class Component<II extends IntentInfo> {
6518 public final ArrayList<II> intents;
6519 public final String className;
6521 public Bundle metaData;
6522 public Package owner;
6524 ComponentName componentName;
6525 String componentShortName;
6527 public Component(Package _owner) {
6533 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
6535 intents = new ArrayList<II>(0);
6536 if (parsePackageItemInfo(args.owner, outInfo, args.outError, args.tag, args.sa,
6537 true /*nameRequired*/, args.nameRes, args.labelRes, args.iconRes,
6538 args.roundIconRes, args.logoRes, args.bannerRes)) {
6539 className = outInfo.name;
6545 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
6546 this(args, (PackageItemInfo)outInfo);
6547 if (args.outError[0] != null) {
6551 if (args.processRes != 0) {
6553 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
6554 pname = args.sa.getNonConfigurationString(args.processRes,
6555 Configuration.NATIVE_CONFIG_VERSION);
6557 // Some older apps have been seen to use a resource reference
6558 // here that on older builds was ignored (with a warning). We
6559 // need to continue to do this for them so they don't break.
6560 pname = args.sa.getNonResourceString(args.processRes);
6562 outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
6563 owner.applicationInfo.processName, pname,
6564 args.flags, args.sepProcesses, args.outError);
6567 if (args.descriptionRes != 0) {
6568 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
6571 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
6574 public Component(Component<II> clone) {
6575 owner = clone.owner;
6576 intents = clone.intents;
6577 className = clone.className;
6578 componentName = clone.componentName;
6579 componentShortName = clone.componentShortName;
6582 public ComponentName getComponentName() {
6583 if (componentName != null) {
6584 return componentName;
6586 if (className != null) {
6587 componentName = new ComponentName(owner.applicationInfo.packageName,
6590 return componentName;
6593 protected Component(Parcel in) {
6594 className = in.readString();
6595 metaData = in.readBundle();
6596 intents = createIntentsList(in);
6601 protected void writeToParcel(Parcel dest, int flags) {
6602 dest.writeString(className);
6603 dest.writeBundle(metaData);
6605 writeIntentsList(intents, dest, flags);
6610 * Implementation note: The serialized form for the intent list also contains the name
6611 * of the concrete class that's stored in the list, and assumes that every element of the
6612 * list is of the same type. This is very similar to the original parcelable mechanism.
6613 * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable
6614 * and is public API. It also declares Parcelable related methods as final which means
6615 * we can't extend them. The approach of using composition instead of inheritance leads to
6616 * a large set of cascading changes in the PackageManagerService, which seem undesirable.
6619 * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up
6620 * to make sure their owner fields are consistent. See {@code fixupOwner}.
6622 private static void writeIntentsList(ArrayList<? extends IntentInfo> list, Parcel out,
6629 final int N = list.size();
6632 // Don't bother writing the component name if the list is empty.
6634 IntentInfo info = list.get(0);
6635 out.writeString(info.getClass().getName());
6637 for (int i = 0; i < N;i++) {
6638 list.get(i).writeIntentInfoToParcel(out, flags);
6643 private static <T extends IntentInfo> ArrayList<T> createIntentsList(Parcel in) {
6644 int N = in.readInt();
6650 return new ArrayList<>(0);
6653 String componentName = in.readString();
6654 final ArrayList<T> intentsList;
6656 final Class<T> cls = (Class<T>) Class.forName(componentName);
6657 final Constructor<T> cons = cls.getConstructor(Parcel.class);
6659 intentsList = new ArrayList<>(N);
6660 for (int i = 0; i < N; ++i) {
6661 intentsList.add(cons.newInstance(in));
6663 } catch (ReflectiveOperationException ree) {
6664 throw new AssertionError("Unable to construct intent list for: " + componentName);
6670 public void appendComponentShortName(StringBuilder sb) {
6671 ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className);
6674 public void printComponentShortName(PrintWriter pw) {
6675 ComponentName.printShortString(pw, owner.applicationInfo.packageName, className);
6678 public void setPackageName(String packageName) {
6679 componentName = null;
6680 componentShortName = null;
6684 public final static class Permission extends Component<IntentInfo> implements Parcelable {
6685 public final PermissionInfo info;
6686 public boolean tree;
6687 public PermissionGroup group;
6689 public Permission(Package _owner) {
6691 info = new PermissionInfo();
6694 public Permission(Package _owner, PermissionInfo _info) {
6699 public void setPackageName(String packageName) {
6700 super.setPackageName(packageName);
6701 info.packageName = packageName;
6704 public String toString() {
6705 return "Permission{"
6706 + Integer.toHexString(System.identityHashCode(this))
6707 + " " + info.name + "}";
6711 public int describeContents() {
6716 public void writeToParcel(Parcel dest, int flags) {
6717 super.writeToParcel(dest, flags);
6718 dest.writeParcelable(info, flags);
6719 dest.writeInt(tree ? 1 : 0);
6720 dest.writeParcelable(group, flags);
6723 private Permission(Parcel in) {
6725 final ClassLoader boot = Object.class.getClassLoader();
6726 info = in.readParcelable(boot);
6727 if (info.group != null) {
6728 info.group = info.group.intern();
6731 tree = (in.readInt() == 1);
6732 group = in.readParcelable(boot);
6735 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Permission>() {
6736 public Permission createFromParcel(Parcel in) {
6737 return new Permission(in);
6740 public Permission[] newArray(int size) {
6741 return new Permission[size];
6746 public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable {
6747 public final PermissionGroupInfo info;
6749 public PermissionGroup(Package _owner) {
6751 info = new PermissionGroupInfo();
6754 public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
6759 public void setPackageName(String packageName) {
6760 super.setPackageName(packageName);
6761 info.packageName = packageName;
6764 public String toString() {
6765 return "PermissionGroup{"
6766 + Integer.toHexString(System.identityHashCode(this))
6767 + " " + info.name + "}";
6771 public int describeContents() {
6776 public void writeToParcel(Parcel dest, int flags) {
6777 super.writeToParcel(dest, flags);
6778 dest.writeParcelable(info, flags);
6781 private PermissionGroup(Parcel in) {
6783 info = in.readParcelable(Object.class.getClassLoader());
6786 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<PermissionGroup>() {
6787 public PermissionGroup createFromParcel(Parcel in) {
6788 return new PermissionGroup(in);
6791 public PermissionGroup[] newArray(int size) {
6792 return new PermissionGroup[size];
6797 private static boolean copyNeeded(int flags, Package p,
6798 PackageUserState state, Bundle metaData, int userId) {
6799 if (userId != UserHandle.USER_SYSTEM) {
6800 // We always need to copy for other users, since we need
6801 // to fix up the uid.
6804 if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
6805 boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
6806 if (p.applicationInfo.enabled != enabled) {
6810 boolean suspended = (p.applicationInfo.flags & FLAG_SUSPENDED) != 0;
6811 if (state.suspended != suspended) {
6814 if (!state.installed || state.hidden) {
6817 if (state.stopped) {
6820 if (state.instantApp != p.applicationInfo.isInstantApp()) {
6823 if ((flags & PackageManager.GET_META_DATA) != 0
6824 && (metaData != null || p.mAppMetaData != null)) {
6827 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
6828 && p.usesLibraryFiles != null) {
6831 if (p.staticSharedLibName != null) {
6837 public static ApplicationInfo generateApplicationInfo(Package p, int flags,
6838 PackageUserState state) {
6839 return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
6842 private static void updateApplicationInfo(ApplicationInfo ai, int flags,
6843 PackageUserState state) {
6844 // CompatibilityMode is global state.
6845 if (!sCompatibilityModeEnabled) {
6846 ai.disableCompatibilityMode();
6848 if (state.installed) {
6849 ai.flags |= ApplicationInfo.FLAG_INSTALLED;
6851 ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
6853 if (state.suspended) {
6854 ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
6856 ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
6858 if (state.instantApp) {
6859 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT;
6861 ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT;
6864 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
6866 ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
6868 if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
6870 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
6871 ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
6872 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
6873 || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
6876 ai.enabledSetting = state.enabled;
6877 if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
6878 ai.category = state.categoryHint;
6880 if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
6881 ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
6883 ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
6884 ai.resourceDirs = state.overlayPaths;
6887 public static ApplicationInfo generateApplicationInfo(Package p, int flags,
6888 PackageUserState state, int userId) {
6889 if (p == null) return null;
6890 if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
6893 if (!copyNeeded(flags, p, state, null, userId)
6894 && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0
6895 || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
6896 // In this case it is safe to directly modify the internal ApplicationInfo state:
6897 // - CompatibilityMode is global state, so will be the same for every call.
6898 // - We only come in to here if the app should reported as installed; this is the
6899 // default state, and we will do a copy otherwise.
6900 // - The enable state will always be reported the same for the application across
6901 // calls; the only exception is for the UNTIL_USED mode, and in that case we will
6903 updateApplicationInfo(p.applicationInfo, flags, state);
6904 return p.applicationInfo;
6907 // Make shallow copy so we can store the metadata/libraries safely
6908 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
6909 ai.initForUser(userId);
6910 if ((flags & PackageManager.GET_META_DATA) != 0) {
6911 ai.metaData = p.mAppMetaData;
6913 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
6914 ai.sharedLibraryFiles = p.usesLibraryFiles;
6916 if (state.stopped) {
6917 ai.flags |= ApplicationInfo.FLAG_STOPPED;
6919 ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
6921 updateApplicationInfo(ai, flags, state);
6925 public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags,
6926 PackageUserState state, int userId) {
6927 if (ai == null) return null;
6928 if (!checkUseInstalledOrHidden(flags, state, ai)) {
6931 // This is only used to return the ResolverActivity; we will just always
6933 ai = new ApplicationInfo(ai);
6934 ai.initForUser(userId);
6935 if (state.stopped) {
6936 ai.flags |= ApplicationInfo.FLAG_STOPPED;
6938 ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
6940 updateApplicationInfo(ai, flags, state);
6944 public static final PermissionInfo generatePermissionInfo(
6945 Permission p, int flags) {
6946 if (p == null) return null;
6947 if ((flags&PackageManager.GET_META_DATA) == 0) {
6950 PermissionInfo pi = new PermissionInfo(p.info);
6951 pi.metaData = p.metaData;
6955 public static final PermissionGroupInfo generatePermissionGroupInfo(
6956 PermissionGroup pg, int flags) {
6957 if (pg == null) return null;
6958 if ((flags&PackageManager.GET_META_DATA) == 0) {
6961 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);
6962 pgi.metaData = pg.metaData;
6966 public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
6967 public final ActivityInfo info;
6968 private boolean mHasMaxAspectRatio;
6970 private boolean hasMaxAspectRatio() {
6971 return mHasMaxAspectRatio;
6974 public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
6977 info.applicationInfo = args.owner.applicationInfo;
6980 public void setPackageName(String packageName) {
6981 super.setPackageName(packageName);
6982 info.packageName = packageName;
6986 private void setMaxAspectRatio(float maxAspectRatio) {
6987 if (info.resizeMode == RESIZE_MODE_RESIZEABLE
6988 || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
6989 // Resizeable activities can be put in any aspect ratio.
6993 if (maxAspectRatio < 1.0f && maxAspectRatio != 0) {
6994 // Ignore any value lesser than 1.0.
6998 info.maxAspectRatio = maxAspectRatio;
6999 mHasMaxAspectRatio = true;
7002 public String toString() {
7003 StringBuilder sb = new StringBuilder(128);
7004 sb.append("Activity{");
7005 sb.append(Integer.toHexString(System.identityHashCode(this)));
7007 appendComponentShortName(sb);
7009 return sb.toString();
7013 public int describeContents() {
7018 public void writeToParcel(Parcel dest, int flags) {
7019 super.writeToParcel(dest, flags);
7020 dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
7021 dest.writeBoolean(mHasMaxAspectRatio);
7024 private Activity(Parcel in) {
7026 info = in.readParcelable(Object.class.getClassLoader());
7027 mHasMaxAspectRatio = in.readBoolean();
7029 for (ActivityIntentInfo aii : intents) {
7030 aii.activity = this;
7033 if (info.permission != null) {
7034 info.permission = info.permission.intern();
7038 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Activity>() {
7039 public Activity createFromParcel(Parcel in) {
7040 return new Activity(in);
7043 public Activity[] newArray(int size) {
7044 return new Activity[size];
7049 public static final ActivityInfo generateActivityInfo(Activity a, int flags,
7050 PackageUserState state, int userId) {
7051 if (a == null) return null;
7052 if (!checkUseInstalledOrHidden(flags, state, a.owner.applicationInfo)) {
7055 if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
7056 updateApplicationInfo(a.info.applicationInfo, flags, state);
7059 // Make shallow copies so we can store the metadata safely
7060 ActivityInfo ai = new ActivityInfo(a.info);
7061 ai.metaData = a.metaData;
7062 ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);
7066 public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags,
7067 PackageUserState state, int userId) {
7068 if (ai == null) return null;
7069 if (!checkUseInstalledOrHidden(flags, state, ai.applicationInfo)) {
7072 // This is only used to return the ResolverActivity; we will just always
7074 ai = new ActivityInfo(ai);
7075 ai.applicationInfo = generateApplicationInfo(ai.applicationInfo, flags, state, userId);
7079 public final static class Service extends Component<ServiceIntentInfo> implements Parcelable {
7080 public final ServiceInfo info;
7082 public Service(final ParseComponentArgs args, final ServiceInfo _info) {
7085 info.applicationInfo = args.owner.applicationInfo;
7088 public void setPackageName(String packageName) {
7089 super.setPackageName(packageName);
7090 info.packageName = packageName;
7093 public String toString() {
7094 StringBuilder sb = new StringBuilder(128);
7095 sb.append("Service{");
7096 sb.append(Integer.toHexString(System.identityHashCode(this)));
7098 appendComponentShortName(sb);
7100 return sb.toString();
7104 public int describeContents() {
7109 public void writeToParcel(Parcel dest, int flags) {
7110 super.writeToParcel(dest, flags);
7111 dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
7114 private Service(Parcel in) {
7116 info = in.readParcelable(Object.class.getClassLoader());
7118 for (ServiceIntentInfo aii : intents) {
7122 if (info.permission != null) {
7123 info.permission = info.permission.intern();
7127 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Service>() {
7128 public Service createFromParcel(Parcel in) {
7129 return new Service(in);
7132 public Service[] newArray(int size) {
7133 return new Service[size];
7138 public static final ServiceInfo generateServiceInfo(Service s, int flags,
7139 PackageUserState state, int userId) {
7140 if (s == null) return null;
7141 if (!checkUseInstalledOrHidden(flags, state, s.owner.applicationInfo)) {
7144 if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
7145 updateApplicationInfo(s.info.applicationInfo, flags, state);
7148 // Make shallow copies so we can store the metadata safely
7149 ServiceInfo si = new ServiceInfo(s.info);
7150 si.metaData = s.metaData;
7151 si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId);
7155 public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable {
7156 public final ProviderInfo info;
7157 public boolean syncable;
7159 public Provider(final ParseComponentArgs args, final ProviderInfo _info) {
7162 info.applicationInfo = args.owner.applicationInfo;
7166 public Provider(Provider existingProvider) {
7167 super(existingProvider);
7168 this.info = existingProvider.info;
7169 this.syncable = existingProvider.syncable;
7172 public void setPackageName(String packageName) {
7173 super.setPackageName(packageName);
7174 info.packageName = packageName;
7177 public String toString() {
7178 StringBuilder sb = new StringBuilder(128);
7179 sb.append("Provider{");
7180 sb.append(Integer.toHexString(System.identityHashCode(this)));
7182 appendComponentShortName(sb);
7184 return sb.toString();
7188 public int describeContents() {
7193 public void writeToParcel(Parcel dest, int flags) {
7194 super.writeToParcel(dest, flags);
7195 dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
7196 dest.writeInt((syncable) ? 1 : 0);
7199 private Provider(Parcel in) {
7201 info = in.readParcelable(Object.class.getClassLoader());
7202 syncable = (in.readInt() == 1);
7204 for (ProviderIntentInfo aii : intents) {
7205 aii.provider = this;
7208 if (info.readPermission != null) {
7209 info.readPermission = info.readPermission.intern();
7212 if (info.writePermission != null) {
7213 info.writePermission = info.writePermission.intern();
7216 if (info.authority != null) {
7217 info.authority = info.authority.intern();
7221 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Provider>() {
7222 public Provider createFromParcel(Parcel in) {
7223 return new Provider(in);
7226 public Provider[] newArray(int size) {
7227 return new Provider[size];
7232 public static final ProviderInfo generateProviderInfo(Provider p, int flags,
7233 PackageUserState state, int userId) {
7234 if (p == null) return null;
7235 if (!checkUseInstalledOrHidden(flags, state, p.owner.applicationInfo)) {
7238 if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
7239 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
7240 || p.info.uriPermissionPatterns == null)) {
7241 updateApplicationInfo(p.info.applicationInfo, flags, state);
7244 // Make shallow copies so we can store the metadata safely
7245 ProviderInfo pi = new ProviderInfo(p.info);
7246 pi.metaData = p.metaData;
7247 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
7248 pi.uriPermissionPatterns = null;
7250 pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId);
7254 public final static class Instrumentation extends Component<IntentInfo> implements
7256 public final InstrumentationInfo info;
7258 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
7263 public void setPackageName(String packageName) {
7264 super.setPackageName(packageName);
7265 info.packageName = packageName;
7268 public String toString() {
7269 StringBuilder sb = new StringBuilder(128);
7270 sb.append("Instrumentation{");
7271 sb.append(Integer.toHexString(System.identityHashCode(this)));
7273 appendComponentShortName(sb);
7275 return sb.toString();
7279 public int describeContents() {
7284 public void writeToParcel(Parcel dest, int flags) {
7285 super.writeToParcel(dest, flags);
7286 dest.writeParcelable(info, flags);
7289 private Instrumentation(Parcel in) {
7291 info = in.readParcelable(Object.class.getClassLoader());
7293 if (info.targetPackage != null) {
7294 info.targetPackage = info.targetPackage.intern();
7297 if (info.targetProcesses != null) {
7298 info.targetProcesses = info.targetProcesses.intern();
7302 public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Instrumentation>() {
7303 public Instrumentation createFromParcel(Parcel in) {
7304 return new Instrumentation(in);
7307 public Instrumentation[] newArray(int size) {
7308 return new Instrumentation[size];
7313 public static final InstrumentationInfo generateInstrumentationInfo(
7314 Instrumentation i, int flags) {
7315 if (i == null) return null;
7316 if ((flags&PackageManager.GET_META_DATA) == 0) {
7319 InstrumentationInfo ii = new InstrumentationInfo(i.info);
7320 ii.metaData = i.metaData;
7324 public static abstract class IntentInfo extends IntentFilter {
7325 public boolean hasDefault;
7326 public int labelRes;
7327 public CharSequence nonLocalizedLabel;
7331 public int preferred;
7333 protected IntentInfo() {
7336 protected IntentInfo(Parcel dest) {
7338 hasDefault = (dest.readInt() == 1);
7339 labelRes = dest.readInt();
7340 nonLocalizedLabel = dest.readCharSequence();
7341 icon = dest.readInt();
7342 logo = dest.readInt();
7343 banner = dest.readInt();
7344 preferred = dest.readInt();
7348 public void writeIntentInfoToParcel(Parcel dest, int flags) {
7349 super.writeToParcel(dest, flags);
7350 dest.writeInt(hasDefault ? 1 : 0);
7351 dest.writeInt(labelRes);
7352 dest.writeCharSequence(nonLocalizedLabel);
7353 dest.writeInt(icon);
7354 dest.writeInt(logo);
7355 dest.writeInt(banner);
7356 dest.writeInt(preferred);
7360 public final static class ActivityIntentInfo extends IntentInfo {
7361 public Activity activity;
7363 public ActivityIntentInfo(Activity _activity) {
7364 activity = _activity;
7367 public String toString() {
7368 StringBuilder sb = new StringBuilder(128);
7369 sb.append("ActivityIntentInfo{");
7370 sb.append(Integer.toHexString(System.identityHashCode(this)));
7372 activity.appendComponentShortName(sb);
7374 return sb.toString();
7377 public ActivityIntentInfo(Parcel in) {
7382 public final static class ServiceIntentInfo extends IntentInfo {
7383 public Service service;
7385 public ServiceIntentInfo(Service _service) {
7389 public String toString() {
7390 StringBuilder sb = new StringBuilder(128);
7391 sb.append("ServiceIntentInfo{");
7392 sb.append(Integer.toHexString(System.identityHashCode(this)));
7394 service.appendComponentShortName(sb);
7396 return sb.toString();
7399 public ServiceIntentInfo(Parcel in) {
7404 public static final class ProviderIntentInfo extends IntentInfo {
7405 public Provider provider;
7407 public ProviderIntentInfo(Provider provider) {
7408 this.provider = provider;
7411 public String toString() {
7412 StringBuilder sb = new StringBuilder(128);
7413 sb.append("ProviderIntentInfo{");
7414 sb.append(Integer.toHexString(System.identityHashCode(this)));
7416 provider.appendComponentShortName(sb);
7418 return sb.toString();
7421 public ProviderIntentInfo(Parcel in) {
7429 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
7430 sCompatibilityModeEnabled = compatibilityModeEnabled;
7433 private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>();
7435 public static long readFullyIgnoringContents(InputStream in) throws IOException {
7436 byte[] buffer = sBuffer.getAndSet(null);
7437 if (buffer == null) {
7438 buffer = new byte[4096];
7443 while ((n = in.read(buffer, 0, buffer.length)) != -1) {
7447 sBuffer.set(buffer);
7451 public static void closeQuietly(StrictJarFile jarFile) {
7452 if (jarFile != null) {
7455 } catch (Exception ignored) {
7460 public static class PackageParserException extends Exception {
7461 public final int error;
7463 public PackageParserException(int error, String detailMessage) {
7464 super(detailMessage);
7468 public PackageParserException(int error, String detailMessage, Throwable throwable) {
7469 super(detailMessage, throwable);