Home | History | Annotate | Download | only in pm
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.content.pm;
     18 
     19 import static android.content.pm.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_RESIZEABLE;
     31 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
     32 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
     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_UNSPECIFIED;
     44 
     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.PackageParserCacheHelper.ReadHelper;
     54 import android.content.pm.PackageParserCacheHelper.WriteHelper;
     55 import android.content.pm.split.DefaultSplitAssetLoader;
     56 import android.content.pm.split.SplitAssetDependencyLoader;
     57 import android.content.pm.split.SplitAssetLoader;
     58 import android.content.res.AssetManager;
     59 import android.content.res.Configuration;
     60 import android.content.res.Resources;
     61 import android.content.res.TypedArray;
     62 import android.content.res.XmlResourceParser;
     63 import android.os.Build;
     64 import android.os.Bundle;
     65 import android.os.FileUtils;
     66 import android.os.Parcel;
     67 import android.os.Parcelable;
     68 import android.os.PatternMatcher;
     69 import android.os.SystemClock;
     70 import android.os.SystemProperties;
     71 import android.os.Trace;
     72 import android.os.UserHandle;
     73 import android.os.storage.StorageManager;
     74 import android.system.ErrnoException;
     75 import android.system.OsConstants;
     76 import android.system.StructStat;
     77 import android.text.TextUtils;
     78 import android.util.ArrayMap;
     79 import android.util.ArraySet;
     80 import android.util.AttributeSet;
     81 import android.util.Base64;
     82 import android.util.DisplayMetrics;
     83 import android.util.Log;
     84 import android.util.Pair;
     85 import android.util.Slog;
     86 import android.util.SparseArray;
     87 import android.util.TypedValue;
     88 import android.util.apk.ApkSignatureSchemeV2Verifier;
     89 import android.util.jar.StrictJarFile;
     90 import android.view.Gravity;
     91 
     92 import com.android.internal.R;
     93 import com.android.internal.annotations.VisibleForTesting;
     94 import com.android.internal.os.ClassLoaderFactory;
     95 import com.android.internal.util.ArrayUtils;
     96 import com.android.internal.util.XmlUtils;
     97 
     98 import libcore.io.IoUtils;
     99 
    100 import libcore.util.EmptyArray;
    101 import org.xmlpull.v1.XmlPullParser;
    102 import org.xmlpull.v1.XmlPullParserException;
    103 
    104 import java.io.File;
    105 import java.io.FileOutputStream;
    106 import java.io.IOException;
    107 import java.io.InputStream;
    108 import java.io.PrintWriter;
    109 import java.lang.reflect.Constructor;
    110 import java.security.GeneralSecurityException;
    111 import java.security.KeyFactory;
    112 import java.security.NoSuchAlgorithmException;
    113 import java.security.PublicKey;
    114 import java.security.cert.Certificate;
    115 import java.security.cert.CertificateEncodingException;
    116 import java.security.spec.EncodedKeySpec;
    117 import java.security.spec.InvalidKeySpecException;
    118 import java.security.spec.X509EncodedKeySpec;
    119 import java.util.ArrayList;
    120 import java.util.Arrays;
    121 import java.util.Collections;
    122 import java.util.Comparator;
    123 import java.util.Iterator;
    124 import java.util.List;
    125 import java.util.Set;
    126 import java.util.UUID;
    127 import java.util.concurrent.atomic.AtomicInteger;
    128 import java.util.concurrent.atomic.AtomicReference;
    129 import java.util.zip.ZipEntry;
    130 
    131 /**
    132  * Parser for package files (APKs) on disk. This supports apps packaged either
    133  * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple
    134  * APKs in a single directory.
    135  * <p>
    136  * Apps packaged as multiple APKs always consist of a single "base" APK (with a
    137  * {@code null} split name) and zero or more "split" APKs (with unique split
    138  * names). Any subset of those split APKs are a valid install, as long as the
    139  * following constraints are met:
    140  * <ul>
    141  * <li>All APKs must have the exact same package name, version code, and signing
    142  * certificates.
    143  * <li>All APKs must have unique split names.
    144  * <li>All installations must contain a single base APK.
    145  * </ul>
    146  *
    147  * @hide
    148  */
    149 public class PackageParser {
    150     private static final boolean DEBUG_JAR = false;
    151     private static final boolean DEBUG_PARSER = false;
    152     private static final boolean DEBUG_BACKUP = false;
    153     private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
    154     private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
    155 
    156     private static final String PROPERTY_CHILD_PACKAGES_ENABLED =
    157             "persist.sys.child_packages_enabled";
    158 
    159     private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
    160             SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
    161 
    162     private static final int MAX_PACKAGES_PER_APK = 5;
    163 
    164     public static final int APK_SIGNING_UNKNOWN = 0;
    165     public static final int APK_SIGNING_V1 = 1;
    166     public static final int APK_SIGNING_V2 = 2;
    167 
    168     private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
    169 
    170     // TODO: switch outError users to PackageParserException
    171     // TODO: refactor "codePath" to "apkPath"
    172 
    173     /** File name in an APK for the Android manifest. */
    174     private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
    175 
    176     /** Path prefix for apps on expanded storage */
    177     private static final String MNT_EXPAND = "/mnt/expand/";
    178 
    179     private static final String TAG_MANIFEST = "manifest";
    180     private static final String TAG_APPLICATION = "application";
    181     private static final String TAG_PACKAGE_VERIFIER = "package-verifier";
    182     private static final String TAG_OVERLAY = "overlay";
    183     private static final String TAG_KEY_SETS = "key-sets";
    184     private static final String TAG_PERMISSION_GROUP = "permission-group";
    185     private static final String TAG_PERMISSION = "permission";
    186     private static final String TAG_PERMISSION_TREE = "permission-tree";
    187     private static final String TAG_USES_PERMISSION = "uses-permission";
    188     private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
    189     private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";
    190     private static final String TAG_USES_CONFIGURATION = "uses-configuration";
    191     private static final String TAG_USES_FEATURE = "uses-feature";
    192     private static final String TAG_FEATURE_GROUP = "feature-group";
    193     private static final String TAG_USES_SDK = "uses-sdk";
    194     private static final String TAG_SUPPORT_SCREENS = "supports-screens";
    195     private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";
    196     private static final String TAG_INSTRUMENTATION = "instrumentation";
    197     private static final String TAG_ORIGINAL_PACKAGE = "original-package";
    198     private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
    199     private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
    200     private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";
    201     private static final String TAG_SUPPORTS_INPUT = "supports-input";
    202     private static final String TAG_EAT_COMMENT = "eat-comment";
    203     private static final String TAG_PACKAGE = "package";
    204     private static final String TAG_RESTRICT_UPDATE = "restrict-update";
    205     private static final String TAG_USES_SPLIT = "uses-split";
    206 
    207     // [b/36551762] STOPSHIP remove the ability to expose components via meta-data
    208     // Temporary workaround; allow meta-data to expose components to instant apps
    209     private static final String META_DATA_INSTANT_APPS = "instantapps.clients.allowed";
    210 
    211     private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
    212 
    213     /**
    214      * Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
    215      * @hide
    216      */
    217     private static final int RECREATE_ON_CONFIG_CHANGES_MASK =
    218             ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC;
    219 
    220     // These are the tags supported by child packages
    221     private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
    222     static {
    223         CHILD_PACKAGE_TAGS.add(TAG_APPLICATION);
    224         CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION);
    225         CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M);
    226         CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23);
    227         CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION);
    228         CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE);
    229         CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP);
    230         CHILD_PACKAGE_TAGS.add(TAG_USES_SDK);
    231         CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS);
    232         CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION);
    233         CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE);
    234         CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS);
    235         CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT);
    236         CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
    237     }
    238 
    239     private static final boolean LOG_UNSAFE_BROADCASTS = false;
    240 
    241     /**
    242      * Total number of packages that were read from the cache.  We use it only for logging.
    243      */
    244     public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger();
    245 
    246     // Set of broadcast actions that are safe for manifest receivers
    247     private static final Set<String> SAFE_BROADCASTS = new ArraySet<>();
    248     static {
    249         SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED);
    250     }
    251 
    252     /** @hide */
    253     public static class NewPermissionInfo {
    254         public final String name;
    255         public final int sdkVersion;
    256         public final int fileVersion;
    257 
    258         public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {
    259             this.name = name;
    260             this.sdkVersion = sdkVersion;
    261             this.fileVersion = fileVersion;
    262         }
    263     }
    264 
    265     /** @hide */
    266     public static class SplitPermissionInfo {
    267         public final String rootPerm;
    268         public final String[] newPerms;
    269         public final int targetSdk;
    270 
    271         public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
    272             this.rootPerm = rootPerm;
    273             this.newPerms = newPerms;
    274             this.targetSdk = targetSdk;
    275         }
    276     }
    277 
    278     /**
    279      * List of new permissions that have been added since 1.0.
    280      * NOTE: These must be declared in SDK version order, with permissions
    281      * added to older SDKs appearing before those added to newer SDKs.
    282      * If sdkVersion is 0, then this is not a permission that we want to
    283      * automatically add to older apps, but we do want to allow it to be
    284      * granted during a platform update.
    285      * @hide
    286      */
    287     public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] =
    288         new PackageParser.NewPermissionInfo[] {
    289             new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
    290                     android.os.Build.VERSION_CODES.DONUT, 0),
    291             new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE,
    292                     android.os.Build.VERSION_CODES.DONUT, 0)
    293     };
    294 
    295     /**
    296      * List of permissions that have been split into more granular or dependent
    297      * permissions.
    298      * @hide
    299      */
    300     public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] =
    301         new PackageParser.SplitPermissionInfo[] {
    302             // READ_EXTERNAL_STORAGE is always required when an app requests
    303             // WRITE_EXTERNAL_STORAGE, because we can't have an app that has
    304             // write access without read access.  The hack here with the target
    305             // target SDK version ensures that this grant is always done.
    306             new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
    307                     new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE },
    308                     android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1),
    309             new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
    310                     new String[] { android.Manifest.permission.READ_CALL_LOG },
    311                     android.os.Build.VERSION_CODES.JELLY_BEAN),
    312             new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
    313                     new String[] { android.Manifest.permission.WRITE_CALL_LOG },
    314                     android.os.Build.VERSION_CODES.JELLY_BEAN)
    315     };
    316 
    317     /**
    318      * @deprecated callers should move to explicitly passing around source path.
    319      */
    320     @Deprecated
    321     private String mArchiveSourcePath;
    322 
    323     private String[] mSeparateProcesses;
    324     private boolean mOnlyCoreApps;
    325     private DisplayMetrics mMetrics;
    326     private Callback mCallback;
    327     private File mCacheDir;
    328 
    329     private static final int SDK_VERSION = Build.VERSION.SDK_INT;
    330     private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
    331 
    332     private int mParseError = PackageManager.INSTALL_SUCCEEDED;
    333 
    334     private static boolean sCompatibilityModeEnabled = true;
    335     private static final int PARSE_DEFAULT_INSTALL_LOCATION =
    336             PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
    337     private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
    338 
    339     static class ParsePackageItemArgs {
    340         final Package owner;
    341         final String[] outError;
    342         final int nameRes;
    343         final int labelRes;
    344         final int iconRes;
    345         final int roundIconRes;
    346         final int logoRes;
    347         final int bannerRes;
    348 
    349         String tag;
    350         TypedArray sa;
    351 
    352         ParsePackageItemArgs(Package _owner, String[] _outError,
    353                 int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
    354                 int _bannerRes) {
    355             owner = _owner;
    356             outError = _outError;
    357             nameRes = _nameRes;
    358             labelRes = _labelRes;
    359             iconRes = _iconRes;
    360             logoRes = _logoRes;
    361             bannerRes = _bannerRes;
    362             roundIconRes = _roundIconRes;
    363         }
    364     }
    365 
    366     /** @hide */
    367     @VisibleForTesting
    368     public static class ParseComponentArgs extends ParsePackageItemArgs {
    369         final String[] sepProcesses;
    370         final int processRes;
    371         final int descriptionRes;
    372         final int enabledRes;
    373         int flags;
    374 
    375         public ParseComponentArgs(Package _owner, String[] _outError,
    376                 int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
    377                 int _bannerRes,
    378                 String[] _sepProcesses, int _processRes,
    379                 int _descriptionRes, int _enabledRes) {
    380             super(_owner, _outError, _nameRes, _labelRes, _iconRes, _roundIconRes, _logoRes,
    381                     _bannerRes);
    382             sepProcesses = _sepProcesses;
    383             processRes = _processRes;
    384             descriptionRes = _descriptionRes;
    385             enabledRes = _enabledRes;
    386         }
    387     }
    388 
    389     /**
    390      * Lightweight parsed details about a single package.
    391      */
    392     public static class PackageLite {
    393         public final String packageName;
    394         public final int versionCode;
    395         public final int installLocation;
    396         public final VerifierInfo[] verifiers;
    397 
    398         /** Names of any split APKs, ordered by parsed splitName */
    399         public final String[] splitNames;
    400 
    401         /** Names of any split APKs that are features. Ordered by splitName */
    402         public final boolean[] isFeatureSplits;
    403 
    404         /** Dependencies of any split APKs, ordered by parsed splitName */
    405         public final String[] usesSplitNames;
    406         public final String[] configForSplit;
    407 
    408         /**
    409          * Path where this package was found on disk. For monolithic packages
    410          * this is path to single base APK file; for cluster packages this is
    411          * path to the cluster directory.
    412          */
    413         public final String codePath;
    414 
    415         /** Path of base APK */
    416         public final String baseCodePath;
    417         /** Paths of any split APKs, ordered by parsed splitName */
    418         public final String[] splitCodePaths;
    419 
    420         /** Revision code of base APK */
    421         public final int baseRevisionCode;
    422         /** Revision codes of any split APKs, ordered by parsed splitName */
    423         public final int[] splitRevisionCodes;
    424 
    425         public final boolean coreApp;
    426         public final boolean debuggable;
    427         public final boolean multiArch;
    428         public final boolean use32bitAbi;
    429         public final boolean extractNativeLibs;
    430         public final boolean isolatedSplits;
    431 
    432         public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
    433                 boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit,
    434                 String[] splitCodePaths, int[] splitRevisionCodes) {
    435             this.packageName = baseApk.packageName;
    436             this.versionCode = baseApk.versionCode;
    437             this.installLocation = baseApk.installLocation;
    438             this.verifiers = baseApk.verifiers;
    439             this.splitNames = splitNames;
    440             this.isFeatureSplits = isFeatureSplits;
    441             this.usesSplitNames = usesSplitNames;
    442             this.configForSplit = configForSplit;
    443             this.codePath = codePath;
    444             this.baseCodePath = baseApk.codePath;
    445             this.splitCodePaths = splitCodePaths;
    446             this.baseRevisionCode = baseApk.revisionCode;
    447             this.splitRevisionCodes = splitRevisionCodes;
    448             this.coreApp = baseApk.coreApp;
    449             this.debuggable = baseApk.debuggable;
    450             this.multiArch = baseApk.multiArch;
    451             this.use32bitAbi = baseApk.use32bitAbi;
    452             this.extractNativeLibs = baseApk.extractNativeLibs;
    453             this.isolatedSplits = baseApk.isolatedSplits;
    454         }
    455 
    456         public List<String> getAllCodePaths() {
    457             ArrayList<String> paths = new ArrayList<>();
    458             paths.add(baseCodePath);
    459             if (!ArrayUtils.isEmpty(splitCodePaths)) {
    460                 Collections.addAll(paths, splitCodePaths);
    461             }
    462             return paths;
    463         }
    464     }
    465 
    466     /**
    467      * Lightweight parsed details about a single APK file.
    468      */
    469     public static class ApkLite {
    470         public final String codePath;
    471         public final String packageName;
    472         public final String splitName;
    473         public boolean isFeatureSplit;
    474         public final String configForSplit;
    475         public final String usesSplitName;
    476         public final int versionCode;
    477         public final int revisionCode;
    478         public final int installLocation;
    479         public final VerifierInfo[] verifiers;
    480         public final Signature[] signatures;
    481         public final Certificate[][] certificates;
    482         public final boolean coreApp;
    483         public final boolean debuggable;
    484         public final boolean multiArch;
    485         public final boolean use32bitAbi;
    486         public final boolean extractNativeLibs;
    487         public final boolean isolatedSplits;
    488 
    489         public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
    490                 String configForSplit, String usesSplitName, int versionCode, int revisionCode,
    491                 int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
    492                 Certificate[][] certificates, boolean coreApp, boolean debuggable,
    493                 boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs,
    494                 boolean isolatedSplits) {
    495             this.codePath = codePath;
    496             this.packageName = packageName;
    497             this.splitName = splitName;
    498             this.isFeatureSplit = isFeatureSplit;
    499             this.configForSplit = configForSplit;
    500             this.usesSplitName = usesSplitName;
    501             this.versionCode = versionCode;
    502             this.revisionCode = revisionCode;
    503             this.installLocation = installLocation;
    504             this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
    505             this.signatures = signatures;
    506             this.certificates = certificates;
    507             this.coreApp = coreApp;
    508             this.debuggable = debuggable;
    509             this.multiArch = multiArch;
    510             this.use32bitAbi = use32bitAbi;
    511             this.extractNativeLibs = extractNativeLibs;
    512             this.isolatedSplits = isolatedSplits;
    513         }
    514     }
    515 
    516     /**
    517      * Cached parse state for new components.
    518      *
    519      * Allows reuse of the same parse argument records to avoid GC pressure.  Lifetime is carefully
    520      * scoped to the parsing of a single application element.
    521      */
    522     private static class CachedComponentArgs {
    523         ParseComponentArgs mActivityArgs;
    524         ParseComponentArgs mActivityAliasArgs;
    525         ParseComponentArgs mServiceArgs;
    526         ParseComponentArgs mProviderArgs;
    527     }
    528 
    529     /**
    530      * Cached state for parsing instrumentation to avoid GC pressure.
    531      *
    532      * Must be manually reset to null for each new manifest.
    533      */
    534     private ParsePackageItemArgs mParseInstrumentationArgs;
    535 
    536     /** If set to true, we will only allow package files that exactly match
    537      *  the DTD.  Otherwise, we try to get as much from the package as we
    538      *  can without failing.  This should normally be set to false, to
    539      *  support extensions to the DTD in future versions. */
    540     private static final boolean RIGID_PARSER = false;
    541 
    542     private static final String TAG = "PackageParser";
    543 
    544     public PackageParser() {
    545         mMetrics = new DisplayMetrics();
    546         mMetrics.setToDefaults();
    547     }
    548 
    549     public void setSeparateProcesses(String[] procs) {
    550         mSeparateProcesses = procs;
    551     }
    552 
    553     /**
    554      * Flag indicating this parser should only consider apps with
    555      * {@code coreApp} manifest attribute to be valid apps. This is useful when
    556      * creating a minimalist boot environment.
    557      */
    558     public void setOnlyCoreApps(boolean onlyCoreApps) {
    559         mOnlyCoreApps = onlyCoreApps;
    560     }
    561 
    562     public void setDisplayMetrics(DisplayMetrics metrics) {
    563         mMetrics = metrics;
    564     }
    565 
    566     /**
    567      * Sets the cache directory for this package parser.
    568      */
    569     public void setCacheDir(File cacheDir) {
    570         mCacheDir = cacheDir;
    571     }
    572 
    573     /**
    574      * Callback interface for retrieving information that may be needed while parsing
    575      * a package.
    576      */
    577     public interface Callback {
    578         boolean hasFeature(String feature);
    579         String[] getOverlayPaths(String targetPackageName, String targetPath);
    580         String[] getOverlayApks(String targetPackageName);
    581     }
    582 
    583     /**
    584      * Standard implementation of {@link Callback} on top of the public {@link PackageManager}
    585      * class.
    586      */
    587     public static final class CallbackImpl implements Callback {
    588         private final PackageManager mPm;
    589 
    590         public CallbackImpl(PackageManager pm) {
    591             mPm = pm;
    592         }
    593 
    594         @Override public boolean hasFeature(String feature) {
    595             return mPm.hasSystemFeature(feature);
    596         }
    597 
    598         @Override public String[] getOverlayPaths(String targetPackageName, String targetPath) {
    599             return null;
    600         }
    601 
    602         @Override public String[] getOverlayApks(String targetPackageName) {
    603             return null;
    604         }
    605     }
    606 
    607     /**
    608      * Set the {@link Callback} that can be used while parsing.
    609      */
    610     public void setCallback(Callback cb) {
    611         mCallback = cb;
    612     }
    613 
    614     public static final boolean isApkFile(File file) {
    615         return isApkPath(file.getName());
    616     }
    617 
    618     public static boolean isApkPath(String path) {
    619         return path.endsWith(".apk");
    620     }
    621 
    622     /**
    623      * Generate and return the {@link PackageInfo} for a parsed package.
    624      *
    625      * @param p the parsed package.
    626      * @param flags indicating which optional information is included.
    627      */
    628     public static PackageInfo generatePackageInfo(PackageParser.Package p,
    629             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
    630             Set<String> grantedPermissions, PackageUserState state) {
    631 
    632         return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
    633                 grantedPermissions, state, UserHandle.getCallingUserId());
    634     }
    635 
    636     /**
    637      * Returns true if the package is installed and not hidden, or if the caller
    638      * explicitly wanted all uninstalled and hidden packages as well.
    639      * @param appInfo The applicationInfo of the app being checked.
    640      */
    641     private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state,
    642             ApplicationInfo appInfo) {
    643         // If available for the target user, or trying to match uninstalled packages and it's
    644         // a system app.
    645         return state.isAvailable(flags)
    646                 || (appInfo != null && appInfo.isSystemApp()
    647                         && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0);
    648     }
    649 
    650     public static boolean isAvailable(PackageUserState state) {
    651         return checkUseInstalledOrHidden(0, state, null);
    652     }
    653 
    654     public static PackageInfo generatePackageInfo(PackageParser.Package p,
    655             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
    656             Set<String> grantedPermissions, PackageUserState state, int userId) {
    657         if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
    658             return null;
    659         }
    660         PackageInfo pi = new PackageInfo();
    661         pi.packageName = p.packageName;
    662         pi.splitNames = p.splitNames;
    663         pi.versionCode = p.mVersionCode;
    664         pi.baseRevisionCode = p.baseRevisionCode;
    665         pi.splitRevisionCodes = p.splitRevisionCodes;
    666         pi.versionName = p.mVersionName;
    667         pi.sharedUserId = p.mSharedUserId;
    668         pi.sharedUserLabel = p.mSharedUserLabel;
    669         pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
    670         pi.installLocation = p.installLocation;
    671         pi.isStub = p.isStub;
    672         pi.coreApp = p.coreApp;
    673         if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0
    674                 || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
    675             pi.requiredForAllUsers = p.mRequiredForAllUsers;
    676         }
    677         pi.restrictedAccountType = p.mRestrictedAccountType;
    678         pi.requiredAccountType = p.mRequiredAccountType;
    679         pi.overlayTarget = p.mOverlayTarget;
    680         pi.overlayPriority = p.mOverlayPriority;
    681         pi.isStaticOverlay = p.mIsStaticOverlay;
    682         pi.firstInstallTime = firstInstallTime;
    683         pi.lastUpdateTime = lastUpdateTime;
    684         if ((flags&PackageManager.GET_GIDS) != 0) {
    685             pi.gids = gids;
    686         }
    687         if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) {
    688             int N = p.configPreferences != null ? p.configPreferences.size() : 0;
    689             if (N > 0) {
    690                 pi.configPreferences = new ConfigurationInfo[N];
    691                 p.configPreferences.toArray(pi.configPreferences);
    692             }
    693             N = p.reqFeatures != null ? p.reqFeatures.size() : 0;
    694             if (N > 0) {
    695                 pi.reqFeatures = new FeatureInfo[N];
    696                 p.reqFeatures.toArray(pi.reqFeatures);
    697             }
    698             N = p.featureGroups != null ? p.featureGroups.size() : 0;
    699             if (N > 0) {
    700                 pi.featureGroups = new FeatureGroupInfo[N];
    701                 p.featureGroups.toArray(pi.featureGroups);
    702             }
    703         }
    704         if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
    705             final int N = p.activities.size();
    706             if (N > 0) {
    707                 int num = 0;
    708                 final ActivityInfo[] res = new ActivityInfo[N];
    709                 for (int i = 0; i < N; i++) {
    710                     final Activity a = p.activities.get(i);
    711                     if (state.isMatch(a.info, flags)) {
    712                         res[num++] = generateActivityInfo(a, flags, state, userId);
    713                     }
    714                 }
    715                 pi.activities = ArrayUtils.trimToSize(res, num);
    716             }
    717         }
    718         if ((flags & PackageManager.GET_RECEIVERS) != 0) {
    719             final int N = p.receivers.size();
    720             if (N > 0) {
    721                 int num = 0;
    722                 final ActivityInfo[] res = new ActivityInfo[N];
    723                 for (int i = 0; i < N; i++) {
    724                     final Activity a = p.receivers.get(i);
    725                     if (state.isMatch(a.info, flags)) {
    726                         res[num++] = generateActivityInfo(a, flags, state, userId);
    727                     }
    728                 }
    729                 pi.receivers = ArrayUtils.trimToSize(res, num);
    730             }
    731         }
    732         if ((flags & PackageManager.GET_SERVICES) != 0) {
    733             final int N = p.services.size();
    734             if (N > 0) {
    735                 int num = 0;
    736                 final ServiceInfo[] res = new ServiceInfo[N];
    737                 for (int i = 0; i < N; i++) {
    738                     final Service s = p.services.get(i);
    739                     if (state.isMatch(s.info, flags)) {
    740                         res[num++] = generateServiceInfo(s, flags, state, userId);
    741                     }
    742                 }
    743                 pi.services = ArrayUtils.trimToSize(res, num);
    744             }
    745         }
    746         if ((flags & PackageManager.GET_PROVIDERS) != 0) {
    747             final int N = p.providers.size();
    748             if (N > 0) {
    749                 int num = 0;
    750                 final ProviderInfo[] res = new ProviderInfo[N];
    751                 for (int i = 0; i < N; i++) {
    752                     final Provider pr = p.providers.get(i);
    753                     if (state.isMatch(pr.info, flags)) {
    754                         res[num++] = generateProviderInfo(pr, flags, state, userId);
    755                     }
    756                 }
    757                 pi.providers = ArrayUtils.trimToSize(res, num);
    758             }
    759         }
    760         if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) {
    761             int N = p.instrumentation.size();
    762             if (N > 0) {
    763                 pi.instrumentation = new InstrumentationInfo[N];
    764                 for (int i=0; i<N; i++) {
    765                     pi.instrumentation[i] = generateInstrumentationInfo(
    766                             p.instrumentation.get(i), flags);
    767                 }
    768             }
    769         }
    770         if ((flags&PackageManager.GET_PERMISSIONS) != 0) {
    771             int N = p.permissions.size();
    772             if (N > 0) {
    773                 pi.permissions = new PermissionInfo[N];
    774                 for (int i=0; i<N; i++) {
    775                     pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags);
    776                 }
    777             }
    778             N = p.requestedPermissions.size();
    779             if (N > 0) {
    780                 pi.requestedPermissions = new String[N];
    781                 pi.requestedPermissionsFlags = new int[N];
    782                 for (int i=0; i<N; i++) {
    783                     final String perm = p.requestedPermissions.get(i);
    784                     pi.requestedPermissions[i] = perm;
    785                     // The notion of required permissions is deprecated but for compatibility.
    786                     pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
    787                     if (grantedPermissions != null && grantedPermissions.contains(perm)) {
    788                         pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
    789                     }
    790                 }
    791             }
    792         }
    793         if ((flags&PackageManager.GET_SIGNATURES) != 0) {
    794            int N = (p.mSignatures != null) ? p.mSignatures.length : 0;
    795            if (N > 0) {
    796                 pi.signatures = new Signature[N];
    797                 System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);
    798             }
    799         }
    800         return pi;
    801     }
    802 
    803     private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry)
    804             throws PackageParserException {
    805         InputStream is = null;
    806         try {
    807             // We must read the stream for the JarEntry to retrieve
    808             // its certificates.
    809             is = jarFile.getInputStream(entry);
    810             readFullyIgnoringContents(is);
    811             return jarFile.getCertificateChains(entry);
    812         } catch (IOException | RuntimeException e) {
    813             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
    814                     "Failed reading " + entry.getName() + " in " + jarFile, e);
    815         } finally {
    816             IoUtils.closeQuietly(is);
    817         }
    818     }
    819 
    820     public final static int PARSE_IS_SYSTEM = 1<<0;
    821     public final static int PARSE_CHATTY = 1<<1;
    822     public final static int PARSE_MUST_BE_APK = 1<<2;
    823     public final static int PARSE_IGNORE_PROCESSES = 1<<3;
    824     public final static int PARSE_FORWARD_LOCK = 1<<4;
    825     public final static int PARSE_EXTERNAL_STORAGE = 1<<5;
    826     public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
    827     public final static int PARSE_IS_PRIVILEGED = 1<<7;
    828     public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
    829     public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
    830     public final static int PARSE_ENFORCE_CODE = 1<<10;
    831     /** @deprecated remove when fixing b/34761192 */
    832     @Deprecated
    833     public final static int PARSE_IS_EPHEMERAL = 1<<11;
    834     public final static int PARSE_FORCE_SDK = 1<<12;
    835 
    836     private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
    837 
    838     /**
    839      * Used to sort a set of APKs based on their split names, always placing the
    840      * base APK (with {@code null} split name) first.
    841      */
    842     private static class SplitNameComparator implements Comparator<String> {
    843         @Override
    844         public int compare(String lhs, String rhs) {
    845             if (lhs == null) {
    846                 return -1;
    847             } else if (rhs == null) {
    848                 return 1;
    849             } else {
    850                 return lhs.compareTo(rhs);
    851             }
    852         }
    853     }
    854 
    855     /**
    856      * Parse only lightweight details about the package at the given location.
    857      * Automatically detects if the package is a monolithic style (single APK
    858      * file) or cluster style (directory of APKs).
    859      * <p>
    860      * This performs sanity checking on cluster style packages, such as
    861      * requiring identical package name and version codes, a single base APK,
    862      * and unique split names.
    863      *
    864      * @see PackageParser#parsePackage(File, int)
    865      */
    866     public static PackageLite parsePackageLite(File packageFile, int flags)
    867             throws PackageParserException {
    868         if (packageFile.isDirectory()) {
    869             return parseClusterPackageLite(packageFile, flags);
    870         } else {
    871             return parseMonolithicPackageLite(packageFile, flags);
    872         }
    873     }
    874 
    875     private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)
    876             throws PackageParserException {
    877         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
    878         final ApkLite baseApk = parseApkLite(packageFile, flags);
    879         final String packagePath = packageFile.getAbsolutePath();
    880         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    881         return new PackageLite(packagePath, baseApk, null, null, null, null, null, null);
    882     }
    883 
    884     static PackageLite parseClusterPackageLite(File packageDir, int flags)
    885             throws PackageParserException {
    886         final File[] files = packageDir.listFiles();
    887         if (ArrayUtils.isEmpty(files)) {
    888             throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
    889                     "No packages found in split");
    890         }
    891 
    892         String packageName = null;
    893         int versionCode = 0;
    894 
    895         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
    896         final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
    897         for (File file : files) {
    898             if (isApkFile(file)) {
    899                 final ApkLite lite = parseApkLite(file, flags);
    900 
    901                 // Assert that all package names and version codes are
    902                 // consistent with the first one we encounter.
    903                 if (packageName == null) {
    904                     packageName = lite.packageName;
    905                     versionCode = lite.versionCode;
    906                 } else {
    907                     if (!packageName.equals(lite.packageName)) {
    908                         throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
    909                                 "Inconsistent package " + lite.packageName + " in " + file
    910                                 + "; expected " + packageName);
    911                     }
    912                     if (versionCode != lite.versionCode) {
    913                         throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
    914                                 "Inconsistent version " + lite.versionCode + " in " + file
    915                                 + "; expected " + versionCode);
    916                     }
    917                 }
    918 
    919                 // Assert that each split is defined only once
    920                 if (apks.put(lite.splitName, lite) != null) {
    921                     throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
    922                             "Split name " + lite.splitName
    923                             + " defined more than once; most recent was " + file);
    924                 }
    925             }
    926         }
    927         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    928 
    929         final ApkLite baseApk = apks.remove(null);
    930         if (baseApk == null) {
    931             throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
    932                     "Missing base APK in " + packageDir);
    933         }
    934 
    935         // Always apply deterministic ordering based on splitName
    936         final int size = apks.size();
    937 
    938         String[] splitNames = null;
    939         boolean[] isFeatureSplits = null;
    940         String[] usesSplitNames = null;
    941         String[] configForSplits = null;
    942         String[] splitCodePaths = null;
    943         int[] splitRevisionCodes = null;
    944         String[] splitClassLoaderNames = null;
    945         if (size > 0) {
    946             splitNames = new String[size];
    947             isFeatureSplits = new boolean[size];
    948             usesSplitNames = new String[size];
    949             configForSplits = new String[size];
    950             splitCodePaths = new String[size];
    951             splitRevisionCodes = new int[size];
    952 
    953             splitNames = apks.keySet().toArray(splitNames);
    954             Arrays.sort(splitNames, sSplitNameComparator);
    955 
    956             for (int i = 0; i < size; i++) {
    957                 final ApkLite apk = apks.get(splitNames[i]);
    958                 usesSplitNames[i] = apk.usesSplitName;
    959                 isFeatureSplits[i] = apk.isFeatureSplit;
    960                 configForSplits[i] = apk.configForSplit;
    961                 splitCodePaths[i] = apk.codePath;
    962                 splitRevisionCodes[i] = apk.revisionCode;
    963             }
    964         }
    965 
    966         final String codePath = packageDir.getAbsolutePath();
    967         return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
    968                 configForSplits, splitCodePaths, splitRevisionCodes);
    969     }
    970 
    971     /**
    972      * Parse the package at the given location. Automatically detects if the
    973      * package is a monolithic style (single APK file) or cluster style
    974      * (directory of APKs).
    975      * <p>
    976      * This performs sanity checking on cluster style packages, such as
    977      * requiring identical package name and version codes, a single base APK,
    978      * and unique split names.
    979      * <p>
    980      * Note that this <em>does not</em> perform signature verification; that
    981      * must be done separately in {@link #collectCertificates(Package, int)}.
    982      *
    983      * If {@code useCaches} is true, the package parser might return a cached
    984      * result from a previous parse of the same {@code packageFile} with the same
    985      * {@code flags}. Note that this method does not check whether {@code packageFile}
    986      * has changed since the last parse, it's up to callers to do so.
    987      *
    988      * @see #parsePackageLite(File, int)
    989      */
    990     public Package parsePackage(File packageFile, int flags, boolean useCaches)
    991             throws PackageParserException {
    992         Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
    993         if (parsed != null) {
    994             return parsed;
    995         }
    996 
    997         long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
    998         if (packageFile.isDirectory()) {
    999             parsed = parseClusterPackage(packageFile, flags);
   1000         } else {
   1001             parsed = parseMonolithicPackage(packageFile, flags);
   1002         }
   1003 
   1004         long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
   1005         cacheResult(packageFile, flags, parsed);
   1006         if (LOG_PARSE_TIMINGS) {
   1007             parseTime = cacheTime - parseTime;
   1008             cacheTime = SystemClock.uptimeMillis() - cacheTime;
   1009             if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
   1010                 Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
   1011                         + "ms, update_cache=" + cacheTime + " ms");
   1012             }
   1013         }
   1014         return parsed;
   1015     }
   1016 
   1017     /**
   1018      * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
   1019      */
   1020     public Package parsePackage(File packageFile, int flags) throws PackageParserException {
   1021         return parsePackage(packageFile, flags, false /* useCaches */);
   1022     }
   1023 
   1024     /**
   1025      * Returns the cache key for a specificied {@code packageFile} and {@code flags}.
   1026      */
   1027     private String getCacheKey(File packageFile, int flags) {
   1028         StringBuilder sb = new StringBuilder(packageFile.getName());
   1029         sb.append('-');
   1030         sb.append(flags);
   1031 
   1032         return sb.toString();
   1033     }
   1034 
   1035     @VisibleForTesting
   1036     protected Package fromCacheEntry(byte[] bytes) {
   1037         return fromCacheEntryStatic(bytes);
   1038     }
   1039 
   1040     /** static version of {@link #fromCacheEntry} for unit tests. */
   1041     @VisibleForTesting
   1042     public static Package fromCacheEntryStatic(byte[] bytes) {
   1043         final Parcel p = Parcel.obtain();
   1044         p.unmarshall(bytes, 0, bytes.length);
   1045         p.setDataPosition(0);
   1046 
   1047         final ReadHelper helper = new ReadHelper(p);
   1048         helper.startAndInstall();
   1049 
   1050         PackageParser.Package pkg = new PackageParser.Package(p);
   1051 
   1052         p.recycle();
   1053 
   1054         sCachedPackageReadCount.incrementAndGet();
   1055 
   1056         return pkg;
   1057     }
   1058 
   1059     @VisibleForTesting
   1060     protected byte[] toCacheEntry(Package pkg) {
   1061         return toCacheEntryStatic(pkg);
   1062 
   1063     }
   1064 
   1065     /** static version of {@link #toCacheEntry} for unit tests. */
   1066     @VisibleForTesting
   1067     public static byte[] toCacheEntryStatic(Package pkg) {
   1068         final Parcel p = Parcel.obtain();
   1069         final WriteHelper helper = new WriteHelper(p);
   1070 
   1071         pkg.writeToParcel(p, 0 /* flags */);
   1072 
   1073         helper.finishAndUninstall();
   1074 
   1075         byte[] serialized = p.marshall();
   1076         p.recycle();
   1077 
   1078         return serialized;
   1079     }
   1080 
   1081     /**
   1082      * Given a {@code packageFile} and a {@code cacheFile} returns whether the
   1083      * cache file is up to date based on the mod-time of both files.
   1084      */
   1085     private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
   1086         try {
   1087             // NOTE: We don't use the File.lastModified API because it has the very
   1088             // non-ideal failure mode of returning 0 with no excepions thrown.
   1089             // The nio2 Files API is a little better but is considerably more expensive.
   1090             final StructStat pkg = android.system.Os.stat(packageFile.getAbsolutePath());
   1091             final StructStat cache = android.system.Os.stat(cacheFile.getAbsolutePath());
   1092             return pkg.st_mtime < cache.st_mtime;
   1093         } catch (ErrnoException ee) {
   1094             // The most common reason why stat fails is that a given cache file doesn't
   1095             // exist. We ignore that here. It's easy to reason that it's safe to say the
   1096             // cache isn't up to date if we see any sort of exception here.
   1097             //
   1098             // (1) Exception while stating the package file : This should never happen,
   1099             // and if it does, we do a full package parse (which is likely to throw the
   1100             // same exception).
   1101             // (2) Exception while stating the cache file : If the file doesn't exist, the
   1102             // cache is obviously out of date. If the file *does* exist, we can't read it.
   1103             // We will attempt to delete and recreate it after parsing the package.
   1104             if (ee.errno != OsConstants.ENOENT) {
   1105                 Slog.w("Error while stating package cache : ", ee);
   1106             }
   1107 
   1108             return false;
   1109         }
   1110     }
   1111 
   1112     /**
   1113      * Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
   1114      * or {@code null} if no cached result exists.
   1115      */
   1116     private Package getCachedResult(File packageFile, int flags) {
   1117         if (mCacheDir == null) {
   1118             return null;
   1119         }
   1120 
   1121         final String cacheKey = getCacheKey(packageFile, flags);
   1122         final File cacheFile = new File(mCacheDir, cacheKey);
   1123 
   1124         try {
   1125             // If the cache is not up to date, return null.
   1126             if (!isCacheUpToDate(packageFile, cacheFile)) {
   1127                 return null;
   1128             }
   1129 
   1130             final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
   1131             Package p = fromCacheEntry(bytes);
   1132             if (mCallback != null) {
   1133                 String[] overlayApks = mCallback.getOverlayApks(p.packageName);
   1134                 if (overlayApks != null && overlayApks.length > 0) {
   1135                     for (String overlayApk : overlayApks) {
   1136                         // If a static RRO is updated, return null.
   1137                         if (!isCacheUpToDate(new File(overlayApk), cacheFile)) {
   1138                             return null;
   1139                         }
   1140                     }
   1141                 }
   1142             }
   1143             return p;
   1144         } catch (Throwable e) {
   1145             Slog.w(TAG, "Error reading package cache: ", e);
   1146 
   1147             // If something went wrong while reading the cache entry, delete the cache file
   1148             // so that we regenerate it the next time.
   1149             cacheFile.delete();
   1150             return null;
   1151         }
   1152     }
   1153 
   1154     /**
   1155      * Caches the parse result for {@code packageFile} with flags {@code flags}.
   1156      */
   1157     private void cacheResult(File packageFile, int flags, Package parsed) {
   1158         if (mCacheDir == null) {
   1159             return;
   1160         }
   1161 
   1162         try {
   1163             final String cacheKey = getCacheKey(packageFile, flags);
   1164             final File cacheFile = new File(mCacheDir, cacheKey);
   1165 
   1166             if (cacheFile.exists()) {
   1167                 if (!cacheFile.delete()) {
   1168                     Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
   1169                 }
   1170             }
   1171 
   1172             final byte[] cacheEntry = toCacheEntry(parsed);
   1173 
   1174             if (cacheEntry == null) {
   1175                 return;
   1176             }
   1177 
   1178             try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
   1179                 fos.write(cacheEntry);
   1180             } catch (IOException ioe) {
   1181                 Slog.w(TAG, "Error writing cache entry.", ioe);
   1182                 cacheFile.delete();
   1183             }
   1184         } catch (Throwable e) {
   1185             Slog.w(TAG, "Error saving package cache.", e);
   1186         }
   1187     }
   1188 
   1189     /**
   1190      * Parse all APKs contained in the given directory, treating them as a
   1191      * single package. This also performs sanity checking, such as requiring
   1192      * identical package name and version codes, a single base APK, and unique
   1193      * split names.
   1194      * <p>
   1195      * Note that this <em>does not</em> perform signature verification; that
   1196      * must be done separately in {@link #collectCertificates(Package, int)}.
   1197      */
   1198     private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
   1199         final PackageLite lite = parseClusterPackageLite(packageDir, 0);
   1200         if (mOnlyCoreApps && !lite.coreApp) {
   1201             throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
   1202                     "Not a coreApp: " + packageDir);
   1203         }
   1204 
   1205         // Build the split dependency tree.
   1206         SparseArray<int[]> splitDependencies = null;
   1207         final SplitAssetLoader assetLoader;
   1208         if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
   1209             try {
   1210                 splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
   1211                 assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
   1212             } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
   1213                 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
   1214             }
   1215         } else {
   1216             assetLoader = new DefaultSplitAssetLoader(lite, flags);
   1217         }
   1218 
   1219         try {
   1220             final AssetManager assets = assetLoader.getBaseAssetManager();
   1221             final File baseApk = new File(lite.baseCodePath);
   1222             final Package pkg = parseBaseApk(baseApk, assets, flags);
   1223             if (pkg == null) {
   1224                 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
   1225                         "Failed to parse base APK: " + baseApk);
   1226             }
   1227 
   1228             if (!ArrayUtils.isEmpty(lite.splitNames)) {
   1229                 final int num = lite.splitNames.length;
   1230                 pkg.splitNames = lite.splitNames;
   1231                 pkg.splitCodePaths = lite.splitCodePaths;
   1232                 pkg.splitRevisionCodes = lite.splitRevisionCodes;
   1233                 pkg.splitFlags = new int[num];
   1234                 pkg.splitPrivateFlags = new int[num];
   1235                 pkg.applicationInfo.splitNames = pkg.splitNames;
   1236                 pkg.applicationInfo.splitDependencies = splitDependencies;
   1237                 pkg.applicationInfo.splitClassLoaderNames = new String[num];
   1238 
   1239                 for (int i = 0; i < num; i++) {
   1240                     final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
   1241                     parseSplitApk(pkg, i, splitAssets, flags);
   1242                 }
   1243             }
   1244 
   1245             pkg.setCodePath(packageDir.getAbsolutePath());
   1246             pkg.setUse32bitAbi(lite.use32bitAbi);
   1247             return pkg;
   1248         } finally {
   1249             IoUtils.closeQuietly(assetLoader);
   1250         }
   1251     }
   1252 
   1253     /**
   1254      * Parse the given APK file, treating it as as a single monolithic package.
   1255      * <p>
   1256      * Note that this <em>does not</em> perform signature verification; that
   1257      * must be done separately in {@link #collectCertificates(Package, int)}.
   1258      *
   1259      * @deprecated external callers should move to
   1260      *             {@link #parsePackage(File, int)}. Eventually this method will
   1261      *             be marked private.
   1262      */
   1263     @Deprecated
   1264     public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
   1265         final AssetManager assets = newConfiguredAssetManager();
   1266         final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
   1267         if (mOnlyCoreApps) {
   1268             if (!lite.coreApp) {
   1269                 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
   1270                         "Not a coreApp: " + apkFile);
   1271             }
   1272         }
   1273 
   1274         try {
   1275             final Package pkg = parseBaseApk(apkFile, assets, flags);
   1276             pkg.setCodePath(apkFile.getAbsolutePath());
   1277             pkg.setUse32bitAbi(lite.use32bitAbi);
   1278             return pkg;
   1279         } finally {
   1280             IoUtils.closeQuietly(assets);
   1281         }
   1282     }
   1283 
   1284     private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
   1285             throws PackageParserException {
   1286         if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
   1287             throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
   1288                     "Invalid package file: " + apkPath);
   1289         }
   1290 
   1291         // The AssetManager guarantees uniqueness for asset paths, so if this asset path
   1292         // already exists in the AssetManager, addAssetPath will only return the cookie
   1293         // assigned to it.
   1294         int cookie = assets.addAssetPath(apkPath);
   1295         if (cookie == 0) {
   1296             throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
   1297                     "Failed adding asset path: " + apkPath);
   1298         }
   1299         return cookie;
   1300     }
   1301 
   1302     private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
   1303             throws PackageParserException {
   1304         final String apkPath = apkFile.getAbsolutePath();
   1305 
   1306         String volumeUuid = null;
   1307         if (apkPath.startsWith(MNT_EXPAND)) {
   1308             final int end = apkPath.indexOf('/', MNT_EXPAND.length());
   1309             volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
   1310         }
   1311 
   1312         mParseError = PackageManager.INSTALL_SUCCEEDED;
   1313         mArchiveSourcePath = apkFile.getAbsolutePath();
   1314 
   1315         if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
   1316 
   1317         final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
   1318 
   1319         Resources res = null;
   1320         XmlResourceParser parser = null;
   1321         try {
   1322             res = new Resources(assets, mMetrics, null);
   1323             parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
   1324 
   1325             final String[] outError = new String[1];
   1326             final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
   1327             if (pkg == null) {
   1328                 throw new PackageParserException(mParseError,
   1329                         apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
   1330             }
   1331 
   1332             pkg.setVolumeUuid(volumeUuid);
   1333             pkg.setApplicationVolumeUuid(volumeUuid);
   1334             pkg.setBaseCodePath(apkPath);
   1335             pkg.setSignatures(null);
   1336 
   1337             return pkg;
   1338 
   1339         } catch (PackageParserException e) {
   1340             throw e;
   1341         } catch (Exception e) {
   1342             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
   1343                     "Failed to read manifest from " + apkPath, e);
   1344         } finally {
   1345             IoUtils.closeQuietly(parser);
   1346         }
   1347     }
   1348 
   1349     private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags)
   1350             throws PackageParserException {
   1351         final String apkPath = pkg.splitCodePaths[splitIndex];
   1352 
   1353         mParseError = PackageManager.INSTALL_SUCCEEDED;
   1354         mArchiveSourcePath = apkPath;
   1355 
   1356         if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
   1357 
   1358         final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
   1359 
   1360         final Resources res;
   1361         XmlResourceParser parser = null;
   1362         try {
   1363             res = new Resources(assets, mMetrics, null);
   1364             assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   1365                     Build.VERSION.RESOURCES_SDK_INT);
   1366             parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
   1367 
   1368             final String[] outError = new String[1];
   1369             pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
   1370             if (pkg == null) {
   1371                 throw new PackageParserException(mParseError,
   1372                         apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
   1373             }
   1374 
   1375         } catch (PackageParserException e) {
   1376             throw e;
   1377         } catch (Exception e) {
   1378             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
   1379                     "Failed to read manifest from " + apkPath, e);
   1380         } finally {
   1381             IoUtils.closeQuietly(parser);
   1382         }
   1383     }
   1384 
   1385     /**
   1386      * Parse the manifest of a <em>split APK</em>.
   1387      * <p>
   1388      * Note that split APKs have many more restrictions on what they're capable
   1389      * of doing, so many valid features of a base APK have been carefully
   1390      * omitted here.
   1391      */
   1392     private Package parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags,
   1393             int splitIndex, String[] outError) throws XmlPullParserException, IOException,
   1394             PackageParserException {
   1395         AttributeSet attrs = parser;
   1396 
   1397         // We parsed manifest tag earlier; just skip past it
   1398         parsePackageSplitNames(parser, attrs);
   1399 
   1400         mParseInstrumentationArgs = null;
   1401 
   1402         int type;
   1403 
   1404         boolean foundApp = false;
   1405 
   1406         int outerDepth = parser.getDepth();
   1407         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   1408                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
   1409             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   1410                 continue;
   1411             }
   1412 
   1413             String tagName = parser.getName();
   1414             if (tagName.equals(TAG_APPLICATION)) {
   1415                 if (foundApp) {
   1416                     if (RIGID_PARSER) {
   1417                         outError[0] = "<manifest> has more than one <application>";
   1418                         mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   1419                         return null;
   1420                     } else {
   1421                         Slog.w(TAG, "<manifest> has more than one <application>");
   1422                         XmlUtils.skipCurrentTag(parser);
   1423                         continue;
   1424                     }
   1425                 }
   1426 
   1427                 foundApp = true;
   1428                 if (!parseSplitApplication(pkg, res, parser, flags, splitIndex, outError)) {
   1429                     return null;
   1430                 }
   1431 
   1432             } else if (RIGID_PARSER) {
   1433                 outError[0] = "Bad element under <manifest>: "
   1434                     + parser.getName();
   1435                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   1436                 return null;
   1437 
   1438             } else {
   1439                 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
   1440                         + " at " + mArchiveSourcePath + " "
   1441                         + parser.getPositionDescription());
   1442                 XmlUtils.skipCurrentTag(parser);
   1443                 continue;
   1444             }
   1445         }
   1446 
   1447         if (!foundApp) {
   1448             outError[0] = "<manifest> does not contain an <application>";
   1449             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
   1450         }
   1451 
   1452         return pkg;
   1453     }
   1454 
   1455     public static int getApkSigningVersion(Package pkg) {
   1456         try {
   1457             if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) {
   1458                 return APK_SIGNING_V2;
   1459             }
   1460             return APK_SIGNING_V1;
   1461         } catch (IOException e) {
   1462         }
   1463         return APK_SIGNING_UNKNOWN;
   1464     }
   1465 
   1466     /**
   1467      * Populates the correct packages fields with the given certificates.
   1468      * <p>
   1469      * This is useful when we've already processed the certificates [such as during package
   1470      * installation through an installer session]. We don't re-process the archive and
   1471      * simply populate the correct fields.
   1472      */
   1473     public static void populateCertificates(Package pkg, Certificate[][] certificates)
   1474             throws PackageParserException {
   1475         pkg.mCertificates = null;
   1476         pkg.mSignatures = null;
   1477         pkg.mSigningKeys = null;
   1478 
   1479         pkg.mCertificates = certificates;
   1480         try {
   1481             pkg.mSignatures = convertToSignatures(certificates);
   1482         } catch (CertificateEncodingException e) {
   1483             // certificates weren't encoded properly; something went wrong
   1484             throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
   1485                     "Failed to collect certificates from " + pkg.baseCodePath, e);
   1486         }
   1487         pkg.mSigningKeys = new ArraySet<>(certificates.length);
   1488         for (int i = 0; i < certificates.length; i++) {
   1489             Certificate[] signerCerts = certificates[i];
   1490             Certificate signerCert = signerCerts[0];
   1491             pkg.mSigningKeys.add(signerCert.getPublicKey());
   1492         }
   1493         // add signatures to child packages
   1494         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
   1495         for (int i = 0; i < childCount; i++) {
   1496             Package childPkg = pkg.childPackages.get(i);
   1497             childPkg.mCertificates = pkg.mCertificates;
   1498             childPkg.mSignatures = pkg.mSignatures;
   1499             childPkg.mSigningKeys = pkg.mSigningKeys;
   1500         }
   1501     }
   1502 
   1503     /**
   1504      * Collect certificates from all the APKs described in the given package,
   1505      * populating {@link Package#mSignatures}. Also asserts that all APK
   1506      * contents are signed correctly and consistently.
   1507      */
   1508     public static void collectCertificates(Package pkg, int parseFlags)
   1509             throws PackageParserException {
   1510         collectCertificatesInternal(pkg, parseFlags);
   1511         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
   1512         for (int i = 0; i < childCount; i++) {
   1513             Package childPkg = pkg.childPackages.get(i);
   1514             childPkg.mCertificates = pkg.mCertificates;
   1515             childPkg.mSignatures = pkg.mSignatures;
   1516             childPkg.mSigningKeys = pkg.mSigningKeys;
   1517         }
   1518     }
   1519 
   1520     private static void collectCertificatesInternal(Package pkg, int parseFlags)
   1521             throws PackageParserException {
   1522         pkg.mCertificates = null;
   1523         pkg.mSignatures = null;
   1524         pkg.mSigningKeys = null;
   1525 
   1526         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
   1527         try {
   1528             collectCertificates(pkg, new File(pkg.baseCodePath), parseFlags);
   1529 
   1530             if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
   1531                 for (int i = 0; i < pkg.splitCodePaths.length; i++) {
   1532                     collectCertificates(pkg, new File(pkg.splitCodePaths[i]), parseFlags);
   1533                 }
   1534             }
   1535         } finally {
   1536             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
   1537         }
   1538     }
   1539 
   1540     private static void collectCertificates(Package pkg, File apkFile, int parseFlags)
   1541             throws PackageParserException {
   1542         final String apkPath = apkFile.getAbsolutePath();
   1543 
   1544         // Try to verify the APK using APK Signature Scheme v2.
   1545         boolean verified = false;
   1546         {
   1547             Certificate[][] allSignersCerts = null;
   1548             Signature[] signatures = null;
   1549             try {
   1550                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2");
   1551                 allSignersCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
   1552                 signatures = convertToSignatures(allSignersCerts);
   1553                 // APK verified using APK Signature Scheme v2.
   1554                 verified = true;
   1555             } catch (ApkSignatureSchemeV2Verifier.SignatureNotFoundException e) {
   1556                 // No APK Signature Scheme v2 signature found
   1557                 if ((parseFlags & PARSE_IS_EPHEMERAL) != 0) {
   1558                     throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
   1559                         "No APK Signature Scheme v2 signature in ephemeral package " + apkPath,
   1560                         e);
   1561                 }
   1562                 // Static shared libraries must use only the V2 signing scheme
   1563                 if (pkg.applicationInfo.isStaticSharedLibrary()) {
   1564                     throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
   1565                             "Static shared libs must use v2 signature scheme " + apkPath);
   1566                 }
   1567             } catch (Exception e) {
   1568                 // APK Signature Scheme v2 signature was found but did not verify
   1569                 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
   1570                         "Failed to collect certificates from " + apkPath
   1571                                 + " using APK Signature Scheme v2",
   1572                         e);
   1573             } finally {
   1574                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
   1575             }
   1576 
   1577             if (verified) {
   1578                 if (pkg.mCertificates == null) {
   1579                     pkg.mCertificates = allSignersCerts;
   1580                     pkg.mSignatures = signatures;
   1581                     pkg.mSigningKeys = new ArraySet<>(allSignersCerts.length);
   1582                     for (int i = 0; i < allSignersCerts.length; i++) {
   1583                         Certificate[] signerCerts = allSignersCerts[i];
   1584                         Certificate signerCert = signerCerts[0];
   1585                         pkg.mSigningKeys.add(signerCert.getPublicKey());
   1586                     }
   1587                 } else {
   1588                     if (!Signature.areExactMatch(pkg.mSignatures, signatures)) {
   1589                         throw new PackageParserException(
   1590                                 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
   1591                                 apkPath + " has mismatched certificates");
   1592                     }
   1593                 }
   1594                 // Not yet done, because we need to confirm that AndroidManifest.xml exists and,
   1595                 // if requested, that classes.dex exists.
   1596             }
   1597         }
   1598 
   1599         StrictJarFile jarFile = null;
   1600         try {
   1601             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
   1602             // Ignore signature stripping protections when verifying APKs from system partition.
   1603             // For those APKs we only care about extracting signer certificates, and don't care
   1604             // about verifying integrity.
   1605             boolean signatureSchemeRollbackProtectionsEnforced =
   1606                     (parseFlags & PARSE_IS_SYSTEM_DIR) == 0;
   1607             jarFile = new StrictJarFile(
   1608                     apkPath,
   1609                     !verified, // whether to verify JAR signature
   1610                     signatureSchemeRollbackProtectionsEnforced);
   1611             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
   1612 
   1613             // Always verify manifest, regardless of source
   1614             final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
   1615             if (manifestEntry == null) {
   1616                 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
   1617                         "Package " + apkPath + " has no manifest");
   1618             }
   1619 
   1620             // Optimization: early termination when APK already verified
   1621             if (verified) {
   1622                 return;
   1623             }
   1624 
   1625             // APK's integrity needs to be verified using JAR signature scheme.
   1626             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV1");
   1627             final List<ZipEntry> toVerify = new ArrayList<>();
   1628             toVerify.add(manifestEntry);
   1629 
   1630             // If we're parsing an untrusted package, verify all contents
   1631             if ((parseFlags & PARSE_IS_SYSTEM_DIR) == 0) {
   1632                 final Iterator<ZipEntry> i = jarFile.iterator();
   1633                 while (i.hasNext()) {
   1634                     final ZipEntry entry = i.next();
   1635 
   1636                     if (entry.isDirectory()) continue;
   1637 
   1638                     final String entryName = entry.getName();
   1639                     if (entryName.startsWith("META-INF/")) continue;
   1640                     if (entryName.equals(ANDROID_MANIFEST_FILENAME)) continue;
   1641 
   1642                     toVerify.add(entry);
   1643                 }
   1644             }
   1645 
   1646             // Verify that entries are signed consistently with the first entry
   1647             // we encountered. Note that for splits, certificates may have
   1648             // already been populated during an earlier parse of a base APK.
   1649             for (ZipEntry entry : toVerify) {
   1650                 final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
   1651                 if (ArrayUtils.isEmpty(entryCerts)) {
   1652                     throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
   1653                             "Package " + apkPath + " has no certificates at entry "
   1654                             + entry.getName());
   1655                 }
   1656                 final Signature[] entrySignatures = convertToSignatures(entryCerts);
   1657 
   1658                 if (pkg.mCertificates == null) {
   1659                     pkg.mCertificates = entryCerts;
   1660                     pkg.mSignatures = entrySignatures;
   1661                     pkg.mSigningKeys = new ArraySet<PublicKey>();
   1662                     for (int i=0; i < entryCerts.length; i++) {
   1663                         pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
   1664                     }
   1665                 } else {
   1666                     if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {
   1667                         throw new PackageParserException(
   1668                                 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath
   1669                                         + " has mismatched certificates at entry "
   1670                                         + entry.getName());
   1671                     }
   1672                 }
   1673             }
   1674             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
   1675         } catch (GeneralSecurityException e) {
   1676             throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
   1677                     "Failed to collect certificates from " + apkPath, e);
   1678         } catch (IOException | RuntimeException e) {
   1679             throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
   1680                     "Failed to collect certificates from " + apkPath, e);
   1681         } finally {
   1682             closeQuietly(jarFile);
   1683         }
   1684     }
   1685 
   1686     private static Signature[] convertToSignatures(Certificate[][] certs)
   1687             throws CertificateEncodingException {
   1688         final Signature[] res = new Signature[certs.length];
   1689         for (int i = 0; i < certs.length; i++) {
   1690             res[i] = new Signature(certs[i]);
   1691         }
   1692         return res;
   1693     }
   1694 
   1695     private static AssetManager newConfiguredAssetManager() {
   1696         AssetManager assetManager = new AssetManager();
   1697         assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   1698                 Build.VERSION.RESOURCES_SDK_INT);
   1699         return assetManager;
   1700     }
   1701 
   1702     /**
   1703      * Utility method that retrieves lightweight details about a single APK
   1704      * file, including package name, split name, and install location.
   1705      *
   1706      * @param apkFile path to a single APK
   1707      * @param flags optional parse flags, such as
   1708      *            {@link #PARSE_COLLECT_CERTIFICATES}
   1709      */
   1710     public static ApkLite parseApkLite(File apkFile, int flags)
   1711             throws PackageParserException {
   1712         final String apkPath = apkFile.getAbsolutePath();
   1713 
   1714         AssetManager assets = null;
   1715         XmlResourceParser parser = null;
   1716         try {
   1717             assets = newConfiguredAssetManager();
   1718             int cookie = assets.addAssetPath(apkPath);
   1719             if (cookie == 0) {
   1720                 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
   1721                         "Failed to parse " + apkPath);
   1722             }
   1723 
   1724             final DisplayMetrics metrics = new DisplayMetrics();
   1725             metrics.setToDefaults();
   1726 
   1727             parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
   1728 
   1729             final Signature[] signatures;
   1730             final Certificate[][] certificates;
   1731             if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
   1732                 // TODO: factor signature related items out of Package object
   1733                 final Package tempPkg = new Package((String) null);
   1734                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
   1735                 try {
   1736                     collectCertificates(tempPkg, apkFile, flags);
   1737                 } finally {
   1738                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
   1739                 }
   1740                 signatures = tempPkg.mSignatures;
   1741                 certificates = tempPkg.mCertificates;
   1742             } else {
   1743                 signatures = null;
   1744                 certificates = null;
   1745             }
   1746 
   1747             final AttributeSet attrs = parser;
   1748             return parseApkLite(apkPath, parser, attrs, signatures, certificates);
   1749 
   1750         } catch (XmlPullParserException | IOException | RuntimeException e) {
   1751             Slog.w(TAG, "Failed to parse " + apkPath, e);
   1752             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
   1753                     "Failed to parse " + apkPath, e);
   1754         } finally {
   1755             IoUtils.closeQuietly(parser);
   1756             IoUtils.closeQuietly(assets);
   1757         }
   1758     }
   1759 
   1760     private static String validateName(String name, boolean requireSeparator,
   1761             boolean requireFilename) {
   1762         final int N = name.length();
   1763         boolean hasSep = false;
   1764         boolean front = true;
   1765         for (int i=0; i<N; i++) {
   1766             final char c = name.charAt(i);
   1767             if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
   1768                 front = false;
   1769                 continue;
   1770             }
   1771             if (!front) {
   1772                 if ((c >= '0' && c <= '9') || c == '_') {
   1773                     continue;
   1774                 }
   1775             }
   1776             if (c == '.') {
   1777                 hasSep = true;
   1778                 front = true;
   1779                 continue;
   1780             }
   1781             return "bad character '" + c + "'";
   1782         }
   1783         if (requireFilename && !FileUtils.isValidExtFilename(name)) {
   1784             return "Invalid filename";
   1785         }
   1786         return hasSep || !requireSeparator
   1787                 ? null : "must have at least one '.' separator";
   1788     }
   1789 
   1790     private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
   1791             AttributeSet attrs) throws IOException, XmlPullParserException,
   1792             PackageParserException {
   1793 
   1794         int type;
   1795         while ((type = parser.next()) != XmlPullParser.START_TAG
   1796                 && type != XmlPullParser.END_DOCUMENT) {
   1797         }
   1798 
   1799         if (type != XmlPullParser.START_TAG) {
   1800             throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
   1801                     "No start tag found");
   1802         }
   1803         if (!parser.getName().equals(TAG_MANIFEST)) {
   1804             throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
   1805                     "No <manifest> tag");
   1806         }
   1807 
   1808         final String packageName = attrs.getAttributeValue(null, "package");
   1809         if (!"android".equals(packageName)) {
   1810             final String error = validateName(packageName, true, true);
   1811             if (error != null) {
   1812                 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
   1813                         "Invalid manifest package: " + error);
   1814             }
   1815         }
   1816 
   1817         String splitName = attrs.getAttributeValue(null, "split");
   1818         if (splitName != null) {
   1819             if (splitName.length() == 0) {
   1820                 splitName = null;
   1821             } else {
   1822                 final String error = validateName(splitName, false, false);
   1823                 if (error != null) {
   1824                     throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
   1825                             "Invalid manifest split: " + error);
   1826                 }
   1827             }
   1828         }
   1829 
   1830         return Pair.create(packageName.intern(),
   1831                 (splitName != null) ? splitName.intern() : splitName);
   1832     }
   1833 
   1834     private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
   1835             Signature[] signatures, Certificate[][] certificates)
   1836             throws IOException, XmlPullParserException, PackageParserException {
   1837         final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
   1838 
   1839         int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
   1840         int versionCode = 0;
   1841         int revisionCode = 0;
   1842         boolean coreApp = false;
   1843         boolean debuggable = false;
   1844         boolean multiArch = false;
   1845         boolean use32bitAbi = false;
   1846         boolean extractNativeLibs = true;
   1847         boolean isolatedSplits = false;
   1848         boolean isFeatureSplit = false;
   1849         String configForSplit = null;
   1850         String usesSplitName = null;
   1851 
   1852         for (int i = 0; i < attrs.getAttributeCount(); i++) {
   1853             final String attr = attrs.getAttributeName(i);
   1854             if (attr.equals("installLocation")) {
   1855                 installLocation = attrs.getAttributeIntValue(i,
   1856                         PARSE_DEFAULT_INSTALL_LOCATION);
   1857             } else if (attr.equals("versionCode")) {
   1858                 versionCode = attrs.getAttributeIntValue(i, 0);
   1859             } else if (attr.equals("revisionCode")) {
   1860                 revisionCode = attrs.getAttributeIntValue(i, 0);
   1861             } else if (attr.equals("coreApp")) {
   1862                 coreApp = attrs.getAttributeBooleanValue(i, false);
   1863             } else if (attr.equals("isolatedSplits")) {
   1864                 isolatedSplits = attrs.getAttributeBooleanValue(i, false);
   1865             } else if (attr.equals("configForSplit")) {
   1866                 configForSplit = attrs.getAttributeValue(i);
   1867             } else if (attr.equals("isFeatureSplit")) {
   1868                 isFeatureSplit = attrs.getAttributeBooleanValue(i, false);
   1869             }
   1870         }
   1871 
   1872         // Only search the tree when the tag is directly below <manifest>
   1873         int type;
   1874         final int searchDepth = parser.getDepth() + 1;
   1875 
   1876         final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
   1877         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   1878                 && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {
   1879             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   1880                 continue;
   1881             }
   1882 
   1883             if (parser.getDepth() != searchDepth) {
   1884                 continue;
   1885             }
   1886 
   1887             if (TAG_PACKAGE_VERIFIER.equals(parser.getName())) {
   1888                 final VerifierInfo verifier = parseVerifier(attrs);
   1889                 if (verifier != null) {
   1890                     verifiers.add(verifier);
   1891                 }
   1892             } else if (TAG_APPLICATION.equals(parser.getName())) {
   1893                 for (int i = 0; i < attrs.getAttributeCount(); ++i) {
   1894                     final String attr = attrs.getAttributeName(i);
   1895                     if ("debuggable".equals(attr)) {
   1896                         debuggable = attrs.getAttributeBooleanValue(i, false);
   1897                     }
   1898                     if ("multiArch".equals(attr)) {
   1899                         multiArch = attrs.getAttributeBooleanValue(i, false);
   1900                     }
   1901                     if ("use32bitAbi".equals(attr)) {
   1902                         use32bitAbi = attrs.getAttributeBooleanValue(i, false);
   1903                     }
   1904                     if ("extractNativeLibs".equals(attr)) {
   1905                         extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
   1906                     }
   1907                 }
   1908             } else if (TAG_USES_SPLIT.equals(parser.getName())) {
   1909                 if (usesSplitName != null) {
   1910                     Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others.");
   1911                     continue;
   1912                 }
   1913 
   1914                 usesSplitName = attrs.getAttributeValue(ANDROID_RESOURCES, "name");
   1915                 if (usesSplitName == null) {
   1916                     throw new PackageParserException(
   1917                             PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
   1918                             "<uses-split> tag requires 'android:name' attribute");
   1919                 }
   1920             }
   1921         }
   1922 
   1923         return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
   1924                 configForSplit, usesSplitName, versionCode, revisionCode, installLocation,
   1925                 verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi,
   1926                 extractNativeLibs, isolatedSplits);
   1927     }
   1928 
   1929     /**
   1930      * Parses a child package and adds it to the parent if successful. If you add
   1931      * new tags that need to be supported by child packages make sure to add them
   1932      * to {@link #CHILD_PACKAGE_TAGS}.
   1933      *
   1934      * @param parentPkg The parent that contains the child
   1935      * @param res Resources against which to resolve values
   1936      * @param parser Parser of the manifest
   1937      * @param flags Flags about how to parse
   1938      * @param outError Human readable error if parsing fails
   1939      * @return True of parsing succeeded.
   1940      *
   1941      * @throws XmlPullParserException
   1942      * @throws IOException
   1943      */
   1944     private boolean parseBaseApkChild(Package parentPkg, Resources res, XmlResourceParser parser,
   1945             int flags, String[] outError) throws XmlPullParserException, IOException {
   1946         // Let ppl not abuse this mechanism by limiting the packages per APK
   1947         if (parentPkg.childPackages != null && parentPkg.childPackages.size() + 2
   1948                 > MAX_PACKAGES_PER_APK) {
   1949             outError[0] = "Maximum number of packages per APK is: " + MAX_PACKAGES_PER_APK;
   1950             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   1951             return false;
   1952         }
   1953 
   1954         // Make sure we have a valid child package name
   1955         String childPackageName = parser.getAttributeValue(null, "package");
   1956         if (validateName(childPackageName, true, false) != null) {
   1957             mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
   1958             return false;
   1959         }
   1960 
   1961         // Child packages must be unique
   1962         if (childPackageName.equals(parentPkg.packageName)) {
   1963             String message = "Child package name cannot be equal to parent package name: "
   1964                     + parentPkg.packageName;
   1965             Slog.w(TAG, message);
   1966             outError[0] = message;
   1967             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   1968             return false;
   1969         }
   1970 
   1971         // Child packages must be unique
   1972         if (parentPkg.hasChildPackage(childPackageName)) {
   1973             String message = "Duplicate child package:" + childPackageName;
   1974             Slog.w(TAG, message);
   1975             outError[0] = message;
   1976             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   1977             return false;
   1978         }
   1979 
   1980         // Go ahead and parse the child
   1981         Package childPkg = new Package(childPackageName);
   1982 
   1983         // Child package inherits parent version code/name/target SDK
   1984         childPkg.mVersionCode = parentPkg.mVersionCode;
   1985         childPkg.baseRevisionCode = parentPkg.baseRevisionCode;
   1986         childPkg.mVersionName = parentPkg.mVersionName;
   1987         childPkg.applicationInfo.targetSdkVersion = parentPkg.applicationInfo.targetSdkVersion;
   1988         childPkg.applicationInfo.minSdkVersion = parentPkg.applicationInfo.minSdkVersion;
   1989 
   1990         childPkg = parseBaseApkCommon(childPkg, CHILD_PACKAGE_TAGS, res, parser, flags, outError);
   1991         if (childPkg == null) {
   1992             // If we got null then error was set during child parsing
   1993             return false;
   1994         }
   1995 
   1996         // Set the parent-child relation
   1997         if (parentPkg.childPackages == null) {
   1998             parentPkg.childPackages = new ArrayList<>();
   1999         }
   2000         parentPkg.childPackages.add(childPkg);
   2001         childPkg.parentPackage = parentPkg;
   2002 
   2003         return true;
   2004     }
   2005 
   2006     /**
   2007      * Parse the manifest of a <em>base APK</em>. When adding new features you
   2008      * need to consider whether they should be supported by split APKs and child
   2009      * packages.
   2010      *
   2011      * @param apkPath The package apk file path
   2012      * @param res The resources from which to resolve values
   2013      * @param parser The manifest parser
   2014      * @param flags Flags how to parse
   2015      * @param outError Human readable error message
   2016      * @return Parsed package or null on error.
   2017      *
   2018      * @throws XmlPullParserException
   2019      * @throws IOException
   2020      */
   2021     private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
   2022             String[] outError) throws XmlPullParserException, IOException {
   2023         final String splitName;
   2024         final String pkgName;
   2025 
   2026         try {
   2027             Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser);
   2028             pkgName = packageSplit.first;
   2029             splitName = packageSplit.second;
   2030 
   2031             if (!TextUtils.isEmpty(splitName)) {
   2032                 outError[0] = "Expected base APK, but found split " + splitName;
   2033                 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
   2034                 return null;
   2035             }
   2036         } catch (PackageParserException e) {
   2037             mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
   2038             return null;
   2039         }
   2040 
   2041         if (mCallback != null) {
   2042             String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath);
   2043             if (overlayPaths != null && overlayPaths.length > 0) {
   2044                 for (String overlayPath : overlayPaths) {
   2045                     res.getAssets().addOverlayPath(overlayPath);
   2046                 }
   2047             }
   2048         }
   2049 
   2050         final Package pkg = new Package(pkgName);
   2051 
   2052         TypedArray sa = res.obtainAttributes(parser,
   2053                 com.android.internal.R.styleable.AndroidManifest);
   2054 
   2055         pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
   2056                 com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
   2057         pkg.baseRevisionCode = sa.getInteger(
   2058                 com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
   2059         pkg.mVersionName = sa.getNonConfigurationString(
   2060                 com.android.internal.R.styleable.AndroidManifest_versionName, 0);
   2061         if (pkg.mVersionName != null) {
   2062             pkg.mVersionName = pkg.mVersionName.intern();
   2063         }
   2064 
   2065         pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
   2066 
   2067         sa.recycle();
   2068 
   2069         return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
   2070     }
   2071 
   2072     /**
   2073      * This is the common parsing routing for handling parent and child
   2074      * packages in a base APK. The difference between parent and child
   2075      * parsing is that some tags are not supported by child packages as
   2076      * well as some manifest attributes are ignored. The implementation
   2077      * assumes the calling code has already handled the manifest tag if needed
   2078      * (this applies to the parent only).
   2079      *
   2080      * @param pkg The package which to populate
   2081      * @param acceptedTags Which tags to handle, null to handle all
   2082      * @param res Resources against which to resolve values
   2083      * @param parser Parser of the manifest
   2084      * @param flags Flags about how to parse
   2085      * @param outError Human readable error if parsing fails
   2086      * @return The package if parsing succeeded or null.
   2087      *
   2088      * @throws XmlPullParserException
   2089      * @throws IOException
   2090      */
   2091     private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
   2092             XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
   2093             IOException {
   2094         mParseInstrumentationArgs = null;
   2095 
   2096         int type;
   2097         boolean foundApp = false;
   2098 
   2099         TypedArray sa = res.obtainAttributes(parser,
   2100                 com.android.internal.R.styleable.AndroidManifest);
   2101 
   2102         String str = sa.getNonConfigurationString(
   2103                 com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
   2104         if (str != null && str.length() > 0) {
   2105             if ((flags & PARSE_IS_EPHEMERAL) != 0) {
   2106                 outError[0] = "sharedUserId not allowed in ephemeral application";
   2107                 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
   2108                 return null;
   2109             }
   2110             String nameError = validateName(str, true, false);
   2111             if (nameError != null && !"android".equals(pkg.packageName)) {
   2112                 outError[0] = "<manifest> specifies bad sharedUserId name \""
   2113                     + str + "\": " + nameError;
   2114                 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
   2115                 return null;
   2116             }
   2117             pkg.mSharedUserId = str.intern();
   2118             pkg.mSharedUserLabel = sa.getResourceId(
   2119                     com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
   2120         }
   2121 
   2122         pkg.installLocation = sa.getInteger(
   2123                 com.android.internal.R.styleable.AndroidManifest_installLocation,
   2124                 PARSE_DEFAULT_INSTALL_LOCATION);
   2125         pkg.applicationInfo.installLocation = pkg.installLocation;
   2126 
   2127         final int targetSandboxVersion = sa.getInteger(
   2128                 com.android.internal.R.styleable.AndroidManifest_targetSandboxVersion,
   2129                 PARSE_DEFAULT_TARGET_SANDBOX);
   2130         pkg.applicationInfo.targetSandboxVersion = targetSandboxVersion;
   2131 
   2132         /* Set the global "forward lock" flag */
   2133         if ((flags & PARSE_FORWARD_LOCK) != 0) {
   2134             pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
   2135         }
   2136 
   2137         /* Set the global "on SD card" flag */
   2138         if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
   2139             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
   2140         }
   2141 
   2142         if (sa.getBoolean(com.android.internal.R.styleable.AndroidManifest_isolatedSplits, false)) {
   2143             pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
   2144         }
   2145 
   2146         // Resource boolean are -1, so 1 means we don't know the value.
   2147         int supportsSmallScreens = 1;
   2148         int supportsNormalScreens = 1;
   2149         int supportsLargeScreens = 1;
   2150         int supportsXLargeScreens = 1;
   2151         int resizeable = 1;
   2152         int anyDensity = 1;
   2153 
   2154         int outerDepth = parser.getDepth();
   2155         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   2156                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
   2157             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   2158                 continue;
   2159             }
   2160 
   2161             String tagName = parser.getName();
   2162 
   2163             if (acceptedTags != null && !acceptedTags.contains(tagName)) {
   2164                 Slog.w(TAG, "Skipping unsupported element under <manifest>: "
   2165                         + tagName + " at " + mArchiveSourcePath + " "
   2166                         + parser.getPositionDescription());
   2167                 XmlUtils.skipCurrentTag(parser);
   2168                 continue;
   2169             }
   2170 
   2171             if (tagName.equals(TAG_APPLICATION)) {
   2172                 if (foundApp) {
   2173                     if (RIGID_PARSER) {
   2174                         outError[0] = "<manifest> has more than one <application>";
   2175                         mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   2176                         return null;
   2177                     } else {
   2178                         Slog.w(TAG, "<manifest> has more than one <application>");
   2179                         XmlUtils.skipCurrentTag(parser);
   2180                         continue;
   2181                     }
   2182                 }
   2183 
   2184                 foundApp = true;
   2185                 if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
   2186                     return null;
   2187                 }
   2188             } else if (tagName.equals(TAG_OVERLAY)) {
   2189                 sa = res.obtainAttributes(parser,
   2190                         com.android.internal.R.styleable.AndroidManifestResourceOverlay);
   2191                 pkg.mOverlayTarget = sa.getString(
   2192                         com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
   2193                 pkg.mOverlayPriority = sa.getInt(
   2194                         com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
   2195                         0);
   2196                 pkg.mIsStaticOverlay = sa.getBoolean(
   2197                         com.android.internal.R.styleable.AndroidManifestResourceOverlay_isStatic,
   2198                         false);
   2199                 final String propName = sa.getString(
   2200                         com.android.internal.R.styleable
   2201                         .AndroidManifestResourceOverlay_requiredSystemPropertyName);
   2202                 final String propValue = sa.getString(
   2203                         com.android.internal.R.styleable
   2204                         .AndroidManifestResourceOverlay_requiredSystemPropertyValue);
   2205                 sa.recycle();
   2206 
   2207                 if (pkg.mOverlayTarget == null) {
   2208                     outError[0] = "<overlay> does not specify a target package";
   2209                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   2210                     return null;
   2211                 }
   2212 
   2213                 if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
   2214                     outError[0] = "<overlay> priority must be between 0 and 9999";
   2215                     mParseError =
   2216                         PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   2217                     return null;
   2218                 }
   2219 
   2220                 // check to see if overlay should be excluded based on system property condition
   2221                 if (!checkOverlayRequiredSystemProperty(propName, propValue)) {
   2222                     Slog.i(TAG, "Skipping target and overlay pair " + pkg.mOverlayTarget + " and "
   2223                         + pkg.baseCodePath+ ": overlay ignored due to required system property: "
   2224                         + propName + " with value: " + propValue);
   2225                     return null;
   2226                 }
   2227 
   2228                 XmlUtils.skipCurrentTag(parser);
   2229 
   2230             } else if (tagName.equals(TAG_KEY_SETS)) {
   2231                 if (!parseKeySets(pkg, res, parser, outError)) {
   2232                     return null;
   2233                 }
   2234             } else if (tagName.equals(TAG_PERMISSION_GROUP)) {
   2235                 if (!parsePermissionGroup(pkg, flags, res, parser, outError)) {
   2236                     return null;
   2237                 }
   2238             } else if (tagName.equals(TAG_PERMISSION)) {
   2239                 if (!parsePermission(pkg, res, parser, outError)) {
   2240                     return null;
   2241                 }
   2242             } else if (tagName.equals(TAG_PERMISSION_TREE)) {
   2243                 if (!parsePermissionTree(pkg, res, parser, outError)) {
   2244                     return null;
   2245                 }
   2246             } else if (tagName.equals(TAG_USES_PERMISSION)) {
   2247                 if (!parseUsesPermission(pkg, res, parser)) {
   2248                     return null;
   2249                 }
   2250             } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)
   2251                     || tagName.equals(TAG_USES_PERMISSION_SDK_23)) {
   2252                 if (!parseUsesPermission(pkg, res, parser)) {
   2253                     return null;
   2254                 }
   2255             } else if (tagName.equals(TAG_USES_CONFIGURATION)) {
   2256                 ConfigurationInfo cPref = new ConfigurationInfo();
   2257                 sa = res.obtainAttributes(parser,
   2258                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration);
   2259                 cPref.reqTouchScreen = sa.getInt(
   2260                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
   2261                         Configuration.TOUCHSCREEN_UNDEFINED);
   2262                 cPref.reqKeyboardType = sa.getInt(
   2263                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
   2264                         Configuration.KEYBOARD_UNDEFINED);
   2265                 if (sa.getBoolean(
   2266                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
   2267                         false)) {
   2268                     cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
   2269                 }
   2270                 cPref.reqNavigation = sa.getInt(
   2271                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
   2272                         Configuration.NAVIGATION_UNDEFINED);
   2273                 if (sa.getBoolean(
   2274                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
   2275                         false)) {
   2276                     cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
   2277                 }
   2278                 sa.recycle();
   2279                 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
   2280 
   2281                 XmlUtils.skipCurrentTag(parser);
   2282 
   2283             } else if (tagName.equals(TAG_USES_FEATURE)) {
   2284                 FeatureInfo fi = parseUsesFeature(res, parser);
   2285                 pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi);
   2286 
   2287                 if (fi.name == null) {
   2288                     ConfigurationInfo cPref = new ConfigurationInfo();
   2289                     cPref.reqGlEsVersion = fi.reqGlEsVersion;
   2290                     pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
   2291                 }
   2292 
   2293                 XmlUtils.skipCurrentTag(parser);
   2294 
   2295             } else if (tagName.equals(TAG_FEATURE_GROUP)) {
   2296                 FeatureGroupInfo group = new FeatureGroupInfo();
   2297                 ArrayList<FeatureInfo> features = null;
   2298                 final int innerDepth = parser.getDepth();
   2299                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   2300                         && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
   2301                     if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   2302                         continue;
   2303                     }
   2304 
   2305                     final String innerTagName = parser.getName();
   2306                     if (innerTagName.equals("uses-feature")) {
   2307                         FeatureInfo featureInfo = parseUsesFeature(res, parser);
   2308                         // FeatureGroups are stricter and mandate that
   2309                         // any <uses-feature> declared are mandatory.
   2310                         featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
   2311                         features = ArrayUtils.add(features, featureInfo);
   2312                     } else {
   2313                         Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName +
   2314                                 " at " + mArchiveSourcePath + " " +
   2315                                 parser.getPositionDescription());
   2316                     }
   2317                     XmlUtils.skipCurrentTag(parser);
   2318                 }
   2319 
   2320                 if (features != null) {
   2321                     group.features = new FeatureInfo[features.size()];
   2322                     group.features = features.toArray(group.features);
   2323                 }
   2324                 pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group);
   2325 
   2326             } else if (tagName.equals(TAG_USES_SDK)) {
   2327                 if (SDK_VERSION > 0) {
   2328                     sa = res.obtainAttributes(parser,
   2329                             com.android.internal.R.styleable.AndroidManifestUsesSdk);
   2330 
   2331                     int minVers = 1;
   2332                     String minCode = null;
   2333                     int targetVers = 0;
   2334                     String targetCode = null;
   2335 
   2336                     TypedValue val = sa.peekValue(
   2337                             com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
   2338                     if (val != null) {
   2339                         if (val.type == TypedValue.TYPE_STRING && val.string != null) {
   2340                             targetCode = minCode = val.string.toString();
   2341                         } else {
   2342                             // If it's not a string, it's an integer.
   2343                             targetVers = minVers = val.data;
   2344                         }
   2345                     }
   2346 
   2347                     val = sa.peekValue(
   2348                             com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
   2349                     if (val != null) {
   2350                         if (val.type == TypedValue.TYPE_STRING && val.string != null) {
   2351                             targetCode = val.string.toString();
   2352                             if (minCode == null) {
   2353                                 minCode = targetCode;
   2354                             }
   2355                         } else {
   2356                             // If it's not a string, it's an integer.
   2357                             targetVers = val.data;
   2358                         }
   2359                     }
   2360 
   2361                     sa.recycle();
   2362 
   2363                     final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode,
   2364                             SDK_VERSION, SDK_CODENAMES, outError);
   2365                     if (minSdkVersion < 0) {
   2366                         mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
   2367                         return null;
   2368                     }
   2369 
   2370                     final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers,
   2371                             targetCode, SDK_VERSION, SDK_CODENAMES, outError);
   2372                     if (targetSdkVersion < 0) {
   2373                         mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
   2374                         return null;
   2375                     }
   2376 
   2377                     pkg.applicationInfo.minSdkVersion = minSdkVersion;
   2378                     pkg.applicationInfo.targetSdkVersion = targetSdkVersion;
   2379                 }
   2380 
   2381                 XmlUtils.skipCurrentTag(parser);
   2382 
   2383             } else if (tagName.equals(TAG_SUPPORT_SCREENS)) {
   2384                 sa = res.obtainAttributes(parser,
   2385                         com.android.internal.R.styleable.AndroidManifestSupportsScreens);
   2386 
   2387                 pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger(
   2388                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp,
   2389                         0);
   2390                 pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger(
   2391                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp,
   2392                         0);
   2393                 pkg.applicationInfo.largestWidthLimitDp = sa.getInteger(
   2394                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp,
   2395                         0);
   2396 
   2397                 // This is a trick to get a boolean and still able to detect
   2398                 // if a value was actually set.
   2399                 supportsSmallScreens = sa.getInteger(
   2400                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens,
   2401                         supportsSmallScreens);
   2402                 supportsNormalScreens = sa.getInteger(
   2403                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens,
   2404                         supportsNormalScreens);
   2405                 supportsLargeScreens = sa.getInteger(
   2406                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens,
   2407                         supportsLargeScreens);
   2408                 supportsXLargeScreens = sa.getInteger(
   2409                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens,
   2410                         supportsXLargeScreens);
   2411                 resizeable = sa.getInteger(
   2412                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable,
   2413                         resizeable);
   2414                 anyDensity = sa.getInteger(
   2415                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity,
   2416                         anyDensity);
   2417 
   2418                 sa.recycle();
   2419 
   2420                 XmlUtils.skipCurrentTag(parser);
   2421 
   2422             } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) {
   2423                 sa = res.obtainAttributes(parser,
   2424                         com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
   2425 
   2426                 // Note: don't allow this value to be a reference to a resource
   2427                 // that may change.
   2428                 String name = sa.getNonResourceString(
   2429                         com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name);
   2430 
   2431                 sa.recycle();
   2432 
   2433                 if (name != null && (flags&PARSE_IS_SYSTEM) != 0) {
   2434                     if (pkg.protectedBroadcasts == null) {
   2435                         pkg.protectedBroadcasts = new ArrayList<String>();
   2436                     }
   2437                     if (!pkg.protectedBroadcasts.contains(name)) {
   2438                         pkg.protectedBroadcasts.add(name.intern());
   2439                     }
   2440                 }
   2441 
   2442                 XmlUtils.skipCurrentTag(parser);
   2443 
   2444             } else if (tagName.equals(TAG_INSTRUMENTATION)) {
   2445                 if (parseInstrumentation(pkg, res, parser, outError) == null) {
   2446                     return null;
   2447                 }
   2448             } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) {
   2449                 sa = res.obtainAttributes(parser,
   2450                         com.android.internal.R.styleable.AndroidManifestOriginalPackage);
   2451 
   2452                 String orig =sa.getNonConfigurationString(
   2453                         com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
   2454                 if (!pkg.packageName.equals(orig)) {
   2455                     if (pkg.mOriginalPackages == null) {
   2456                         pkg.mOriginalPackages = new ArrayList<String>();
   2457                         pkg.mRealPackage = pkg.packageName;
   2458                     }
   2459                     pkg.mOriginalPackages.add(orig);
   2460                 }
   2461 
   2462                 sa.recycle();
   2463 
   2464                 XmlUtils.skipCurrentTag(parser);
   2465 
   2466             } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) {
   2467                 sa = res.obtainAttributes(parser,
   2468                         com.android.internal.R.styleable.AndroidManifestOriginalPackage);
   2469 
   2470                 String name = sa.getNonConfigurationString(
   2471                         com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
   2472 
   2473                 sa.recycle();
   2474 
   2475                 if (name != null) {
   2476                     if (pkg.mAdoptPermissions == null) {
   2477                         pkg.mAdoptPermissions = new ArrayList<String>();
   2478                     }
   2479                     pkg.mAdoptPermissions.add(name);
   2480                 }
   2481 
   2482                 XmlUtils.skipCurrentTag(parser);
   2483 
   2484             } else if (tagName.equals(TAG_USES_GL_TEXTURE)) {
   2485                 // Just skip this tag
   2486                 XmlUtils.skipCurrentTag(parser);
   2487                 continue;
   2488 
   2489             } else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) {
   2490                 // Just skip this tag
   2491                 XmlUtils.skipCurrentTag(parser);
   2492                 continue;
   2493             } else if (tagName.equals(TAG_SUPPORTS_INPUT)) {//
   2494                 XmlUtils.skipCurrentTag(parser);
   2495                 continue;
   2496 
   2497             } else if (tagName.equals(TAG_EAT_COMMENT)) {
   2498                 // Just skip this tag
   2499                 XmlUtils.skipCurrentTag(parser);
   2500                 continue;
   2501 
   2502             } else if (tagName.equals(TAG_PACKAGE)) {
   2503                 if (!MULTI_PACKAGE_APK_ENABLED) {
   2504                     XmlUtils.skipCurrentTag(parser);
   2505                     continue;
   2506                 }
   2507                 if (!parseBaseApkChild(pkg, res, parser, flags, outError)) {
   2508                     // If parsing a child failed the error is already set
   2509                     return null;
   2510                 }
   2511 
   2512             } else if (tagName.equals(TAG_RESTRICT_UPDATE)) {
   2513                 if ((flags & PARSE_IS_SYSTEM_DIR) != 0) {
   2514                     sa = res.obtainAttributes(parser,
   2515                             com.android.internal.R.styleable.AndroidManifestRestrictUpdate);
   2516                     final String hash = sa.getNonConfigurationString(
   2517                             com.android.internal.R.styleable.AndroidManifestRestrictUpdate_hash, 0);
   2518                     sa.recycle();
   2519 
   2520                     pkg.restrictUpdateHash = null;
   2521                     if (hash != null) {
   2522                         final int hashLength = hash.length();
   2523                         final byte[] hashBytes = new byte[hashLength / 2];
   2524                         for (int i = 0; i < hashLength; i += 2){
   2525                             hashBytes[i/2] = (byte) ((Character.digit(hash.charAt(i), 16) << 4)
   2526                                     + Character.digit(hash.charAt(i + 1), 16));
   2527                         }
   2528                         pkg.restrictUpdateHash = hashBytes;
   2529                     }
   2530                 }
   2531 
   2532                 XmlUtils.skipCurrentTag(parser);
   2533 
   2534             } else if (RIGID_PARSER) {
   2535                 outError[0] = "Bad element under <manifest>: "
   2536                     + parser.getName();
   2537                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   2538                 return null;
   2539 
   2540             } else {
   2541                 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
   2542                         + " at " + mArchiveSourcePath + " "
   2543                         + parser.getPositionDescription());
   2544                 XmlUtils.skipCurrentTag(parser);
   2545                 continue;
   2546             }
   2547         }
   2548 
   2549         if (!foundApp && pkg.instrumentation.size() == 0) {
   2550             outError[0] = "<manifest> does not contain an <application> or <instrumentation>";
   2551             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
   2552         }
   2553 
   2554         final int NP = PackageParser.NEW_PERMISSIONS.length;
   2555         StringBuilder implicitPerms = null;
   2556         for (int ip=0; ip<NP; ip++) {
   2557             final PackageParser.NewPermissionInfo npi
   2558                     = PackageParser.NEW_PERMISSIONS[ip];
   2559             if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
   2560                 break;
   2561             }
   2562             if (!pkg.requestedPermissions.contains(npi.name)) {
   2563                 if (implicitPerms == null) {
   2564                     implicitPerms = new StringBuilder(128);
   2565                     implicitPerms.append(pkg.packageName);
   2566                     implicitPerms.append(": compat added ");
   2567                 } else {
   2568                     implicitPerms.append(' ');
   2569                 }
   2570                 implicitPerms.append(npi.name);
   2571                 pkg.requestedPermissions.add(npi.name);
   2572             }
   2573         }
   2574         if (implicitPerms != null) {
   2575             Slog.i(TAG, implicitPerms.toString());
   2576         }
   2577 
   2578         final int NS = PackageParser.SPLIT_PERMISSIONS.length;
   2579         for (int is=0; is<NS; is++) {
   2580             final PackageParser.SplitPermissionInfo spi
   2581                     = PackageParser.SPLIT_PERMISSIONS[is];
   2582             if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
   2583                     || !pkg.requestedPermissions.contains(spi.rootPerm)) {
   2584                 continue;
   2585             }
   2586             for (int in=0; in<spi.newPerms.length; in++) {
   2587                 final String perm = spi.newPerms[in];
   2588                 if (!pkg.requestedPermissions.contains(perm)) {
   2589                     pkg.requestedPermissions.add(perm);
   2590                 }
   2591             }
   2592         }
   2593 
   2594         if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
   2595                 && pkg.applicationInfo.targetSdkVersion
   2596                         >= android.os.Build.VERSION_CODES.DONUT)) {
   2597             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
   2598         }
   2599         if (supportsNormalScreens != 0) {
   2600             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
   2601         }
   2602         if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
   2603                 && pkg.applicationInfo.targetSdkVersion
   2604                         >= android.os.Build.VERSION_CODES.DONUT)) {
   2605             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
   2606         }
   2607         if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
   2608                 && pkg.applicationInfo.targetSdkVersion
   2609                         >= android.os.Build.VERSION_CODES.GINGERBREAD)) {
   2610             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
   2611         }
   2612         if (resizeable < 0 || (resizeable > 0
   2613                 && pkg.applicationInfo.targetSdkVersion
   2614                         >= android.os.Build.VERSION_CODES.DONUT)) {
   2615             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
   2616         }
   2617         if (anyDensity < 0 || (anyDensity > 0
   2618                 && pkg.applicationInfo.targetSdkVersion
   2619                         >= android.os.Build.VERSION_CODES.DONUT)) {
   2620             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
   2621         }
   2622 
   2623         // At this point we can check if an application is not supporting densities and hence
   2624         // cannot be windowed / resized. Note that an SDK version of 0 is common for
   2625         // pre-Doughnut applications.
   2626         if (pkg.applicationInfo.usesCompatibilityMode()) {
   2627             adjustPackageToBeUnresizeableAndUnpipable(pkg);
   2628         }
   2629         return pkg;
   2630     }
   2631 
   2632     private boolean checkOverlayRequiredSystemProperty(String propName, String propValue) {
   2633 
   2634         if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) {
   2635             if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) {
   2636                 // malformed condition - incomplete
   2637                 Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName
   2638                     + "=" + propValue + "' - require both requiredSystemPropertyName"
   2639                     + " AND requiredSystemPropertyValue to be specified.");
   2640                 return false;
   2641             }
   2642             // no valid condition set - so no exclusion criteria, overlay will be included.
   2643             return true;
   2644         }
   2645 
   2646         // check property value - make sure it is both set and equal to expected value
   2647         final String currValue = SystemProperties.get(propName);
   2648         return (currValue != null && currValue.equals(propValue));
   2649     }
   2650 
   2651     /**
   2652      * This is a pre-density application which will get scaled - instead of being pixel perfect.
   2653      * This type of application is not resizable.
   2654      *
   2655      * @param pkg The package which needs to be marked as unresizable.
   2656      */
   2657     private void adjustPackageToBeUnresizeableAndUnpipable(Package pkg) {
   2658         for (Activity a : pkg.activities) {
   2659             a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
   2660             a.info.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE;
   2661         }
   2662     }
   2663 
   2664     /**
   2665      * Computes the targetSdkVersion to use at runtime. If the package is not
   2666      * compatible with this platform, populates {@code outError[0]} with an
   2667      * error message.
   2668      * <p>
   2669      * If {@code targetCode} is not specified, e.g. the value is {@code null},
   2670      * then the {@code targetVers} will be returned unmodified.
   2671      * <p>
   2672      * Otherwise, the behavior varies based on whether the current platform
   2673      * is a pre-release version, e.g. the {@code platformSdkCodenames} array
   2674      * has length > 0:
   2675      * <ul>
   2676      * <li>If this is a pre-release platform and the value specified by
   2677      * {@code targetCode} is contained within the array of allowed pre-release
   2678      * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
   2679      * <li>If this is a released platform, this method will return -1 to
   2680      * indicate that the package is not compatible with this platform.
   2681      * </ul>
   2682      *
   2683      * @param targetVers targetSdkVersion number, if specified in the
   2684      *                   application manifest, or 0 otherwise
   2685      * @param targetCode targetSdkVersion code, if specified in the application
   2686      *                   manifest, or {@code null} otherwise
   2687      * @param platformSdkVersion platform SDK version number, typically
   2688      *                           Build.VERSION.SDK_INT
   2689      * @param platformSdkCodenames array of allowed pre-release SDK codenames
   2690      *                             for this platform
   2691      * @param outError output array to populate with error, if applicable
   2692      * @return the targetSdkVersion to use at runtime, or -1 if the package is
   2693      *         not compatible with this platform
   2694      * @hide Exposed for unit testing only.
   2695      */
   2696     @TestApi
   2697     public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
   2698             @Nullable String targetCode, @IntRange(from = 1) int platformSdkVersion,
   2699             @NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
   2700         // If it's a release SDK, return the version number unmodified.
   2701         if (targetCode == null) {
   2702             return targetVers;
   2703         }
   2704 
   2705         // If it's a pre-release SDK and the codename matches this platform, it
   2706         // definitely targets this SDK.
   2707         if (ArrayUtils.contains(platformSdkCodenames, targetCode)) {
   2708             return Build.VERSION_CODES.CUR_DEVELOPMENT;
   2709         }
   2710 
   2711         // Otherwise, we're looking at an incompatible pre-release SDK.
   2712         if (platformSdkCodenames.length > 0) {
   2713             outError[0] = "Requires development platform " + targetCode
   2714                     + " (current platform is any of "
   2715                     + Arrays.toString(platformSdkCodenames) + ")";
   2716         } else {
   2717             outError[0] = "Requires development platform " + targetCode
   2718                     + " but this is a release platform.";
   2719         }
   2720         return -1;
   2721     }
   2722 
   2723     /**
   2724      * Computes the minSdkVersion to use at runtime. If the package is not
   2725      * compatible with this platform, populates {@code outError[0]} with an
   2726      * error message.
   2727      * <p>
   2728      * If {@code minCode} is not specified, e.g. the value is {@code null},
   2729      * then behavior varies based on the {@code platformSdkVersion}:
   2730      * <ul>
   2731      * <li>If the platform SDK version is greater than or equal to the
   2732      * {@code minVers}, returns the {@code mniVers} unmodified.
   2733      * <li>Otherwise, returns -1 to indicate that the package is not
   2734      * compatible with this platform.
   2735      * </ul>
   2736      * <p>
   2737      * Otherwise, the behavior varies based on whether the current platform
   2738      * is a pre-release version, e.g. the {@code platformSdkCodenames} array
   2739      * has length > 0:
   2740      * <ul>
   2741      * <li>If this is a pre-release platform and the value specified by
   2742      * {@code targetCode} is contained within the array of allowed pre-release
   2743      * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
   2744      * <li>If this is a released platform, this method will return -1 to
   2745      * indicate that the package is not compatible with this platform.
   2746      * </ul>
   2747      *
   2748      * @param minVers minSdkVersion number, if specified in the application
   2749      *                manifest, or 1 otherwise
   2750      * @param minCode minSdkVersion code, if specified in the application
   2751      *                manifest, or {@code null} otherwise
   2752      * @param platformSdkVersion platform SDK version number, typically
   2753      *                           Build.VERSION.SDK_INT
   2754      * @param platformSdkCodenames array of allowed prerelease SDK codenames
   2755      *                             for this platform
   2756      * @param outError output array to populate with error, if applicable
   2757      * @return the minSdkVersion to use at runtime, or -1 if the package is not
   2758      *         compatible with this platform
   2759      * @hide Exposed for unit testing only.
   2760      */
   2761     @TestApi
   2762     public static int computeMinSdkVersion(@IntRange(from = 1) int minVers,
   2763             @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
   2764             @NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
   2765         // If it's a release SDK, make sure we meet the minimum SDK requirement.
   2766         if (minCode == null) {
   2767             if (minVers <= platformSdkVersion) {
   2768                 return minVers;
   2769             }
   2770 
   2771             // We don't meet the minimum SDK requirement.
   2772             outError[0] = "Requires newer sdk version #" + minVers
   2773                     + " (current version is #" + platformSdkVersion + ")";
   2774             return -1;
   2775         }
   2776 
   2777         // If it's a pre-release SDK and the codename matches this platform, we
   2778         // definitely meet the minimum SDK requirement.
   2779         if (ArrayUtils.contains(platformSdkCodenames, minCode)) {
   2780             return Build.VERSION_CODES.CUR_DEVELOPMENT;
   2781         }
   2782 
   2783         // Otherwise, we're looking at an incompatible pre-release SDK.
   2784         if (platformSdkCodenames.length > 0) {
   2785             outError[0] = "Requires development platform " + minCode
   2786                     + " (current platform is any of "
   2787                     + Arrays.toString(platformSdkCodenames) + ")";
   2788         } else {
   2789             outError[0] = "Requires development platform " + minCode
   2790                     + " but this is a release platform.";
   2791         }
   2792         return -1;
   2793     }
   2794 
   2795     private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs) {
   2796         FeatureInfo fi = new FeatureInfo();
   2797         TypedArray sa = res.obtainAttributes(attrs,
   2798                 com.android.internal.R.styleable.AndroidManifestUsesFeature);
   2799         // Note: don't allow this value to be a reference to a resource
   2800         // that may change.
   2801         fi.name = sa.getNonResourceString(
   2802                 com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
   2803         fi.version = sa.getInt(
   2804                 com.android.internal.R.styleable.AndroidManifestUsesFeature_version, 0);
   2805         if (fi.name == null) {
   2806             fi.reqGlEsVersion = sa.getInt(
   2807                         com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
   2808                         FeatureInfo.GL_ES_VERSION_UNDEFINED);
   2809         }
   2810         if (sa.getBoolean(
   2811                 com.android.internal.R.styleable.AndroidManifestUsesFeature_required, true)) {
   2812             fi.flags |= FeatureInfo.FLAG_REQUIRED;
   2813         }
   2814         sa.recycle();
   2815         return fi;
   2816     }
   2817 
   2818     private boolean parseUsesStaticLibrary(Package pkg, Resources res, XmlResourceParser parser,
   2819             String[] outError) throws XmlPullParserException, IOException {
   2820         TypedArray sa = res.obtainAttributes(parser,
   2821                 com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary);
   2822 
   2823         // Note: don't allow this value to be a reference to a resource that may change.
   2824         String lname = sa.getNonResourceString(
   2825                 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
   2826         final int version = sa.getInt(
   2827                 com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary_version, -1);
   2828         String certSha256Digest = sa.getNonResourceString(com.android.internal.R.styleable
   2829                 .AndroidManifestUsesStaticLibrary_certDigest);
   2830         sa.recycle();
   2831 
   2832         // Since an APK providing a static shared lib can only provide the lib - fail if malformed
   2833         if (lname == null || version < 0 || certSha256Digest == null) {
   2834             outError[0] = "Bad uses-static-library declaration name: " + lname + " version: "
   2835                     + version + " certDigest" + certSha256Digest;
   2836             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   2837             XmlUtils.skipCurrentTag(parser);
   2838             return false;
   2839         }
   2840 
   2841         // Can depend only on one version of the same library
   2842         if (pkg.usesStaticLibraries != null && pkg.usesStaticLibraries.contains(lname)) {
   2843             outError[0] = "Depending on multiple versions of static library " + lname;
   2844             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   2845             XmlUtils.skipCurrentTag(parser);
   2846             return false;
   2847         }
   2848 
   2849         lname = lname.intern();
   2850         // We allow ":" delimiters in the SHA declaration as this is the format
   2851         // emitted by the certtool making it easy for developers to copy/paste.
   2852         certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
   2853 
   2854         // Fot apps targeting O-MR1 we require explicit enumeration of all certs.
   2855         String[] additionalCertSha256Digests = EmptyArray.STRING;
   2856         if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.O) {
   2857             additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError);
   2858             if (additionalCertSha256Digests == null) {
   2859                 return false;
   2860             }
   2861         } else {
   2862             XmlUtils.skipCurrentTag(parser);
   2863         }
   2864 
   2865         final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1];
   2866         certSha256Digests[0] = certSha256Digest;
   2867         System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests,
   2868                 1, additionalCertSha256Digests.length);
   2869 
   2870         pkg.usesStaticLibraries = ArrayUtils.add(pkg.usesStaticLibraries, lname);
   2871         pkg.usesStaticLibrariesVersions = ArrayUtils.appendInt(
   2872                 pkg.usesStaticLibrariesVersions, version, true);
   2873         pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class,
   2874                 pkg.usesStaticLibrariesCertDigests, certSha256Digests, true);
   2875 
   2876         return true;
   2877     }
   2878 
   2879     private String[] parseAdditionalCertificates(Resources resources, XmlResourceParser parser,
   2880             String[] outError) throws XmlPullParserException, IOException {
   2881         String[] certSha256Digests = EmptyArray.STRING;
   2882 
   2883         int outerDepth = parser.getDepth();
   2884         int type;
   2885         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   2886                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
   2887             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   2888                 continue;
   2889             }
   2890 
   2891             final String nodeName = parser.getName();
   2892             if (nodeName.equals("additional-certificate")) {
   2893                 final TypedArray sa = resources.obtainAttributes(parser, com.android.internal.
   2894                         R.styleable.AndroidManifestAdditionalCertificate);
   2895                 String certSha256Digest = sa.getNonResourceString(com.android.internal.
   2896                         R.styleable.AndroidManifestAdditionalCertificate_certDigest);
   2897                 sa.recycle();
   2898 
   2899                 if (TextUtils.isEmpty(certSha256Digest)) {
   2900                     outError[0] = "Bad additional-certificate declaration with empty"
   2901                             + " certDigest:" + certSha256Digest;
   2902                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   2903                     XmlUtils.skipCurrentTag(parser);
   2904                     sa.recycle();
   2905                     return null;
   2906                 }
   2907 
   2908                 // We allow ":" delimiters in the SHA declaration as this is the format
   2909                 // emitted by the certtool making it easy for developers to copy/paste.
   2910                 certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
   2911                 certSha256Digests = ArrayUtils.appendElement(String.class,
   2912                         certSha256Digests, certSha256Digest);
   2913             } else {
   2914                 XmlUtils.skipCurrentTag(parser);
   2915             }
   2916         }
   2917 
   2918         return certSha256Digests;
   2919     }
   2920 
   2921     private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser)
   2922             throws XmlPullParserException, IOException {
   2923         TypedArray sa = res.obtainAttributes(parser,
   2924                 com.android.internal.R.styleable.AndroidManifestUsesPermission);
   2925 
   2926         // Note: don't allow this value to be a reference to a resource
   2927         // that may change.
   2928         String name = sa.getNonResourceString(
   2929                 com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
   2930 
   2931         int maxSdkVersion = 0;
   2932         TypedValue val = sa.peekValue(
   2933                 com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
   2934         if (val != null) {
   2935             if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
   2936                 maxSdkVersion = val.data;
   2937             }
   2938         }
   2939 
   2940         final String requiredFeature = sa.getNonConfigurationString(
   2941                 com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
   2942 
   2943         final String requiredNotfeature = sa.getNonConfigurationString(
   2944                 com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredNotFeature, 0);
   2945 
   2946         sa.recycle();
   2947 
   2948         XmlUtils.skipCurrentTag(parser);
   2949 
   2950         if (name == null) {
   2951             return true;
   2952         }
   2953 
   2954         if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
   2955             return true;
   2956         }
   2957 
   2958         // Only allow requesting this permission if the platform supports the given feature.
   2959         if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(requiredFeature)) {
   2960             return true;
   2961         }
   2962 
   2963         // Only allow requesting this permission if the platform doesn't support the given feature.
   2964         if (requiredNotfeature != null && mCallback != null
   2965                 && mCallback.hasFeature(requiredNotfeature)) {
   2966             return true;
   2967         }
   2968 
   2969         int index = pkg.requestedPermissions.indexOf(name);
   2970         if (index == -1) {
   2971             pkg.requestedPermissions.add(name.intern());
   2972         } else {
   2973             Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
   2974                     + name + " in package: " + pkg.packageName + " at: "
   2975                     + parser.getPositionDescription());
   2976         }
   2977 
   2978         return true;
   2979     }
   2980 
   2981     private static String buildClassName(String pkg, CharSequence clsSeq,
   2982             String[] outError) {
   2983         if (clsSeq == null || clsSeq.length() <= 0) {
   2984             outError[0] = "Empty class name in package " + pkg;
   2985             return null;
   2986         }
   2987         String cls = clsSeq.toString();
   2988         char c = cls.charAt(0);
   2989         if (c == '.') {
   2990             return pkg + cls;
   2991         }
   2992         if (cls.indexOf('.') < 0) {
   2993             StringBuilder b = new StringBuilder(pkg);
   2994             b.append('.');
   2995             b.append(cls);
   2996             return b.toString();
   2997         }
   2998         return cls;
   2999     }
   3000 
   3001     private static String buildCompoundName(String pkg,
   3002             CharSequence procSeq, String type, String[] outError) {
   3003         String proc = procSeq.toString();
   3004         char c = proc.charAt(0);
   3005         if (pkg != null && c == ':') {
   3006             if (proc.length() < 2) {
   3007                 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg
   3008                         + ": must be at least two characters";
   3009                 return null;
   3010             }
   3011             String subName = proc.substring(1);
   3012             String nameError = validateName(subName, false, false);
   3013             if (nameError != null) {
   3014                 outError[0] = "Invalid " + type + " name " + proc + " in package "
   3015                         + pkg + ": " + nameError;
   3016                 return null;
   3017             }
   3018             return pkg + proc;
   3019         }
   3020         String nameError = validateName(proc, true, false);
   3021         if (nameError != null && !"system".equals(proc)) {
   3022             outError[0] = "Invalid " + type + " name " + proc + " in package "
   3023                     + pkg + ": " + nameError;
   3024             return null;
   3025         }
   3026         return proc;
   3027     }
   3028 
   3029     private static String buildProcessName(String pkg, String defProc,
   3030             CharSequence procSeq, int flags, String[] separateProcesses,
   3031             String[] outError) {
   3032         if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
   3033             return defProc != null ? defProc : pkg;
   3034         }
   3035         if (separateProcesses != null) {
   3036             for (int i=separateProcesses.length-1; i>=0; i--) {
   3037                 String sp = separateProcesses[i];
   3038                 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) {
   3039                     return pkg;
   3040                 }
   3041             }
   3042         }
   3043         if (procSeq == null || procSeq.length() <= 0) {
   3044             return defProc;
   3045         }
   3046         return TextUtils.safeIntern(buildCompoundName(pkg, procSeq, "process", outError));
   3047     }
   3048 
   3049     private static String buildTaskAffinityName(String pkg, String defProc,
   3050             CharSequence procSeq, String[] outError) {
   3051         if (procSeq == null) {
   3052             return defProc;
   3053         }
   3054         if (procSeq.length() <= 0) {
   3055             return null;
   3056         }
   3057         return buildCompoundName(pkg, procSeq, "taskAffinity", outError);
   3058     }
   3059 
   3060     private boolean parseKeySets(Package owner, Resources res,
   3061             XmlResourceParser parser, String[] outError)
   3062             throws XmlPullParserException, IOException {
   3063         // we've encountered the 'key-sets' tag
   3064         // all the keys and keysets that we want must be defined here
   3065         // so we're going to iterate over the parser and pull out the things we want
   3066         int outerDepth = parser.getDepth();
   3067         int currentKeySetDepth = -1;
   3068         int type;
   3069         String currentKeySet = null;
   3070         ArrayMap<String, PublicKey> publicKeys = new ArrayMap<String, PublicKey>();
   3071         ArraySet<String> upgradeKeySets = new ArraySet<String>();
   3072         ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<String, ArraySet<String>>();
   3073         ArraySet<String> improperKeySets = new ArraySet<String>();
   3074         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   3075                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
   3076             if (type == XmlPullParser.END_TAG) {
   3077                 if (parser.getDepth() == currentKeySetDepth) {
   3078                     currentKeySet = null;
   3079                     currentKeySetDepth = -1;
   3080                 }
   3081                 continue;
   3082             }
   3083             String tagName = parser.getName();
   3084             if (tagName.equals("key-set")) {
   3085                 if (currentKeySet != null) {
   3086                     outError[0] = "Improperly nested 'key-set' tag at "
   3087                             + parser.getPositionDescription();
   3088                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3089                     return false;
   3090                 }
   3091                 final TypedArray sa = res.obtainAttributes(parser,
   3092                         com.android.internal.R.styleable.AndroidManifestKeySet);
   3093                 final String keysetName = sa.getNonResourceString(
   3094                     com.android.internal.R.styleable.AndroidManifestKeySet_name);
   3095                 definedKeySets.put(keysetName, new ArraySet<String>());
   3096                 currentKeySet = keysetName;
   3097                 currentKeySetDepth = parser.getDepth();
   3098                 sa.recycle();
   3099             } else if (tagName.equals("public-key")) {
   3100                 if (currentKeySet == null) {
   3101                     outError[0] = "Improperly nested 'key-set' tag at "
   3102                             + parser.getPositionDescription();
   3103                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3104                     return false;
   3105                 }
   3106                 final TypedArray sa = res.obtainAttributes(parser,
   3107                         com.android.internal.R.styleable.AndroidManifestPublicKey);
   3108                 final String publicKeyName = sa.getNonResourceString(
   3109                         com.android.internal.R.styleable.AndroidManifestPublicKey_name);
   3110                 final String encodedKey = sa.getNonResourceString(
   3111                             com.android.internal.R.styleable.AndroidManifestPublicKey_value);
   3112                 if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
   3113                     outError[0] = "'public-key' " + publicKeyName + " must define a public-key value"
   3114                             + " on first use at " + parser.getPositionDescription();
   3115                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3116                     sa.recycle();
   3117                     return false;
   3118                 } else if (encodedKey != null) {
   3119                     PublicKey currentKey = parsePublicKey(encodedKey);
   3120                     if (currentKey == null) {
   3121                         Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
   3122                                 + parser.getPositionDescription() + " key-set " + currentKeySet
   3123                                 + " will not be added to the package's defined key-sets.");
   3124                         sa.recycle();
   3125                         improperKeySets.add(currentKeySet);
   3126                         XmlUtils.skipCurrentTag(parser);
   3127                         continue;
   3128                     }
   3129                     if (publicKeys.get(publicKeyName) == null
   3130                             || publicKeys.get(publicKeyName).equals(currentKey)) {
   3131 
   3132                         /* public-key first definition, or matches old definition */
   3133                         publicKeys.put(publicKeyName, currentKey);
   3134                     } else {
   3135                         outError[0] = "Value of 'public-key' " + publicKeyName
   3136                                + " conflicts with previously defined value at "
   3137                                + parser.getPositionDescription();
   3138                         mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3139                         sa.recycle();
   3140                         return false;
   3141                     }
   3142                 }
   3143                 definedKeySets.get(currentKeySet).add(publicKeyName);
   3144                 sa.recycle();
   3145                 XmlUtils.skipCurrentTag(parser);
   3146             } else if (tagName.equals("upgrade-key-set")) {
   3147                 final TypedArray sa = res.obtainAttributes(parser,
   3148                         com.android.internal.R.styleable.AndroidManifestUpgradeKeySet);
   3149                 String name = sa.getNonResourceString(
   3150                         com.android.internal.R.styleable.AndroidManifestUpgradeKeySet_name);
   3151                 upgradeKeySets.add(name);
   3152                 sa.recycle();
   3153                 XmlUtils.skipCurrentTag(parser);
   3154             } else if (RIGID_PARSER) {
   3155                 outError[0] = "Bad element under <key-sets>: " + parser.getName()
   3156                         + " at " + mArchiveSourcePath + " "
   3157                         + parser.getPositionDescription();
   3158                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3159                 return false;
   3160             } else {
   3161                 Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName()
   3162                         + " at " + mArchiveSourcePath + " "
   3163                         + parser.getPositionDescription());
   3164                 XmlUtils.skipCurrentTag(parser);
   3165                 continue;
   3166             }
   3167         }
   3168         Set<String> publicKeyNames = publicKeys.keySet();
   3169         if (publicKeyNames.removeAll(definedKeySets.keySet())) {
   3170             outError[0] = "Package" + owner.packageName + " AndroidManifext.xml "
   3171                     + "'key-set' and 'public-key' names must be distinct.";
   3172             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3173             return false;
   3174         }
   3175         owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>();
   3176         for (ArrayMap.Entry<String, ArraySet<String>> e: definedKeySets.entrySet()) {
   3177             final String keySetName = e.getKey();
   3178             if (e.getValue().size() == 0) {
   3179                 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
   3180                         + "'key-set' " + keySetName + " has no valid associated 'public-key'."
   3181                         + " Not including in package's defined key-sets.");
   3182                 continue;
   3183             } else if (improperKeySets.contains(keySetName)) {
   3184                 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
   3185                         + "'key-set' " + keySetName + " contained improper 'public-key'"
   3186                         + " tags. Not including in package's defined key-sets.");
   3187                 continue;
   3188             }
   3189             owner.mKeySetMapping.put(keySetName, new ArraySet<PublicKey>());
   3190             for (String s : e.getValue()) {
   3191                 owner.mKeySetMapping.get(keySetName).add(publicKeys.get(s));
   3192             }
   3193         }
   3194         if (owner.mKeySetMapping.keySet().containsAll(upgradeKeySets)) {
   3195             owner.mUpgradeKeySets = upgradeKeySets;
   3196         } else {
   3197             outError[0] ="Package" + owner.packageName + " AndroidManifext.xml "
   3198                    + "does not define all 'upgrade-key-set's .";
   3199             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3200             return false;
   3201         }
   3202         return true;
   3203     }
   3204 
   3205     private boolean parsePermissionGroup(Package owner, int flags, Resources res,
   3206             XmlResourceParser parser, String[] outError)
   3207             throws XmlPullParserException, IOException {
   3208         PermissionGroup perm = new PermissionGroup(owner);
   3209 
   3210         TypedArray sa = res.obtainAttributes(parser,
   3211                 com.android.internal.R.styleable.AndroidManifestPermissionGroup);
   3212         if (!parsePackageItemInfo(owner, perm.info, outError,
   3213                 "<permission-group>", sa, true /*nameRequired*/,
   3214                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
   3215                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
   3216                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
   3217                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_roundIcon,
   3218                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
   3219                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
   3220             sa.recycle();
   3221             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3222             return false;
   3223         }
   3224 
   3225         perm.info.descriptionRes = sa.getResourceId(
   3226                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description,
   3227                 0);
   3228         perm.info.flags = sa.getInt(
   3229                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0);
   3230         perm.info.priority = sa.getInt(
   3231                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0);
   3232         if (perm.info.priority > 0 && (flags&PARSE_IS_SYSTEM) == 0) {
   3233             perm.info.priority = 0;
   3234         }
   3235 
   3236         sa.recycle();
   3237 
   3238         if (!parseAllMetaData(res, parser, "<permission-group>", perm,
   3239                 outError)) {
   3240             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3241             return false;
   3242         }
   3243 
   3244         owner.permissionGroups.add(perm);
   3245 
   3246         return true;
   3247     }
   3248 
   3249     private boolean parsePermission(Package owner, Resources res,
   3250             XmlResourceParser parser, String[] outError)
   3251         throws XmlPullParserException, IOException {
   3252 
   3253         TypedArray sa = res.obtainAttributes(parser,
   3254                 com.android.internal.R.styleable.AndroidManifestPermission);
   3255 
   3256         Permission perm = new Permission(owner);
   3257         if (!parsePackageItemInfo(owner, perm.info, outError,
   3258                 "<permission>", sa, true /*nameRequired*/,
   3259                 com.android.internal.R.styleable.AndroidManifestPermission_name,
   3260                 com.android.internal.R.styleable.AndroidManifestPermission_label,
   3261                 com.android.internal.R.styleable.AndroidManifestPermission_icon,
   3262                 com.android.internal.R.styleable.AndroidManifestPermission_roundIcon,
   3263                 com.android.internal.R.styleable.AndroidManifestPermission_logo,
   3264                 com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
   3265             sa.recycle();
   3266             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3267             return false;
   3268         }
   3269 
   3270         // Note: don't allow this value to be a reference to a resource
   3271         // that may change.
   3272         perm.info.group = sa.getNonResourceString(
   3273                 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup);
   3274         if (perm.info.group != null) {
   3275             perm.info.group = perm.info.group.intern();
   3276         }
   3277 
   3278         perm.info.descriptionRes = sa.getResourceId(
   3279                 com.android.internal.R.styleable.AndroidManifestPermission_description,
   3280                 0);
   3281 
   3282         perm.info.protectionLevel = sa.getInt(
   3283                 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel,
   3284                 PermissionInfo.PROTECTION_NORMAL);
   3285 
   3286         perm.info.flags = sa.getInt(
   3287                 com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0);
   3288 
   3289         sa.recycle();
   3290 
   3291         if (perm.info.protectionLevel == -1) {
   3292             outError[0] = "<permission> does not specify protectionLevel";
   3293             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3294             return false;
   3295         }
   3296 
   3297         perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
   3298 
   3299         if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) {
   3300             if ( (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_INSTANT) == 0
   3301                     && (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) == 0
   3302                     && (perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=
   3303                     PermissionInfo.PROTECTION_SIGNATURE) {
   3304                 outError[0] = "<permission>  protectionLevel specifies a non-instnat flag but is "
   3305                         + "not based on signature type";
   3306                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3307                 return false;
   3308             }
   3309         }
   3310 
   3311         if (!parseAllMetaData(res, parser, "<permission>", perm, outError)) {
   3312             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3313             return false;
   3314         }
   3315 
   3316         owner.permissions.add(perm);
   3317 
   3318         return true;
   3319     }
   3320 
   3321     private boolean parsePermissionTree(Package owner, Resources res,
   3322             XmlResourceParser parser, String[] outError)
   3323         throws XmlPullParserException, IOException {
   3324         Permission perm = new Permission(owner);
   3325 
   3326         TypedArray sa = res.obtainAttributes(parser,
   3327                 com.android.internal.R.styleable.AndroidManifestPermissionTree);
   3328 
   3329         if (!parsePackageItemInfo(owner, perm.info, outError,
   3330                 "<permission-tree>", sa, true /*nameRequired*/,
   3331                 com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
   3332                 com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
   3333                 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
   3334                 com.android.internal.R.styleable.AndroidManifestPermissionTree_roundIcon,
   3335                 com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,
   3336                 com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
   3337             sa.recycle();
   3338             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3339             return false;
   3340         }
   3341 
   3342         sa.recycle();
   3343 
   3344         int index = perm.info.name.indexOf('.');
   3345         if (index > 0) {
   3346             index = perm.info.name.indexOf('.', index+1);
   3347         }
   3348         if (index < 0) {
   3349             outError[0] = "<permission-tree> name has less than three segments: "
   3350                 + perm.info.name;
   3351             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3352             return false;
   3353         }
   3354 
   3355         perm.info.descriptionRes = 0;
   3356         perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
   3357         perm.tree = true;
   3358 
   3359         if (!parseAllMetaData(res, parser, "<permission-tree>", perm,
   3360                 outError)) {
   3361             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3362             return false;
   3363         }
   3364 
   3365         owner.permissions.add(perm);
   3366 
   3367         return true;
   3368     }
   3369 
   3370     private Instrumentation parseInstrumentation(Package owner, Resources res,
   3371             XmlResourceParser parser, String[] outError)
   3372             throws XmlPullParserException, IOException {
   3373         TypedArray sa = res.obtainAttributes(parser,
   3374                 com.android.internal.R.styleable.AndroidManifestInstrumentation);
   3375 
   3376         if (mParseInstrumentationArgs == null) {
   3377             mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError,
   3378                     com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
   3379                     com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
   3380                     com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
   3381                     com.android.internal.R.styleable.AndroidManifestInstrumentation_roundIcon,
   3382                     com.android.internal.R.styleable.AndroidManifestInstrumentation_logo,
   3383                     com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
   3384             mParseInstrumentationArgs.tag = "<instrumentation>";
   3385         }
   3386 
   3387         mParseInstrumentationArgs.sa = sa;
   3388 
   3389         Instrumentation a = new Instrumentation(mParseInstrumentationArgs,
   3390                 new InstrumentationInfo());
   3391         if (outError[0] != null) {
   3392             sa.recycle();
   3393             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3394             return null;
   3395         }
   3396 
   3397         String str;
   3398         // Note: don't allow this value to be a reference to a resource
   3399         // that may change.
   3400         str = sa.getNonResourceString(
   3401                 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage);
   3402         a.info.targetPackage = str != null ? str.intern() : null;
   3403 
   3404         str = sa.getNonResourceString(
   3405                 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetProcesses);
   3406         a.info.targetProcesses = str != null ? str.intern() : null;
   3407 
   3408         a.info.handleProfiling = sa.getBoolean(
   3409                 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling,
   3410                 false);
   3411 
   3412         a.info.functionalTest = sa.getBoolean(
   3413                 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest,
   3414                 false);
   3415 
   3416         sa.recycle();
   3417 
   3418         if (a.info.targetPackage == null) {
   3419             outError[0] = "<instrumentation> does not specify targetPackage";
   3420             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3421             return null;
   3422         }
   3423 
   3424         if (!parseAllMetaData(res, parser, "<instrumentation>", a,
   3425                 outError)) {
   3426             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3427             return null;
   3428         }
   3429 
   3430         owner.instrumentation.add(a);
   3431 
   3432         return a;
   3433     }
   3434 
   3435     /**
   3436      * Parse the {@code application} XML tree at the current parse location in a
   3437      * <em>base APK</em> manifest.
   3438      * <p>
   3439      * When adding new features, carefully consider if they should also be
   3440      * supported by split APKs.
   3441      */
   3442     private boolean parseBaseApplication(Package owner, Resources res,
   3443             XmlResourceParser parser, int flags, String[] outError)
   3444         throws XmlPullParserException, IOException {
   3445         final ApplicationInfo ai = owner.applicationInfo;
   3446         final String pkgName = owner.applicationInfo.packageName;
   3447 
   3448         TypedArray sa = res.obtainAttributes(parser,
   3449                 com.android.internal.R.styleable.AndroidManifestApplication);
   3450 
   3451         if (!parsePackageItemInfo(owner, ai, outError,
   3452                 "<application>", sa, false /*nameRequired*/,
   3453                 com.android.internal.R.styleable.AndroidManifestApplication_name,
   3454                 com.android.internal.R.styleable.AndroidManifestApplication_label,
   3455                 com.android.internal.R.styleable.AndroidManifestApplication_icon,
   3456                 com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,
   3457                 com.android.internal.R.styleable.AndroidManifestApplication_logo,
   3458                 com.android.internal.R.styleable.AndroidManifestApplication_banner)) {
   3459             sa.recycle();
   3460             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3461             return false;
   3462         }
   3463 
   3464         if (ai.name != null) {
   3465             ai.className = ai.name;
   3466         }
   3467 
   3468         String manageSpaceActivity = sa.getNonConfigurationString(
   3469                 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
   3470                 Configuration.NATIVE_CONFIG_VERSION);
   3471         if (manageSpaceActivity != null) {
   3472             ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
   3473                     outError);
   3474         }
   3475 
   3476         boolean allowBackup = sa.getBoolean(
   3477                 com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
   3478         if (allowBackup) {
   3479             ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
   3480 
   3481             // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
   3482             // and restoreAnyVersion are only relevant if backup is possible for the
   3483             // given application.
   3484             String backupAgent = sa.getNonConfigurationString(
   3485                     com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
   3486                     Configuration.NATIVE_CONFIG_VERSION);
   3487             if (backupAgent != null) {
   3488                 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
   3489                 if (DEBUG_BACKUP) {
   3490                     Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName
   3491                             + " from " + pkgName + "+" + backupAgent);
   3492                 }
   3493 
   3494                 if (sa.getBoolean(
   3495                         com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore,
   3496                         true)) {
   3497                     ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
   3498                 }
   3499                 if (sa.getBoolean(
   3500                         com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion,
   3501                         false)) {
   3502                     ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
   3503                 }
   3504                 if (sa.getBoolean(
   3505                         com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly,
   3506                         false)) {
   3507                     ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
   3508                 }
   3509                 if (sa.getBoolean(
   3510                         com.android.internal.R.styleable.AndroidManifestApplication_backupInForeground,
   3511                         false)) {
   3512                     ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
   3513                 }
   3514             }
   3515 
   3516             TypedValue v = sa.peekValue(
   3517                     com.android.internal.R.styleable.AndroidManifestApplication_fullBackupContent);
   3518             if (v != null && (ai.fullBackupContent = v.resourceId) == 0) {
   3519                 if (DEBUG_BACKUP) {
   3520                     Slog.v(TAG, "fullBackupContent specified as boolean=" +
   3521                             (v.data == 0 ? "false" : "true"));
   3522                 }
   3523                 // "false" => -1, "true" => 0
   3524                 ai.fullBackupContent = (v.data == 0 ? -1 : 0);
   3525             }
   3526             if (DEBUG_BACKUP) {
   3527                 Slog.v(TAG, "fullBackupContent=" + ai.fullBackupContent + " for " + pkgName);
   3528             }
   3529         }
   3530 
   3531         ai.theme = sa.getResourceId(
   3532                 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
   3533         ai.descriptionRes = sa.getResourceId(
   3534                 com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
   3535 
   3536         if ((flags&PARSE_IS_SYSTEM) != 0) {
   3537             if (sa.getBoolean(
   3538                     com.android.internal.R.styleable.AndroidManifestApplication_persistent,
   3539                     false)) {
   3540                 // Check if persistence is based on a feature being present
   3541                 final String requiredFeature = sa.getNonResourceString(
   3542                     com.android.internal.R.styleable.
   3543                     AndroidManifestApplication_persistentWhenFeatureAvailable);
   3544                 if (requiredFeature == null || mCallback.hasFeature(requiredFeature)) {
   3545                     ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
   3546                 }
   3547             }
   3548         }
   3549 
   3550         if (sa.getBoolean(
   3551                 com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers,
   3552                 false)) {
   3553             owner.mRequiredForAllUsers = true;
   3554         }
   3555 
   3556         String restrictedAccountType = sa.getString(com.android.internal.R.styleable
   3557                 .AndroidManifestApplication_restrictedAccountType);
   3558         if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
   3559             owner.mRestrictedAccountType = restrictedAccountType;
   3560         }
   3561 
   3562         String requiredAccountType = sa.getString(com.android.internal.R.styleable
   3563                 .AndroidManifestApplication_requiredAccountType);
   3564         if (requiredAccountType != null && requiredAccountType.length() > 0) {
   3565             owner.mRequiredAccountType = requiredAccountType;
   3566         }
   3567 
   3568         if (sa.getBoolean(
   3569                 com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
   3570                 false)) {
   3571             ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
   3572         }
   3573 
   3574         if (sa.getBoolean(
   3575                 com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode,
   3576                 false)) {
   3577             ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE;
   3578         }
   3579 
   3580         owner.baseHardwareAccelerated = sa.getBoolean(
   3581                 com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
   3582                 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
   3583         if (owner.baseHardwareAccelerated) {
   3584             ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
   3585         }
   3586 
   3587         if (sa.getBoolean(
   3588                 com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
   3589                 true)) {
   3590             ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
   3591         }
   3592 
   3593         if (sa.getBoolean(
   3594                 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
   3595                 false)) {
   3596             ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
   3597         }
   3598 
   3599         if (sa.getBoolean(
   3600                 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
   3601                 true)) {
   3602             ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
   3603         }
   3604 
   3605         // The parent package controls installation, hence specify test only installs.
   3606         if (owner.parentPackage == null) {
   3607             if (sa.getBoolean(
   3608                     com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
   3609                     false)) {
   3610                 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
   3611             }
   3612         }
   3613 
   3614         if (sa.getBoolean(
   3615                 com.android.internal.R.styleable.AndroidManifestApplication_largeHeap,
   3616                 false)) {
   3617             ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP;
   3618         }
   3619 
   3620         if (sa.getBoolean(
   3621                 com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic,
   3622                 true)) {
   3623             ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
   3624         }
   3625 
   3626         if (sa.getBoolean(
   3627                 com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl,
   3628                 false /* default is no RTL support*/)) {
   3629             ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
   3630         }
   3631 
   3632         if (sa.getBoolean(
   3633                 com.android.internal.R.styleable.AndroidManifestApplication_multiArch,
   3634                 false)) {
   3635             ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
   3636         }
   3637 
   3638         if (sa.getBoolean(
   3639                 com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
   3640                 true)) {
   3641             ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
   3642         }
   3643 
   3644         if (sa.getBoolean(
   3645                 R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
   3646                 false)) {
   3647             ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
   3648         }
   3649         if (sa.getBoolean(
   3650                 R.styleable.AndroidManifestApplication_directBootAware,
   3651                 false)) {
   3652             ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
   3653         }
   3654 
   3655         if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
   3656             if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity, true)) {
   3657                 ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
   3658             } else {
   3659                 ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
   3660             }
   3661         } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
   3662             ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
   3663         }
   3664 
   3665         ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0);
   3666 
   3667         ai.networkSecurityConfigRes = sa.getResourceId(
   3668                 com.android.internal.R.styleable.AndroidManifestApplication_networkSecurityConfig,
   3669                 0);
   3670         ai.category = sa.getInt(
   3671                 com.android.internal.R.styleable.AndroidManifestApplication_appCategory,
   3672                 ApplicationInfo.CATEGORY_UNDEFINED);
   3673 
   3674         String str;
   3675         str = sa.getNonConfigurationString(
   3676                 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
   3677         ai.permission = (str != null && str.length() > 0) ? str.intern() : null;
   3678 
   3679         if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
   3680             str = sa.getNonConfigurationString(
   3681                     com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity,
   3682                     Configuration.NATIVE_CONFIG_VERSION);
   3683         } else {
   3684             // Some older apps have been seen to use a resource reference
   3685             // here that on older builds was ignored (with a warning).  We
   3686             // need to continue to do this for them so they don't break.
   3687             str = sa.getNonResourceString(
   3688                     com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
   3689         }
   3690         ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
   3691                 str, outError);
   3692 
   3693         if (outError[0] == null) {
   3694             CharSequence pname;
   3695             if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
   3696                 pname = sa.getNonConfigurationString(
   3697                         com.android.internal.R.styleable.AndroidManifestApplication_process,
   3698                         Configuration.NATIVE_CONFIG_VERSION);
   3699             } else {
   3700                 // Some older apps have been seen to use a resource reference
   3701                 // here that on older builds was ignored (with a warning).  We
   3702                 // need to continue to do this for them so they don't break.
   3703                 pname = sa.getNonResourceString(
   3704                         com.android.internal.R.styleable.AndroidManifestApplication_process);
   3705             }
   3706             ai.processName = buildProcessName(ai.packageName, null, pname,
   3707                     flags, mSeparateProcesses, outError);
   3708 
   3709             ai.enabled = sa.getBoolean(
   3710                     com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
   3711 
   3712             if (sa.getBoolean(
   3713                     com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) {
   3714                 ai.flags |= ApplicationInfo.FLAG_IS_GAME;
   3715             }
   3716 
   3717             if (false) {
   3718                 if (sa.getBoolean(
   3719                         com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
   3720                         false)) {
   3721                     ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
   3722 
   3723                     // A heavy-weight application can not be in a custom process.
   3724                     // We can do direct compare because we intern all strings.
   3725                     if (ai.processName != null && ai.processName != ai.packageName) {
   3726                         outError[0] = "cantSaveState applications can not use custom processes";
   3727                     }
   3728                 }
   3729             }
   3730         }
   3731 
   3732         ai.uiOptions = sa.getInt(
   3733                 com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);
   3734 
   3735         ai.classLoaderName = sa.getString(
   3736             com.android.internal.R.styleable.AndroidManifestApplication_classLoader);
   3737         if (ai.classLoaderName != null
   3738                 && !ClassLoaderFactory.isValidClassLoaderName(ai.classLoaderName)) {
   3739             outError[0] = "Invalid class loader name: " + ai.classLoaderName;
   3740         }
   3741 
   3742         sa.recycle();
   3743 
   3744         if (outError[0] != null) {
   3745             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3746             return false;
   3747         }
   3748 
   3749         final int innerDepth = parser.getDepth();
   3750         // IMPORTANT: These must only be cached for a single <application> to avoid components
   3751         // getting added to the wrong package.
   3752         final CachedComponentArgs cachedArgs = new CachedComponentArgs();
   3753         int type;
   3754 
   3755         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   3756                 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
   3757             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   3758                 continue;
   3759             }
   3760 
   3761             String tagName = parser.getName();
   3762             if (tagName.equals("activity")) {
   3763                 Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
   3764                         owner.baseHardwareAccelerated);
   3765                 if (a == null) {
   3766                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3767                     return false;
   3768                 }
   3769 
   3770                 owner.activities.add(a);
   3771 
   3772             } else if (tagName.equals("receiver")) {
   3773                 Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
   3774                         true, false);
   3775                 if (a == null) {
   3776                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3777                     return false;
   3778                 }
   3779 
   3780                 owner.receivers.add(a);
   3781 
   3782             } else if (tagName.equals("service")) {
   3783                 Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
   3784                 if (s == null) {
   3785                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3786                     return false;
   3787                 }
   3788 
   3789                 owner.services.add(s);
   3790 
   3791             } else if (tagName.equals("provider")) {
   3792                 Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
   3793                 if (p == null) {
   3794                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3795                     return false;
   3796                 }
   3797 
   3798                 owner.providers.add(p);
   3799 
   3800             } else if (tagName.equals("activity-alias")) {
   3801                 Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs);
   3802                 if (a == null) {
   3803                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3804                     return false;
   3805                 }
   3806 
   3807                 owner.activities.add(a);
   3808 
   3809             } else if (parser.getName().equals("meta-data")) {
   3810                 // note: application meta-data is stored off to the side, so it can
   3811                 // remain null in the primary copy (we like to avoid extra copies because
   3812                 // it can be large)
   3813                 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
   3814                         outError)) == null) {
   3815                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3816                     return false;
   3817                 }
   3818             } else if (tagName.equals("static-library")) {
   3819                 sa = res.obtainAttributes(parser,
   3820                         com.android.internal.R.styleable.AndroidManifestStaticLibrary);
   3821 
   3822                 // Note: don't allow this value to be a reference to a resource
   3823                 // that may change.
   3824                 final String lname = sa.getNonResourceString(
   3825                         com.android.internal.R.styleable.AndroidManifestStaticLibrary_name);
   3826                 final int version = sa.getInt(
   3827                         com.android.internal.R.styleable.AndroidManifestStaticLibrary_version, -1);
   3828 
   3829                 sa.recycle();
   3830 
   3831                 // Since the app canot run without a static lib - fail if malformed
   3832                 if (lname == null || version < 0) {
   3833                     outError[0] = "Bad static-library declaration name: " + lname
   3834                             + " version: " + version;
   3835                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3836                     XmlUtils.skipCurrentTag(parser);
   3837                     return false;
   3838                 }
   3839 
   3840                 if (owner.mSharedUserId != null) {
   3841                     outError[0] = "sharedUserId not allowed in static shared library";
   3842                     mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
   3843                     XmlUtils.skipCurrentTag(parser);
   3844                     return false;
   3845                 }
   3846 
   3847                 if (owner.staticSharedLibName != null) {
   3848                     outError[0] = "Multiple static-shared libs for package " + pkgName;
   3849                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3850                     XmlUtils.skipCurrentTag(parser);
   3851                     return false;
   3852                 }
   3853 
   3854                 owner.staticSharedLibName = lname.intern();
   3855                 owner.staticSharedLibVersion = version;
   3856                 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY;
   3857 
   3858                 XmlUtils.skipCurrentTag(parser);
   3859 
   3860             } else if (tagName.equals("library")) {
   3861                 sa = res.obtainAttributes(parser,
   3862                         com.android.internal.R.styleable.AndroidManifestLibrary);
   3863 
   3864                 // Note: don't allow this value to be a reference to a resource
   3865                 // that may change.
   3866                 String lname = sa.getNonResourceString(
   3867                         com.android.internal.R.styleable.AndroidManifestLibrary_name);
   3868 
   3869                 sa.recycle();
   3870 
   3871                 if (lname != null) {
   3872                     lname = lname.intern();
   3873                     if (!ArrayUtils.contains(owner.libraryNames, lname)) {
   3874                         owner.libraryNames = ArrayUtils.add(
   3875                                 owner.libraryNames, lname);
   3876                     }
   3877                 }
   3878 
   3879                 XmlUtils.skipCurrentTag(parser);
   3880 
   3881             } else if (tagName.equals("uses-static-library")) {
   3882                 if (!parseUsesStaticLibrary(owner, res, parser, outError)) {
   3883                     return false;
   3884                 }
   3885 
   3886             } else if (tagName.equals("uses-library")) {
   3887                 sa = res.obtainAttributes(parser,
   3888                         com.android.internal.R.styleable.AndroidManifestUsesLibrary);
   3889 
   3890                 // Note: don't allow this value to be a reference to a resource
   3891                 // that may change.
   3892                 String lname = sa.getNonResourceString(
   3893                         com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
   3894                 boolean req = sa.getBoolean(
   3895                         com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
   3896                         true);
   3897 
   3898                 sa.recycle();
   3899 
   3900                 if (lname != null) {
   3901                     lname = lname.intern();
   3902                     if (req) {
   3903                         owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
   3904                     } else {
   3905                         owner.usesOptionalLibraries = ArrayUtils.add(
   3906                                 owner.usesOptionalLibraries, lname);
   3907                     }
   3908                 }
   3909 
   3910                 XmlUtils.skipCurrentTag(parser);
   3911 
   3912             } else if (tagName.equals("uses-package")) {
   3913                 // Dependencies for app installers; we don't currently try to
   3914                 // enforce this.
   3915                 XmlUtils.skipCurrentTag(parser);
   3916 
   3917             } else {
   3918                 if (!RIGID_PARSER) {
   3919                     Slog.w(TAG, "Unknown element under <application>: " + tagName
   3920                             + " at " + mArchiveSourcePath + " "
   3921                             + parser.getPositionDescription());
   3922                     XmlUtils.skipCurrentTag(parser);
   3923                     continue;
   3924                 } else {
   3925                     outError[0] = "Bad element under <application>: " + tagName;
   3926                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3927                     return false;
   3928                 }
   3929             }
   3930         }
   3931 
   3932         // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after
   3933         // every activity info has had a chance to set it from its attributes.
   3934         setMaxAspectRatio(owner);
   3935 
   3936         PackageBackwardCompatibility.modifySharedLibraries(owner);
   3937 
   3938         if (hasDomainURLs(owner)) {
   3939             owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
   3940         } else {
   3941             owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
   3942         }
   3943 
   3944         return true;
   3945     }
   3946 
   3947     /**
   3948      * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
   3949      */
   3950     private static boolean hasDomainURLs(Package pkg) {
   3951         if (pkg == null || pkg.activities == null) return false;
   3952         final ArrayList<Activity> activities = pkg.activities;
   3953         final int countActivities = activities.size();
   3954         for (int n=0; n<countActivities; n++) {
   3955             Activity activity = activities.get(n);
   3956             ArrayList<ActivityIntentInfo> filters = activity.intents;
   3957             if (filters == null) continue;
   3958             final int countFilters = filters.size();
   3959             for (int m=0; m<countFilters; m++) {
   3960                 ActivityIntentInfo aii = filters.get(m);
   3961                 if (!aii.hasAction(Intent.ACTION_VIEW)) continue;
   3962                 if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue;
   3963                 if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
   3964                         aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
   3965                     return true;
   3966                 }
   3967             }
   3968         }
   3969         return false;
   3970     }
   3971 
   3972     /**
   3973      * Parse the {@code application} XML tree at the current parse location in a
   3974      * <em>split APK</em> manifest.
   3975      * <p>
   3976      * Note that split APKs have many more restrictions on what they're capable
   3977      * of doing, so many valid features of a base APK have been carefully
   3978      * omitted here.
   3979      */
   3980     private boolean parseSplitApplication(Package owner, Resources res, XmlResourceParser parser,
   3981             int flags, int splitIndex, String[] outError)
   3982             throws XmlPullParserException, IOException {
   3983         TypedArray sa = res.obtainAttributes(parser,
   3984                 com.android.internal.R.styleable.AndroidManifestApplication);
   3985 
   3986         if (sa.getBoolean(
   3987                 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, true)) {
   3988             owner.splitFlags[splitIndex] |= ApplicationInfo.FLAG_HAS_CODE;
   3989         }
   3990 
   3991         final String classLoaderName = sa.getString(
   3992                 com.android.internal.R.styleable.AndroidManifestApplication_classLoader);
   3993         if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
   3994             owner.applicationInfo.splitClassLoaderNames[splitIndex] = classLoaderName;
   3995         } else {
   3996             outError[0] = "Invalid class loader name: " + classLoaderName;
   3997             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   3998             return false;
   3999         }
   4000 
   4001         final int innerDepth = parser.getDepth();
   4002         int type;
   4003         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   4004                 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
   4005             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   4006                 continue;
   4007             }
   4008 
   4009             ComponentInfo parsedComponent = null;
   4010 
   4011             // IMPORTANT: These must only be cached for a single <application> to avoid components
   4012             // getting added to the wrong package.
   4013             final CachedComponentArgs cachedArgs = new CachedComponentArgs();
   4014             String tagName = parser.getName();
   4015             if (tagName.equals("activity")) {
   4016                 Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
   4017                         owner.baseHardwareAccelerated);
   4018                 if (a == null) {
   4019                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   4020                     return false;
   4021                 }
   4022 
   4023                 owner.activities.add(a);
   4024                 parsedComponent = a.info;
   4025 
   4026             } else if (tagName.equals("receiver")) {
   4027                 Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
   4028                         true, false);
   4029                 if (a == null) {
   4030                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   4031                     return false;
   4032                 }
   4033 
   4034                 owner.receivers.add(a);
   4035                 parsedComponent = a.info;
   4036 
   4037             } else if (tagName.equals("service")) {
   4038                 Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
   4039                 if (s == null) {
   4040                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   4041                     return false;
   4042                 }
   4043 
   4044                 owner.services.add(s);
   4045                 parsedComponent = s.info;
   4046 
   4047             } else if (tagName.equals("provider")) {
   4048                 Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
   4049                 if (p == null) {
   4050                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   4051                     return false;
   4052                 }
   4053 
   4054                 owner.providers.add(p);
   4055                 parsedComponent = p.info;
   4056 
   4057             } else if (tagName.equals("activity-alias")) {
   4058                 Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs);
   4059                 if (a == null) {
   4060                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   4061                     return false;
   4062                 }
   4063 
   4064                 owner.activities.add(a);
   4065                 parsedComponent = a.info;
   4066 
   4067             } else if (parser.getName().equals("meta-data")) {
   4068                 // note: application meta-data is stored off to the side, so it can
   4069                 // remain null in the primary copy (we like to avoid extra copies because
   4070                 // it can be large)
   4071                 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
   4072                         outError)) == null) {
   4073                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   4074                     return false;
   4075                 }
   4076 
   4077             } else if (tagName.equals("uses-static-library")) {
   4078                 if (!parseUsesStaticLibrary(owner, res, parser, outError)) {
   4079                     return false;
   4080                 }
   4081 
   4082             } else if (tagName.equals("uses-library")) {
   4083                 sa = res.obtainAttributes(parser,
   4084                         com.android.internal.R.styleable.AndroidManifestUsesLibrary);
   4085 
   4086                 // Note: don't allow this value to be a reference to a resource
   4087                 // that may change.
   4088                 String lname = sa.getNonResourceString(
   4089                         com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
   4090                 boolean req = sa.getBoolean(
   4091                         com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
   4092                         true);
   4093 
   4094                 sa.recycle();
   4095 
   4096                 if (lname != null) {
   4097                     lname = lname.intern();
   4098                     if (req) {
   4099                         // Upgrade to treat as stronger constraint
   4100                         owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
   4101                         owner.usesOptionalLibraries = ArrayUtils.remove(
   4102                                 owner.usesOptionalLibraries, lname);
   4103                     } else {
   4104                         // Ignore if someone already defined as required
   4105                         if (!ArrayUtils.contains(owner.usesLibraries, lname)) {
   4106                             owner.usesOptionalLibraries = ArrayUtils.add(
   4107                                     owner.usesOptionalLibraries, lname);
   4108                         }
   4109                     }
   4110                 }
   4111 
   4112                 XmlUtils.skipCurrentTag(parser);
   4113 
   4114             } else if (tagName.equals("uses-package")) {
   4115                 // Dependencies for app installers; we don't currently try to
   4116                 // enforce this.
   4117                 XmlUtils.skipCurrentTag(parser);
   4118 
   4119             } else {
   4120                 if (!RIGID_PARSER) {
   4121                     Slog.w(TAG, "Unknown element under <application>: " + tagName
   4122                             + " at " + mArchiveSourcePath + " "
   4123                             + parser.getPositionDescription());
   4124                     XmlUtils.skipCurrentTag(parser);
   4125                     continue;
   4126                 } else {
   4127                     outError[0] = "Bad element under <application>: " + tagName;
   4128                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
   4129                     return false;
   4130                 }
   4131             }
   4132 
   4133             if (parsedComponent != null && parsedComponent.splitName == null) {
   4134                 // If the loaded component did not specify a split, inherit the split name
   4135                 // based on the split it is defined in.
   4136                 // This is used to later load the correct split when starting this
   4137                 // component.
   4138                 parsedComponent.splitName = owner.splitNames[splitIndex];
   4139             }
   4140         }
   4141 
   4142         return true;
   4143     }
   4144 
   4145     private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
   4146             String[] outError, String tag, TypedArray sa, boolean nameRequired,
   4147             int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
   4148         // This case can only happen in unit tests where we sometimes need to create fakes
   4149         // of various package parser data structures.
   4150         if (sa == null) {
   4151             outError[0] = tag + " does not contain any attributes";
   4152             return false;
   4153         }
   4154 
   4155         String name = sa.getNonConfigurationString(nameRes, 0);
   4156         if (name == null) {
   4157             if (nameRequired) {
   4158                 outError[0] = tag + " does not specify android:name";
   4159                 return false;
   4160             }
   4161         } else {
   4162             outInfo.name
   4163                 = buildClassName(owner.applicationInfo.packageName, name, outError);
   4164             if (outInfo.name == null) {
   4165                 return false;
   4166             }
   4167         }
   4168 
   4169         final boolean useRoundIcon =
   4170                 Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
   4171         int roundIconVal = useRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
   4172         if (roundIconVal != 0) {
   4173             outInfo.icon = roundIconVal;
   4174             outInfo.nonLocalizedLabel = null;
   4175         } else {
   4176             int iconVal = sa.getResourceId(iconRes, 0);
   4177             if (iconVal != 0) {
   4178                 outInfo.icon = iconVal;
   4179                 outInfo.nonLocalizedLabel = null;
   4180             }
   4181         }
   4182 
   4183         int logoVal = sa.getResourceId(logoRes, 0);
   4184         if (logoVal != 0) {
   4185             outInfo.logo = logoVal;
   4186         }
   4187 
   4188         int bannerVal = sa.getResourceId(bannerRes, 0);
   4189         if (bannerVal != 0) {
   4190             outInfo.banner = bannerVal;
   4191         }
   4192 
   4193         TypedValue v = sa.peekValue(labelRes);
   4194         if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
   4195             outInfo.nonLocalizedLabel = v.coerceToString();
   4196         }
   4197 
   4198         outInfo.packageName = owner.packageName;
   4199 
   4200         return true;
   4201     }
   4202 
   4203     private Activity parseActivity(Package owner, Resources res,
   4204             XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
   4205             boolean receiver, boolean hardwareAccelerated)
   4206             throws XmlPullParserException, IOException {
   4207         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
   4208 
   4209         if (cachedArgs.mActivityArgs == null) {
   4210             cachedArgs.mActivityArgs = new ParseComponentArgs(owner, outError,
   4211                     R.styleable.AndroidManifestActivity_name,
   4212                     R.styleable.AndroidManifestActivity_label,
   4213                     R.styleable.AndroidManifestActivity_icon,
   4214                     R.styleable.AndroidManifestActivity_roundIcon,
   4215                     R.styleable.AndroidManifestActivity_logo,
   4216                     R.styleable.AndroidManifestActivity_banner,
   4217                     mSeparateProcesses,
   4218                     R.styleable.AndroidManifestActivity_process,
   4219                     R.styleable.AndroidManifestActivity_description,
   4220                     R.styleable.AndroidManifestActivity_enabled);
   4221         }
   4222 
   4223         cachedArgs.mActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
   4224         cachedArgs.mActivityArgs.sa = sa;
   4225         cachedArgs.mActivityArgs.flags = flags;
   4226 
   4227         Activity a = new Activity(cachedArgs.mActivityArgs, new ActivityInfo());
   4228         if (outError[0] != null) {
   4229             sa.recycle();
   4230             return null;
   4231         }
   4232 
   4233         boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
   4234         if (setExported) {
   4235             a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false);
   4236         }
   4237 
   4238         a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
   4239 
   4240         a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
   4241                 a.info.applicationInfo.uiOptions);
   4242 
   4243         String parentName = sa.getNonConfigurationString(
   4244                 R.styleable.AndroidManifestActivity_parentActivityName,
   4245                 Configuration.NATIVE_CONFIG_VERSION);
   4246         if (parentName != null) {
   4247             String parentClassName = buildClassName(a.info.packageName, parentName, outError);
   4248             if (outError[0] == null) {
   4249                 a.info.parentActivityName = parentClassName;
   4250             } else {
   4251                 Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " +
   4252                         parentName);
   4253                 outError[0] = null;
   4254             }
   4255         }
   4256 
   4257         String str;
   4258         str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
   4259         if (str == null) {
   4260             a.info.permission = owner.applicationInfo.permission;
   4261         } else {
   4262             a.info.permission = str.length() > 0 ? str.toString().intern() : null;
   4263         }
   4264 
   4265         str = sa.getNonConfigurationString(
   4266                 R.styleable.AndroidManifestActivity_taskAffinity,
   4267                 Configuration.NATIVE_CONFIG_VERSION);
   4268         a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
   4269                 owner.applicationInfo.taskAffinity, str, outError);
   4270 
   4271         a.info.splitName =
   4272                 sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0);
   4273 
   4274         a.info.flags = 0;
   4275         if (sa.getBoolean(
   4276                 R.styleable.AndroidManifestActivity_multiprocess, false)) {
   4277             a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
   4278         }
   4279 
   4280         if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
   4281             a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
   4282         }
   4283 
   4284         if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
   4285             a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
   4286         }
   4287 
   4288         if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
   4289             a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
   4290         }
   4291 
   4292         if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
   4293             a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
   4294         }
   4295 
   4296         if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
   4297             a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
   4298         }
   4299 
   4300         if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
   4301             a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
   4302         }
   4303 
   4304         if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
   4305                 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
   4306             a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
   4307         }
   4308 
   4309         if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) {
   4310             a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
   4311         }
   4312 
   4313         if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
   4314                 || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
   4315             a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
   4316         }
   4317 
   4318         if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
   4319             a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
   4320         }
   4321 
   4322         if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
   4323             a.info.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
   4324         }
   4325 
   4326         if (!receiver) {
   4327             if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
   4328                     hardwareAccelerated)) {
   4329                 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
   4330             }
   4331 
   4332             a.info.launchMode = sa.getInt(
   4333                     R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
   4334             a.info.documentLaunchMode = sa.getInt(
   4335                     R.styleable.AndroidManifestActivity_documentLaunchMode,
   4336                     ActivityInfo.DOCUMENT_LAUNCH_NONE);
   4337             a.info.maxRecents = sa.getInt(
   4338                     R.styleable.AndroidManifestActivity_maxRecents,
   4339                     ActivityManager.getDefaultAppRecentsLimitStatic());
   4340             a.info.configChanges = getActivityConfigChanges(
   4341                     sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
   4342                     sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
   4343             a.info.softInputMode = sa.getInt(
   4344                     R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
   4345 
   4346             a.info.persistableMode = sa.getInteger(
   4347                     R.styleable.AndroidManifestActivity_persistableMode,
   4348                     ActivityInfo.PERSIST_ROOT_ONLY);
   4349 
   4350             if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
   4351                 a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
   4352             }
   4353 
   4354             if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) {
   4355                 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
   4356             }
   4357 
   4358             if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) {
   4359                 a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
   4360             }
   4361 
   4362             if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
   4363                 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
   4364             }
   4365 
   4366             a.info.screenOrientation = sa.getInt(
   4367                     R.styleable.AndroidManifestActivity_screenOrientation,
   4368                     SCREEN_ORIENTATION_UNSPECIFIED);
   4369 
   4370             setActivityResizeMode(a.info, sa, owner);
   4371 
   4372             if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
   4373                     false)) {
   4374                 a.info.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE;
   4375             }
   4376 
   4377             if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
   4378                 a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
   4379             }
   4380 
   4381             if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
   4382                     && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
   4383                     == TypedValue.TYPE_FLOAT) {
   4384                 a.setMaxAspectRatio(sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
   4385                         0 /*default*/));
   4386             }
   4387 
   4388             a.info.lockTaskLaunchMode =
   4389                     sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
   4390 
   4391             a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
   4392                     R.styleable.AndroidManifestActivity_directBootAware,
   4393                     false);
   4394 
   4395             a.info.requestedVrComponent =
   4396                 sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
   4397 
   4398             a.info.rotationAnimation =
   4399                 sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, ROTATION_ANIMATION_UNSPECIFIED);
   4400 
   4401             a.info.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
   4402                     ActivityInfo.COLOR_MODE_DEFAULT);
   4403 
   4404             if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) {
   4405                 a.info.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
   4406             }
   4407 
   4408             if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) {
   4409                 a.info.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
   4410             }
   4411 
   4412         } else {
   4413             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
   4414             a.info.configChanges = 0;
   4415 
   4416             if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
   4417                 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
   4418                 if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
   4419                     Slog.w(TAG, "Activity exported request ignored due to singleUser: "
   4420                             + a.className + " at " + mArchiveSourcePath + " "
   4421                             + parser.getPositionDescription());
   4422                     a.info.exported = false;
   4423                     setExported = true;
   4424                 }
   4425             }
   4426 
   4427             a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
   4428                     R.styleable.AndroidManifestActivity_directBootAware,
   4429                     false);
   4430         }
   4431 
   4432         if (a.info.directBootAware) {
   4433             owner.applicationInfo.privateFlags |=
   4434                     ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
   4435         }
   4436 
   4437         // can't make this final; we may set it later via meta-data
   4438         boolean visibleToEphemeral =
   4439                 sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
   4440         if (visibleToEphemeral) {
   4441             a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
   4442             owner.visibleToInstantApps = true;
   4443         }
   4444 
   4445         sa.recycle();
   4446 
   4447         if (receiver && (owner.applicationInfo.privateFlags
   4448                 &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
   4449             // A heavy-weight application can not have receives in its main process
   4450             // We can do direct compare because we intern all strings.
   4451             if (a.info.processName == owner.packageName) {
   4452                 outError[0] = "Heavy-weight applications can not have receivers in main process";
   4453             }
   4454         }
   4455 
   4456         if (outError[0] != null) {
   4457             return null;
   4458         }
   4459 
   4460         int outerDepth = parser.getDepth();
   4461         int type;
   4462         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
   4463                && (type != XmlPullParser.END_TAG
   4464                        || parser.getDepth() > outerDepth)) {
   4465             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   4466                 continue;
   4467             }
   4468 
   4469             if (parser.getName().equals("intent-filter")) {
   4470                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
   4471                 if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
   4472                         intent, outError)) {
   4473                     return null;
   4474                 }
   4475                 if (intent.countActions() == 0) {
   4476                     Slog.w(TAG, "No actions in intent filter at "
   4477                             + mArchiveSourcePath + " "
   4478                             + parser.getPositionDescription());
   4479                 } else {
   4480                     a.intents.add(intent);
   4481                 }
   4482                 // adjust activity flags when we implicitly expose it via a browsable filter
   4483                 final int visibility = visibleToEphemeral
   4484                         ? IntentFilter.VISIBILITY_EXPLICIT
   4485                         : !receiver && isImplicitlyExposedIntent(intent)
   4486                                 ? IntentFilter.VISIBILITY_IMPLICIT
   4487                                 : IntentFilter.VISIBILITY_NONE;
   4488                 intent.setVisibilityToInstantApp(visibility);
   4489                 if (intent.isVisibleToInstantApp()) {
   4490                     a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
   4491                 }
   4492                 if (intent.isImplicitlyVisibleToInstantApp()) {
   4493                     a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
   4494                 }
   4495                 if (LOG_UNSAFE_BROADCASTS && receiver
   4496                         && (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O)) {
   4497                     for (int i = 0; i < intent.countActions(); i++) {
   4498                         final String action = intent.getAction(i);
   4499                         if (action == null || !action.startsWith("android.")) continue;
   4500                         if (!SAFE_BROADCASTS.contains(action)) {
   4501                             Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
   4502                                     + owner.packageName + " as requested at: "
   4503                                     + parser.getPositionDescription());
   4504                         }
   4505                     }
   4506                 }
   4507             } else if (!receiver && parser.getName().equals("preferred")) {
   4508                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
   4509                 if (!parseIntent(res, parser, false /*allowGlobs*/, false /*allowAutoVerify*/,
   4510                         intent, outError)) {
   4511                     return null;
   4512                 }
   4513                 if (intent.countActions() == 0) {
   4514                     Slog.w(TAG, "No actions in preferred at "
   4515                             + mArchiveSourcePath + " "
   4516                             + parser.getPositionDescription());
   4517                 } else {
   4518                     if (owner.preferredActivityFilters == null) {
   4519                         owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
   4520                     }
   4521                     owner.preferredActivityFilters.add(intent);
   4522                 }
   4523                 // adjust activity flags when we implicitly expose it via a browsable filter
   4524                 final int visibility = visibleToEphemeral
   4525                         ? IntentFilter.VISIBILITY_EXPLICIT
   4526                         : !receiver && isImplicitlyExposedIntent(intent)
   4527                                 ? IntentFilter.VISIBILITY_IMPLICIT
   4528                                 : IntentFilter.VISIBILITY_NONE;
   4529                 intent.setVisibilityToInstantApp(visibility);
   4530                 if (intent.isVisibleToInstantApp()) {
   4531                     a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
   4532                 }
   4533                 if (intent.isImplicitlyVisibleToInstantApp()) {
   4534                     a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
   4535                 }
   4536             } else if (parser.getName().equals("meta-data")) {
   4537                 if ((a.metaData = parseMetaData(res, parser, a.metaData,
   4538                         outError)) == null) {
   4539                     return null;
   4540                 }
   4541                 // we don't have an attribute [or it's false], but, we have meta-data
   4542                 if (!visibleToEphemeral && a.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
   4543                     visibleToEphemeral = true; // set in case there are more intent filters
   4544                     a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
   4545                     a.info.flags &= ~ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
   4546                     owner.visibleToInstantApps = true;
   4547                     // cycle through any filters already seen
   4548                     for (int i = a.intents.size() - 1; i >= 0; --i) {
   4549                         a.intents.get(i)
   4550                                 .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
   4551                     }
   4552                     if (owner.preferredActivityFilters != null) {
   4553                         for (int i = owner.preferredActivityFilters.size() - 1; i >= 0; --i) {
   4554                             owner.preferredActivityFilters.get(i)
   4555                                     .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
   4556                         }
   4557                     }
   4558                 }
   4559             } else if (!receiver && parser.getName().equals("layout")) {
   4560                 parseLayout(res, parser, a);
   4561             } else {
   4562                 if (!RIGID_PARSER) {
   4563                     Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
   4564                     if (receiver) {
   4565                         Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
   4566                                 + " at " + mArchiveSourcePath + " "
   4567                                 + parser.getPositionDescription());
   4568                     } else {
   4569                         Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
   4570                                 + " at " + mArchiveSourcePath + " "
   4571                                 + parser.getPositionDescription());
   4572                     }
   4573                     XmlUtils.skipCurrentTag(parser);
   4574                     continue;
   4575                 } else {
   4576                     if (receiver) {
   4577                         outError[0] = "Bad element under <receiver>: " + parser.getName();
   4578                     } else {
   4579                         outError[0] = "Bad element under <activity>: " + parser.getName();
   4580                     }
   4581                     return null;
   4582                 }
   4583             }
   4584         }
   4585 
   4586         if (!setExported) {
   4587             a.info.exported = a.intents.size() > 0;
   4588         }
   4589 
   4590         return a;
   4591     }
   4592 
   4593     private void setActivityResizeMode(ActivityInfo aInfo, TypedArray sa, Package owner) {
   4594         final boolean appExplicitDefault = (owner.applicationInfo.privateFlags
   4595                 & (PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
   4596                 | PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0;
   4597 
   4598         if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity)
   4599                 || appExplicitDefault) {
   4600             // Activity or app explicitly set if it is resizeable or not;
   4601             final boolean appResizeable = (owner.applicationInfo.privateFlags
   4602                     & PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0;
   4603             if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
   4604                     appResizeable)) {
   4605                 aInfo.resizeMode = RESIZE_MODE_RESIZEABLE;
   4606             } else {
   4607                 aInfo.resizeMode = RESIZE_MODE_UNRESIZEABLE;
   4608             }
   4609             return;
   4610         }
   4611 
   4612         if ((owner.applicationInfo.privateFlags
   4613                 & PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) != 0) {
   4614             // The activity or app didn't explicitly set the resizing option, however we want to
   4615             // make it resize due to the sdk version it is targeting.
   4616             aInfo.resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
   4617             return;
   4618         }
   4619 
   4620         // resize preference isn't set and target sdk version doesn't support resizing apps by
   4621         // default. For the app to be resizeable if it isn't fixed orientation or immersive.
   4622         if (aInfo.isFixedOrientationPortrait()) {
   4623             aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
   4624         } else if (aInfo.isFixedOrientationLandscape()) {
   4625             aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
   4626         } else if (aInfo.isFixedOrientation()) {
   4627             aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
   4628         } else {
   4629             aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
   4630         }
   4631     }
   4632 
   4633     /**
   4634      * Sets every the max aspect ratio of every child activity that doesn't already have an aspect
   4635      * ratio set.
   4636      */
   4637     private void setMaxAspectRatio(Package owner) {
   4638         // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater.
   4639         // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD.
   4640         float maxAspectRatio = owner.applicationInfo.targetSdkVersion < O
   4641                 ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
   4642 
   4643         if (owner.applicationInfo.maxAspectRatio != 0) {
   4644             // Use the application max aspect ration as default if set.
   4645             maxAspectRatio = owner.applicationInfo.maxAspectRatio;
   4646         } else if (owner.mAppMetaData != null
   4647                 && owner.mAppMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) {
   4648             maxAspectRatio = owner.mAppMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio);
   4649         }
   4650 
   4651         for (Activity activity : owner.activities) {
   4652             // If the max aspect ratio for the activity has already been set, skip.
   4653             if (activity.hasMaxAspectRatio()) {
   4654                 continue;
   4655             }
   4656 
   4657             // By default we prefer to use a values defined on the activity directly than values
   4658             // defined on the application. We do not check the styled attributes on the activity
   4659             // as it would have already been set when we processed the activity. We wait to process
   4660             // the meta data here since this method is called at the end of processing the
   4661             // application and all meta data is guaranteed.
   4662             final float activityAspectRatio = activity.metaData != null
   4663                     ? activity.metaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio)
   4664                     : maxAspectRatio;
   4665 
   4666             activity.setMaxAspectRatio(activityAspectRatio);
   4667         }
   4668     }
   4669 
   4670     /**
   4671      * @param configChanges The bit mask of configChanges fetched from AndroidManifest.xml.
   4672      * @param recreateOnConfigChanges The bit mask recreateOnConfigChanges fetched from
   4673      *                                AndroidManifest.xml.
   4674      * @hide Exposed for unit testing only.
   4675      */
   4676     @TestApi
   4677     public static int getActivityConfigChanges(int configChanges, int recreateOnConfigChanges) {
   4678         return configChanges | ((~recreateOnConfigChanges) & RECREATE_ON_CONFIG_CHANGES_MASK);
   4679     }
   4680 
   4681     private void parseLayout(Resources res, AttributeSet attrs, Activity a) {
   4682         TypedArray sw = res.obtainAttributes(attrs,
   4683                 com.android.internal.R.styleable.AndroidManifestLayout);
   4684         int width = -1;
   4685         float widthFraction = -1f;
   4686         int height = -1;
   4687         float heightFraction = -1f;
   4688         final int widthType = sw.getType(
   4689                 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth);
   4690         if (widthType == TypedValue.TYPE_FRACTION) {
   4691             widthFraction = sw.getFraction(
   4692                     com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth,
   4693                     1, 1, -1);
   4694         } else if (widthType == TypedValue.TYPE_DIMENSION) {
   4695             width = sw.getDimensionPixelSize(
   4696                     com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth,
   4697                     -1);
   4698         }
   4699         final int heightType = sw.getType(
   4700                 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight);
   4701         if (heightType == TypedValue.TYPE_FRACTION) {
   4702             heightFraction = sw.getFraction(
   4703                     com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight,
   4704                     1, 1, -1);
   4705         } else if (heightType == TypedValue.TYPE_DIMENSION) {
   4706             height = sw.getDimensionPixelSize(
   4707                     com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight,
   4708                     -1);
   4709         }
   4710         int gravity = sw.getInt(
   4711                 com.android.internal.R.styleable.AndroidManifestLayout_gravity,
   4712                 Gravity.CENTER);
   4713         int minWidth = sw.getDimensionPixelSize(
   4714                 com.android.internal.R.styleable.AndroidManifestLayout_minWidth,
   4715                 -1);
   4716         int minHeight = sw.getDimensionPixelSize(
   4717                 com.android.internal.R.styleable.AndroidManifestLayout_minHeight,
   4718                 -1);
   4719         sw.recycle();
   4720         a.info.windowLayout = new ActivityInfo.WindowLayout(width, widthFraction,
   4721                 height, heightFraction, gravity, minWidth, minHeight);
   4722     }
   4723 
   4724     private Activity parseActivityAlias(Package owner, Resources res,
   4725             XmlResourceParser parser, int flags, String[] outError,
   4726             CachedComponentArgs cachedArgs)
   4727             throws XmlPullParserException, IOException {
   4728         TypedArray sa = res.obtainAttributes(parser,
   4729                 com.android.internal.R.styleable.AndroidManifestActivityAlias);
   4730 
   4731         String targetActivity = sa.getNonConfigurationString(
   4732                 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity,
   4733                 Configuration.NATIVE_CONFIG_VERSION);
   4734         if (targetActivity == null) {
   4735             outError[0] = "<activity-alias> does not specify android:targetActivity";
   4736             sa.recycle();
   4737             return null;
   4738         }
   4739 
   4740         targetActivity = buildClassName(owner.applicationInfo.packageName,
   4741                 targetActivity, outError);
   4742         if (targetActivity == null) {
   4743             sa.recycle();
   4744             return null;
   4745         }
   4746 
   4747         if (cachedArgs.mActivityAliasArgs == null) {
   4748             cachedArgs.mActivityAliasArgs = new ParseComponentArgs(owner, outError,
   4749                     com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
   4750                     com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
   4751                     com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
   4752                     com.android.internal.R.styleable.AndroidManifestActivityAlias_roundIcon,
   4753                     com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
   4754                     com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
   4755                     mSeparateProcesses,
   4756                     0,
   4757                     com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
   4758                     com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
   4759             cachedArgs.mActivityAliasArgs.tag = "<activity-alias>";
   4760         }
   4761 
   4762         cachedArgs.mActivityAliasArgs.sa = sa;
   4763         cachedArgs.mActivityAliasArgs.flags = flags;
   4764 
   4765         Activity target = null;
   4766 
   4767         final int NA = owner.activities.size();
   4768         for (int i=0; i<NA; i++) {
   4769             Activity t = owner.activities.get(i);
   4770             if (targetActivity.equals(t.info.name)) {
   4771                 target = t;
   4772                 break;
   4773             }
   4774         }
   4775 
   4776         if (target == null) {
   4777             outError[0] = "<activity-alias> target activity " + targetActivity
   4778                     + " not found in manifest";
   4779             sa.recycle();
   4780             return null;
   4781         }
   4782 
   4783         ActivityInfo info = new ActivityInfo();
   4784         info.targetActivity = targetActivity;
   4785         info.configChanges = target.info.configChanges;
   4786         info.flags = target.info.flags;
   4787         info.icon = target.info.icon;
   4788         info.logo = target.info.logo;
   4789         info.banner = target.info.banner;
   4790         info.labelRes = target.info.labelRes;
   4791         info.nonLocalizedLabel = target.info.nonLocalizedLabel;
   4792         info.launchMode = target.info.launchMode;
   4793         info.lockTaskLaunchMode = target.info.lockTaskLaunchMode;
   4794         info.processName = target.info.processName;
   4795         if (info.descriptionRes == 0) {
   4796             info.descriptionRes = target.info.descriptionRes;
   4797         }
   4798         info.screenOrientation = target.info.screenOrientation;
   4799         info.taskAffinity = target.info.taskAffinity;
   4800         info.theme = target.info.theme;
   4801         info.softInputMode = target.info.softInputMode;
   4802         info.uiOptions = target.info.uiOptions;
   4803         info.parentActivityName = target.info.parentActivityName;
   4804         info.maxRecents = target.info.maxRecents;
   4805         info.windowLayout = target.info.windowLayout;
   4806         info.resizeMode = target.info.resizeMode;
   4807         info.maxAspectRatio = target.info.maxAspectRatio;
   4808 
   4809         info.encryptionAware = info.directBootAware = target.info.directBootAware;
   4810 
   4811         Activity a = new Activity(cachedArgs.mActivityAliasArgs, info);
   4812         if (outError[0] != null) {
   4813             sa.recycle();
   4814             return null;
   4815         }
   4816 
   4817         final boolean setExported = sa.hasValue(
   4818                 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported);
   4819         if (setExported) {
   4820             a.info.exported = sa.getBoolean(
   4821                     com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false);
   4822         }
   4823 
   4824         String str;
   4825         str = sa.getNonConfigurationString(
   4826                 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0);
   4827         if (str != null) {
   4828             a.info.permission = str.length() > 0 ? str.toString().intern() : null;
   4829         }
   4830 
   4831         String parentName = sa.getNonConfigurationString(
   4832                 com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName,
   4833                 Configuration.NATIVE_CONFIG_VERSION);
   4834         if (parentName != null) {
   4835             String parentClassName = buildClassName(a.info.packageName, parentName, outError);
   4836             if (outError[0] == null) {
   4837                 a.info.parentActivityName = parentClassName;
   4838             } else {
   4839                 Log.e(TAG, "Activity alias " + a.info.name +
   4840                         " specified invalid parentActivityName " + parentName);
   4841                 outError[0] = null;
   4842             }
   4843         }
   4844 
   4845         // TODO add visibleToInstantApps attribute to activity alias
   4846         final boolean visibleToEphemeral =
   4847                 ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0);
   4848 
   4849         sa.recycle();
   4850 
   4851         if (outError[0] != null) {
   4852             return null;
   4853         }
   4854 
   4855         int outerDepth = parser.getDepth();
   4856         int type;
   4857         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
   4858                && (type != XmlPullParser.END_TAG
   4859                        || parser.getDepth() > outerDepth)) {
   4860             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   4861                 continue;
   4862             }
   4863 
   4864             if (parser.getName().equals("intent-filter")) {
   4865                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
   4866                 if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
   4867                         intent, outError)) {
   4868                     return null;
   4869                 }
   4870                 if (intent.countActions() == 0) {
   4871                     Slog.w(TAG, "No actions in intent filter at "
   4872                             + mArchiveSourcePath + " "
   4873                             + parser.getPositionDescription());
   4874                 } else {
   4875                     a.intents.add(intent);
   4876                 }
   4877                 // adjust activity flags when we implicitly expose it via a browsable filter
   4878                 final int visibility = visibleToEphemeral
   4879                         ? IntentFilter.VISIBILITY_EXPLICIT
   4880                         : isImplicitlyExposedIntent(intent)
   4881                                 ? IntentFilter.VISIBILITY_IMPLICIT
   4882                                 : IntentFilter.VISIBILITY_NONE;
   4883                 intent.setVisibilityToInstantApp(visibility);
   4884                 if (intent.isVisibleToInstantApp()) {
   4885                     a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
   4886                 }
   4887                 if (intent.isImplicitlyVisibleToInstantApp()) {
   4888                     a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
   4889                 }
   4890             } else if (parser.getName().equals("meta-data")) {
   4891                 if ((a.metaData=parseMetaData(res, parser, a.metaData,
   4892                         outError)) == null) {
   4893                     return null;
   4894                 }
   4895             } else {
   4896                 if (!RIGID_PARSER) {
   4897                     Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName()
   4898                             + " at " + mArchiveSourcePath + " "
   4899                             + parser.getPositionDescription());
   4900                     XmlUtils.skipCurrentTag(parser);
   4901                     continue;
   4902                 } else {
   4903                     outError[0] = "Bad element under <activity-alias>: " + parser.getName();
   4904                     return null;
   4905                 }
   4906             }
   4907         }
   4908 
   4909         if (!setExported) {
   4910             a.info.exported = a.intents.size() > 0;
   4911         }
   4912 
   4913         return a;
   4914     }
   4915 
   4916     private Provider parseProvider(Package owner, Resources res,
   4917             XmlResourceParser parser, int flags, String[] outError,
   4918             CachedComponentArgs cachedArgs)
   4919             throws XmlPullParserException, IOException {
   4920         TypedArray sa = res.obtainAttributes(parser,
   4921                 com.android.internal.R.styleable.AndroidManifestProvider);
   4922 
   4923         if (cachedArgs.mProviderArgs == null) {
   4924             cachedArgs.mProviderArgs = new ParseComponentArgs(owner, outError,
   4925                     com.android.internal.R.styleable.AndroidManifestProvider_name,
   4926                     com.android.internal.R.styleable.AndroidManifestProvider_label,
   4927                     com.android.internal.R.styleable.AndroidManifestProvider_icon,
   4928                     com.android.internal.R.styleable.AndroidManifestProvider_roundIcon,
   4929                     com.android.internal.R.styleable.AndroidManifestProvider_logo,
   4930                     com.android.internal.R.styleable.AndroidManifestProvider_banner,
   4931                     mSeparateProcesses,
   4932                     com.android.internal.R.styleable.AndroidManifestProvider_process,
   4933                     com.android.internal.R.styleable.AndroidManifestProvider_description,
   4934                     com.android.internal.R.styleable.AndroidManifestProvider_enabled);
   4935             cachedArgs.mProviderArgs.tag = "<provider>";
   4936         }
   4937 
   4938         cachedArgs.mProviderArgs.sa = sa;
   4939         cachedArgs.mProviderArgs.flags = flags;
   4940 
   4941         Provider p = new Provider(cachedArgs.mProviderArgs, new ProviderInfo());
   4942         if (outError[0] != null) {
   4943             sa.recycle();
   4944             return null;
   4945         }
   4946 
   4947         boolean providerExportedDefault = false;
   4948 
   4949         if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
   4950             // For compatibility, applications targeting API level 16 or lower
   4951             // should have their content providers exported by default, unless they
   4952             // specify otherwise.
   4953             providerExportedDefault = true;
   4954         }
   4955 
   4956         p.info.exported = sa.getBoolean(
   4957                 com.android.internal.R.styleable.AndroidManifestProvider_exported,
   4958                 providerExportedDefault);
   4959 
   4960         String cpname = sa.getNonConfigurationString(
   4961                 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0);
   4962 
   4963         p.info.isSyncable = sa.getBoolean(
   4964                 com.android.internal.R.styleable.AndroidManifestProvider_syncable,
   4965                 false);
   4966 
   4967         String permission = sa.getNonConfigurationString(
   4968                 com.android.internal.R.styleable.AndroidManifestProvider_permission, 0);
   4969         String str = sa.getNonConfigurationString(
   4970                 com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0);
   4971         if (str == null) {
   4972             str = permission;
   4973         }
   4974         if (str == null) {
   4975             p.info.readPermission = owner.applicationInfo.permission;
   4976         } else {
   4977             p.info.readPermission =
   4978                 str.length() > 0 ? str.toString().intern() : null;
   4979         }
   4980         str = sa.getNonConfigurationString(
   4981                 com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0);
   4982         if (str == null) {
   4983             str = permission;
   4984         }
   4985         if (str == null) {
   4986             p.info.writePermission = owner.applicationInfo.permission;
   4987         } else {
   4988             p.info.writePermission =
   4989                 str.length() > 0 ? str.toString().intern() : null;
   4990         }
   4991 
   4992         p.info.grantUriPermissions = sa.getBoolean(
   4993                 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
   4994                 false);
   4995 
   4996         p.info.multiprocess = sa.getBoolean(
   4997                 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
   4998                 false);
   4999 
   5000         p.info.initOrder = sa.getInt(
   5001                 com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
   5002                 0);
   5003 
   5004         p.info.splitName =
   5005                 sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0);
   5006 
   5007         p.info.flags = 0;
   5008 
   5009         if (sa.getBoolean(
   5010                 com.android.internal.R.styleable.AndroidManifestProvider_singleUser,
   5011                 false)) {
   5012             p.info.flags |= ProviderInfo.FLAG_SINGLE_USER;
   5013             if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
   5014                 Slog.w(TAG, "Provider exported request ignored due to singleUser: "
   5015                         + p.className + " at " + mArchiveSourcePath + " "
   5016                         + parser.getPositionDescription());
   5017                 p.info.exported = false;
   5018             }
   5019         }
   5020 
   5021         p.info.encryptionAware = p.info.directBootAware = sa.getBoolean(
   5022                 R.styleable.AndroidManifestProvider_directBootAware,
   5023                 false);
   5024         if (p.info.directBootAware) {
   5025             owner.applicationInfo.privateFlags |=
   5026                     ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
   5027         }
   5028 
   5029         final boolean visibleToEphemeral =
   5030                 sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
   5031         if (visibleToEphemeral) {
   5032             p.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
   5033             owner.visibleToInstantApps = true;
   5034         }
   5035 
   5036         sa.recycle();
   5037 
   5038         if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
   5039                 != 0) {
   5040             // A heavy-weight application can not have providers in its main process
   5041             // We can do direct compare because we intern all strings.
   5042             if (p.info.processName == owner.packageName) {
   5043                 outError[0] = "Heavy-weight applications can not have providers in main process";
   5044                 return null;
   5045             }
   5046         }
   5047 
   5048         if (cpname == null) {
   5049             outError[0] = "<provider> does not include authorities attribute";
   5050             return null;
   5051         }
   5052         if (cpname.length() <= 0) {
   5053             outError[0] = "<provider> has empty authorities attribute";
   5054             return null;
   5055         }
   5056         p.info.authority = cpname.intern();
   5057 
   5058         if (!parseProviderTags(
   5059                 res, parser, visibleToEphemeral, owner, p, outError)) {
   5060             return null;
   5061         }
   5062 
   5063         return p;
   5064     }
   5065 
   5066     private boolean parseProviderTags(Resources res, XmlResourceParser parser,
   5067             boolean visibleToEphemeral, Package owner, Provider outInfo, String[] outError)
   5068                     throws XmlPullParserException, IOException {
   5069         int outerDepth = parser.getDepth();
   5070         int type;
   5071         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
   5072                && (type != XmlPullParser.END_TAG
   5073                        || parser.getDepth() > outerDepth)) {
   5074             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   5075                 continue;
   5076             }
   5077 
   5078             if (parser.getName().equals("intent-filter")) {
   5079                 ProviderIntentInfo intent = new ProviderIntentInfo(outInfo);
   5080                 if (!parseIntent(res, parser, true /*allowGlobs*/, false /*allowAutoVerify*/,
   5081                         intent, outError)) {
   5082                     return false;
   5083                 }
   5084                 if (visibleToEphemeral) {
   5085                     intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
   5086                     outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
   5087                 }
   5088                 outInfo.intents.add(intent);
   5089 
   5090             } else if (parser.getName().equals("meta-data")) {
   5091                 if ((outInfo.metaData=parseMetaData(res, parser,
   5092                         outInfo.metaData, outError)) == null) {
   5093                     return false;
   5094                 }
   5095                 // we don't have an attribute [or it's false], but, we have meta-data
   5096                 if (!visibleToEphemeral && outInfo.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
   5097                     visibleToEphemeral = true; // set in case there are more intent filters
   5098                     outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
   5099                     owner.visibleToInstantApps = true;
   5100                     // cycle through any filters already seen
   5101                     for (int i = outInfo.intents.size() - 1; i >= 0; --i) {
   5102                         outInfo.intents.get(i)
   5103                                 .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
   5104                     }
   5105                 }
   5106 
   5107             } else if (parser.getName().equals("grant-uri-permission")) {
   5108                 TypedArray sa = res.obtainAttributes(parser,
   5109                         com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
   5110 
   5111                 PatternMatcher pa = null;
   5112 
   5113                 String str = sa.getNonConfigurationString(
   5114                         com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0);
   5115                 if (str != null) {
   5116                     pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
   5117                 }
   5118 
   5119                 str = sa.getNonConfigurationString(
   5120                         com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
   5121                 if (str != null) {
   5122                     pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
   5123                 }
   5124 
   5125                 str = sa.getNonConfigurationString(
   5126                         com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
   5127                 if (str != null) {
   5128                     pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
   5129                 }
   5130 
   5131                 sa.recycle();
   5132 
   5133                 if (pa != null) {
   5134                     if (outInfo.info.uriPermissionPatterns == null) {
   5135                         outInfo.info.uriPermissionPatterns = new PatternMatcher[1];
   5136                         outInfo.info.uriPermissionPatterns[0] = pa;
   5137                     } else {
   5138                         final int N = outInfo.info.uriPermissionPatterns.length;
   5139                         PatternMatcher[] newp = new PatternMatcher[N+1];
   5140                         System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N);
   5141                         newp[N] = pa;
   5142                         outInfo.info.uriPermissionPatterns = newp;
   5143                     }
   5144                     outInfo.info.grantUriPermissions = true;
   5145                 } else {
   5146                     if (!RIGID_PARSER) {
   5147                         Slog.w(TAG, "Unknown element under <path-permission>: "
   5148                                 + parser.getName() + " at " + mArchiveSourcePath + " "
   5149                                 + parser.getPositionDescription());
   5150                         XmlUtils.skipCurrentTag(parser);
   5151                         continue;
   5152                     } else {
   5153                         outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
   5154                         return false;
   5155                     }
   5156                 }
   5157                 XmlUtils.skipCurrentTag(parser);
   5158 
   5159             } else if (parser.getName().equals("path-permission")) {
   5160                 TypedArray sa = res.obtainAttributes(parser,
   5161                         com.android.internal.R.styleable.AndroidManifestPathPermission);
   5162 
   5163                 PathPermission pa = null;
   5164 
   5165                 String permission = sa.getNonConfigurationString(
   5166                         com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0);
   5167                 String readPermission = sa.getNonConfigurationString(
   5168                         com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0);
   5169                 if (readPermission == null) {
   5170                     readPermission = permission;
   5171                 }
   5172                 String writePermission = sa.getNonConfigurationString(
   5173                         com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0);
   5174                 if (writePermission == null) {
   5175                     writePermission = permission;
   5176                 }
   5177 
   5178                 boolean havePerm = false;
   5179                 if (readPermission != null) {
   5180                     readPermission = readPermission.intern();
   5181                     havePerm = true;
   5182                 }
   5183                 if (writePermission != null) {
   5184                     writePermission = writePermission.intern();
   5185                     havePerm = true;
   5186                 }
   5187 
   5188                 if (!havePerm) {
   5189                     if (!RIGID_PARSER) {
   5190                         Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
   5191                                 + parser.getName() + " at " + mArchiveSourcePath + " "
   5192                                 + parser.getPositionDescription());
   5193                         XmlUtils.skipCurrentTag(parser);
   5194                         continue;
   5195                     } else {
   5196                         outError[0] = "No readPermission or writePermssion for <path-permission>";
   5197                         return false;
   5198                     }
   5199                 }
   5200 
   5201                 String path = sa.getNonConfigurationString(
   5202                         com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0);
   5203                 if (path != null) {
   5204                     pa = new PathPermission(path,
   5205                             PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
   5206                 }
   5207 
   5208                 path = sa.getNonConfigurationString(
   5209                         com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
   5210                 if (path != null) {
   5211                     pa = new PathPermission(path,
   5212                             PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
   5213                 }
   5214 
   5215                 path = sa.getNonConfigurationString(
   5216                         com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0);
   5217                 if (path != null) {
   5218                     pa = new PathPermission(path,
   5219                             PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
   5220                 }
   5221 
   5222                 path = sa.getNonConfigurationString(
   5223                         com.android.internal.R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0);
   5224                 if (path != null) {
   5225                     pa = new PathPermission(path,
   5226                             PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission);
   5227                 }
   5228 
   5229                 sa.recycle();
   5230 
   5231                 if (pa != null) {
   5232                     if (outInfo.info.pathPermissions == null) {
   5233                         outInfo.info.pathPermissions = new PathPermission[1];
   5234                         outInfo.info.pathPermissions[0] = pa;
   5235                     } else {
   5236                         final int N = outInfo.info.pathPermissions.length;
   5237                         PathPermission[] newp = new PathPermission[N+1];
   5238                         System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
   5239                         newp[N] = pa;
   5240                         outInfo.info.pathPermissions = newp;
   5241                     }
   5242                 } else {
   5243                     if (!RIGID_PARSER) {
   5244                         Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
   5245                                 + parser.getName() + " at " + mArchiveSourcePath + " "
   5246                                 + parser.getPositionDescription());
   5247                         XmlUtils.skipCurrentTag(parser);
   5248                         continue;
   5249                     }
   5250                     outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
   5251                     return false;
   5252                 }
   5253                 XmlUtils.skipCurrentTag(parser);
   5254 
   5255             } else {
   5256                 if (!RIGID_PARSER) {
   5257                     Slog.w(TAG, "Unknown element under <provider>: "
   5258                             + parser.getName() + " at " + mArchiveSourcePath + " "
   5259                             + parser.getPositionDescription());
   5260                     XmlUtils.skipCurrentTag(parser);
   5261                     continue;
   5262                 } else {
   5263                     outError[0] = "Bad element under <provider>: " + parser.getName();
   5264                     return false;
   5265                 }
   5266             }
   5267         }
   5268         return true;
   5269     }
   5270 
   5271     private Service parseService(Package owner, Resources res,
   5272             XmlResourceParser parser, int flags, String[] outError,
   5273             CachedComponentArgs cachedArgs)
   5274             throws XmlPullParserException, IOException {
   5275         TypedArray sa = res.obtainAttributes(parser,
   5276                 com.android.internal.R.styleable.AndroidManifestService);
   5277 
   5278         if (cachedArgs.mServiceArgs == null) {
   5279             cachedArgs.mServiceArgs = new ParseComponentArgs(owner, outError,
   5280                     com.android.internal.R.styleable.AndroidManifestService_name,
   5281                     com.android.internal.R.styleable.AndroidManifestService_label,
   5282                     com.android.internal.R.styleable.AndroidManifestService_icon,
   5283                     com.android.internal.R.styleable.AndroidManifestService_roundIcon,
   5284                     com.android.internal.R.styleable.AndroidManifestService_logo,
   5285                     com.android.internal.R.styleable.AndroidManifestService_banner,
   5286                     mSeparateProcesses,
   5287                     com.android.internal.R.styleable.AndroidManifestService_process,
   5288                     com.android.internal.R.styleable.AndroidManifestService_description,
   5289                     com.android.internal.R.styleable.AndroidManifestService_enabled);
   5290             cachedArgs.mServiceArgs.tag = "<service>";
   5291         }
   5292 
   5293         cachedArgs.mServiceArgs.sa = sa;
   5294         cachedArgs.mServiceArgs.flags = flags;
   5295 
   5296         Service s = new Service(cachedArgs.mServiceArgs, new ServiceInfo());
   5297         if (outError[0] != null) {
   5298             sa.recycle();
   5299             return null;
   5300         }
   5301 
   5302         boolean setExported = sa.hasValue(
   5303                 com.android.internal.R.styleable.AndroidManifestService_exported);
   5304         if (setExported) {
   5305             s.info.exported = sa.getBoolean(
   5306                     com.android.internal.R.styleable.AndroidManifestService_exported, false);
   5307         }
   5308 
   5309         String str = sa.getNonConfigurationString(
   5310                 com.android.internal.R.styleable.AndroidManifestService_permission, 0);
   5311         if (str == null) {
   5312             s.info.permission = owner.applicationInfo.permission;
   5313         } else {
   5314             s.info.permission = str.length() > 0 ? str.toString().intern() : null;
   5315         }
   5316 
   5317         s.info.splitName =
   5318                 sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0);
   5319 
   5320         s.info.flags = 0;
   5321         if (sa.getBoolean(
   5322                 com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
   5323                 false)) {
   5324             s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
   5325         }
   5326         if (sa.getBoolean(
   5327                 com.android.internal.R.styleable.AndroidManifestService_isolatedProcess,
   5328                 false)) {
   5329             s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
   5330         }
   5331         if (sa.getBoolean(
   5332                 com.android.internal.R.styleable.AndroidManifestService_externalService,
   5333                 false)) {
   5334             s.info.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
   5335         }
   5336         if (sa.getBoolean(
   5337                 com.android.internal.R.styleable.AndroidManifestService_singleUser,
   5338                 false)) {
   5339             s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
   5340             if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
   5341                 Slog.w(TAG, "Service exported request ignored due to singleUser: "
   5342                         + s.className + " at " + mArchiveSourcePath + " "
   5343                         + parser.getPositionDescription());
   5344                 s.info.exported = false;
   5345                 setExported = true;
   5346             }
   5347         }
   5348 
   5349         s.info.encryptionAware = s.info.directBootAware = sa.getBoolean(
   5350                 R.styleable.AndroidManifestService_directBootAware,
   5351                 false);
   5352         if (s.info.directBootAware) {
   5353             owner.applicationInfo.privateFlags |=
   5354                     ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
   5355         }
   5356 
   5357         boolean visibleToEphemeral =
   5358                 sa.getBoolean(R.styleable.AndroidManifestService_visibleToInstantApps, false);
   5359         if (visibleToEphemeral) {
   5360             s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
   5361             owner.visibleToInstantApps = true;
   5362         }
   5363 
   5364         sa.recycle();
   5365 
   5366         if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
   5367                 != 0) {
   5368             // A heavy-weight application can not have services in its main process
   5369             // We can do direct compare because we intern all strings.
   5370             if (s.info.processName == owner.packageName) {
   5371                 outError[0] = "Heavy-weight applications can not have services in main process";
   5372                 return null;
   5373             }
   5374         }
   5375 
   5376         int outerDepth = parser.getDepth();
   5377         int type;
   5378         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
   5379                && (type != XmlPullParser.END_TAG
   5380                        || parser.getDepth() > outerDepth)) {
   5381             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   5382                 continue;
   5383             }
   5384 
   5385             if (parser.getName().equals("intent-filter")) {
   5386                 ServiceIntentInfo intent = new ServiceIntentInfo(s);
   5387                 if (!parseIntent(res, parser, true /*allowGlobs*/, false /*allowAutoVerify*/,
   5388                         intent, outError)) {
   5389                     return null;
   5390                 }
   5391                 if (visibleToEphemeral) {
   5392                     intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
   5393                     s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
   5394                 }
   5395                 s.intents.add(intent);
   5396             } else if (parser.getName().equals("meta-data")) {
   5397                 if ((s.metaData=parseMetaData(res, parser, s.metaData,
   5398                         outError)) == null) {
   5399                     return null;
   5400                 }
   5401                 // we don't have an attribute [or it's false], but, we have meta-data
   5402                 if (!visibleToEphemeral && s.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
   5403                     visibleToEphemeral = true; // set in case there are more intent filters
   5404                     s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
   5405                     owner.visibleToInstantApps = true;
   5406                     // cycle through any filters already seen
   5407                     for (int i = s.intents.size() - 1; i >= 0; --i) {
   5408                         s.intents.get(i)
   5409                                 .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
   5410                     }
   5411                 }
   5412             } else {
   5413                 if (!RIGID_PARSER) {
   5414                     Slog.w(TAG, "Unknown element under <service>: "
   5415                             + parser.getName() + " at " + mArchiveSourcePath + " "
   5416                             + parser.getPositionDescription());
   5417                     XmlUtils.skipCurrentTag(parser);
   5418                     continue;
   5419                 } else {
   5420                     outError[0] = "Bad element under <service>: " + parser.getName();
   5421                     return null;
   5422                 }
   5423             }
   5424         }
   5425 
   5426         if (!setExported) {
   5427             s.info.exported = s.intents.size() > 0;
   5428         }
   5429 
   5430         return s;
   5431     }
   5432 
   5433     private boolean isImplicitlyExposedIntent(IntentInfo intent) {
   5434         return intent.hasCategory(Intent.CATEGORY_BROWSABLE)
   5435                 || intent.hasAction(Intent.ACTION_SEND)
   5436                 || intent.hasAction(Intent.ACTION_SENDTO)
   5437                 || intent.hasAction(Intent.ACTION_SEND_MULTIPLE);
   5438     }
   5439 
   5440     private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag,
   5441             Component<?> outInfo, String[] outError) throws XmlPullParserException, IOException {
   5442         int outerDepth = parser.getDepth();
   5443         int type;
   5444         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
   5445                && (type != XmlPullParser.END_TAG
   5446                        || parser.getDepth() > outerDepth)) {
   5447             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   5448                 continue;
   5449             }
   5450 
   5451             if (parser.getName().equals("meta-data")) {
   5452                 if ((outInfo.metaData=parseMetaData(res, parser,
   5453                         outInfo.metaData, outError)) == null) {
   5454                     return false;
   5455                 }
   5456             } else {
   5457                 if (!RIGID_PARSER) {
   5458                     Slog.w(TAG, "Unknown element under " + tag + ": "
   5459                             + parser.getName() + " at " + mArchiveSourcePath + " "
   5460                             + parser.getPositionDescription());
   5461                     XmlUtils.skipCurrentTag(parser);
   5462                     continue;
   5463                 } else {
   5464                     outError[0] = "Bad element under " + tag + ": " + parser.getName();
   5465                     return false;
   5466                 }
   5467             }
   5468         }
   5469         return true;
   5470     }
   5471 
   5472     private Bundle parseMetaData(Resources res,
   5473             XmlResourceParser parser, Bundle data, String[] outError)
   5474             throws XmlPullParserException, IOException {
   5475 
   5476         TypedArray sa = res.obtainAttributes(parser,
   5477                 com.android.internal.R.styleable.AndroidManifestMetaData);
   5478 
   5479         if (data == null) {
   5480             data = new Bundle();
   5481         }
   5482 
   5483         String name = sa.getNonConfigurationString(
   5484                 com.android.internal.R.styleable.AndroidManifestMetaData_name, 0);
   5485         if (name == null) {
   5486             outError[0] = "<meta-data> requires an android:name attribute";
   5487             sa.recycle();
   5488             return null;
   5489         }
   5490 
   5491         name = name.intern();
   5492 
   5493         TypedValue v = sa.peekValue(
   5494                 com.android.internal.R.styleable.AndroidManifestMetaData_resource);
   5495         if (v != null && v.resourceId != 0) {
   5496             //Slog.i(TAG, "Meta data ref " + name + ": " + v);
   5497             data.putInt(name, v.resourceId);
   5498         } else {
   5499             v = sa.peekValue(
   5500                     com.android.internal.R.styleable.AndroidManifestMetaData_value);
   5501             //Slog.i(TAG, "Meta data " + name + ": " + v);
   5502             if (v != null) {
   5503                 if (v.type == TypedValue.TYPE_STRING) {
   5504                     CharSequence cs = v.coerceToString();
   5505                     data.putString(name, cs != null ? cs.toString() : null);
   5506                 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
   5507                     data.putBoolean(name, v.data != 0);
   5508                 } else if (v.type >= TypedValue.TYPE_FIRST_INT
   5509                         && v.type <= TypedValue.TYPE_LAST_INT) {
   5510                     data.putInt(name, v.data);
   5511                 } else if (v.type == TypedValue.TYPE_FLOAT) {
   5512                     data.putFloat(name, v.getFloat());
   5513                 } else {
   5514                     if (!RIGID_PARSER) {
   5515                         Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: "
   5516                                 + parser.getName() + " at " + mArchiveSourcePath + " "
   5517                                 + parser.getPositionDescription());
   5518                     } else {
   5519                         outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types";
   5520                         data = null;
   5521                     }
   5522                 }
   5523             } else {
   5524                 outError[0] = "<meta-data> requires an android:value or android:resource attribute";
   5525                 data = null;
   5526             }
   5527         }
   5528 
   5529         sa.recycle();
   5530 
   5531         XmlUtils.skipCurrentTag(parser);
   5532 
   5533         return data;
   5534     }
   5535 
   5536     private static VerifierInfo parseVerifier(AttributeSet attrs) {
   5537         String packageName = null;
   5538         String encodedPublicKey = null;
   5539 
   5540         final int attrCount = attrs.getAttributeCount();
   5541         for (int i = 0; i < attrCount; i++) {
   5542             final int attrResId = attrs.getAttributeNameResource(i);
   5543             switch (attrResId) {
   5544                 case com.android.internal.R.attr.name:
   5545                     packageName = attrs.getAttributeValue(i);
   5546                     break;
   5547 
   5548                 case com.android.internal.R.attr.publicKey:
   5549                     encodedPublicKey = attrs.getAttributeValue(i);
   5550                     break;
   5551             }
   5552         }
   5553 
   5554         if (packageName == null || packageName.length() == 0) {
   5555             Slog.i(TAG, "verifier package name was null; skipping");
   5556             return null;
   5557         }
   5558 
   5559         final PublicKey publicKey = parsePublicKey(encodedPublicKey);
   5560         if (publicKey == null) {
   5561             Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
   5562             return null;
   5563         }
   5564 
   5565         return new VerifierInfo(packageName, publicKey);
   5566     }
   5567 
   5568     public static final PublicKey parsePublicKey(final String encodedPublicKey) {
   5569         if (encodedPublicKey == null) {
   5570             Slog.w(TAG, "Could not parse null public key");
   5571             return null;
   5572         }
   5573 
   5574         EncodedKeySpec keySpec;
   5575         try {
   5576             final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT);
   5577             keySpec = new X509EncodedKeySpec(encoded);
   5578         } catch (IllegalArgumentException e) {
   5579             Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
   5580             return null;
   5581         }
   5582 
   5583         /* First try the key as an RSA key. */
   5584         try {
   5585             final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
   5586             return keyFactory.generatePublic(keySpec);
   5587         } catch (NoSuchAlgorithmException e) {
   5588             Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build");
   5589         } catch (InvalidKeySpecException e) {
   5590             // Not a RSA public key.
   5591         }
   5592 
   5593         /* Now try it as a ECDSA key. */
   5594         try {
   5595             final KeyFactory keyFactory = KeyFactory.getInstance("EC");
   5596             return keyFactory.generatePublic(keySpec);
   5597         } catch (NoSuchAlgorithmException e) {
   5598             Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build");
   5599         } catch (InvalidKeySpecException e) {
   5600             // Not a ECDSA public key.
   5601         }
   5602 
   5603         /* Now try it as a DSA key. */
   5604         try {
   5605             final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
   5606             return keyFactory.generatePublic(keySpec);
   5607         } catch (NoSuchAlgorithmException e) {
   5608             Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build");
   5609         } catch (InvalidKeySpecException e) {
   5610             // Not a DSA public key.
   5611         }
   5612 
   5613         /* Not a supported key type */
   5614         return null;
   5615     }
   5616 
   5617     private static final String ANDROID_RESOURCES
   5618             = "http://schemas.android.com/apk/res/android";
   5619 
   5620     private boolean parseIntent(Resources res, XmlResourceParser parser, boolean allowGlobs,
   5621             boolean allowAutoVerify, IntentInfo outInfo, String[] outError)
   5622                     throws XmlPullParserException, IOException {
   5623 
   5624         TypedArray sa = res.obtainAttributes(parser,
   5625                 com.android.internal.R.styleable.AndroidManifestIntentFilter);
   5626 
   5627         int priority = sa.getInt(
   5628                 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
   5629         outInfo.setPriority(priority);
   5630 
   5631         TypedValue v = sa.peekValue(
   5632                 com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
   5633         if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
   5634             outInfo.nonLocalizedLabel = v.coerceToString();
   5635         }
   5636 
   5637         final boolean useRoundIcon =
   5638                 Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
   5639         int roundIconVal = useRoundIcon ? sa.getResourceId(
   5640                 com.android.internal.R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0;
   5641         if (roundIconVal != 0) {
   5642             outInfo.icon = roundIconVal;
   5643         } else {
   5644             outInfo.icon = sa.getResourceId(
   5645                     com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
   5646         }
   5647 
   5648         outInfo.logo = sa.getResourceId(
   5649                 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
   5650 
   5651         outInfo.banner = sa.getResourceId(
   5652                 com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0);
   5653 
   5654         if (allowAutoVerify) {
   5655             outInfo.setAutoVerify(sa.getBoolean(
   5656                     com.android.internal.R.styleable.AndroidManifestIntentFilter_autoVerify,
   5657                     false));
   5658         }
   5659 
   5660         sa.recycle();
   5661 
   5662         int outerDepth = parser.getDepth();
   5663         int type;
   5664         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
   5665                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
   5666             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   5667                 continue;
   5668             }
   5669 
   5670             String nodeName = parser.getName();
   5671             if (nodeName.equals("action")) {
   5672                 String value = parser.getAttributeValue(
   5673                         ANDROID_RESOURCES, "name");
   5674                 if (value == null || value == "") {
   5675                     outError[0] = "No value supplied for <android:name>";
   5676                     return false;
   5677                 }
   5678                 XmlUtils.skipCurrentTag(parser);
   5679 
   5680                 outInfo.addAction(value);
   5681             } else if (nodeName.equals("category")) {
   5682                 String value = parser.getAttributeValue(
   5683                         ANDROID_RESOURCES, "name");
   5684                 if (value == null || value == "") {
   5685                     outError[0] = "No value supplied for <android:name>";
   5686                     return false;
   5687                 }
   5688                 XmlUtils.skipCurrentTag(parser);
   5689 
   5690                 outInfo.addCategory(value);
   5691 
   5692             } else if (nodeName.equals("data")) {
   5693                 sa = res.obtainAttributes(parser,
   5694                         com.android.internal.R.styleable.AndroidManifestData);
   5695 
   5696                 String str = sa.getNonConfigurationString(
   5697                         com.android.internal.R.styleable.AndroidManifestData_mimeType, 0);
   5698                 if (str != null) {
   5699                     try {
   5700                         outInfo.addDataType(str);
   5701                     } catch (IntentFilter.MalformedMimeTypeException e) {
   5702                         outError[0] = e.toString();
   5703                         sa.recycle();
   5704                         return false;
   5705                     }
   5706                 }
   5707 
   5708                 str = sa.getNonConfigurationString(
   5709                         com.android.internal.R.styleable.AndroidManifestData_scheme, 0);
   5710                 if (str != null) {
   5711                     outInfo.addDataScheme(str);
   5712                 }
   5713 
   5714                 str = sa.getNonConfigurationString(
   5715                         com.android.internal.R.styleable.AndroidManifestData_ssp, 0);
   5716                 if (str != null) {
   5717                     outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
   5718                 }
   5719 
   5720                 str = sa.getNonConfigurationString(
   5721                         com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0);
   5722                 if (str != null) {
   5723                     outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
   5724                 }
   5725 
   5726                 str = sa.getNonConfigurationString(
   5727                         com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0);
   5728                 if (str != null) {
   5729                     if (!allowGlobs) {
   5730                         outError[0] = "sspPattern not allowed here; ssp must be literal";
   5731                         return false;
   5732                     }
   5733                     outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
   5734                 }
   5735 
   5736                 String host = sa.getNonConfigurationString(
   5737                         com.android.internal.R.styleable.AndroidManifestData_host, 0);
   5738                 String port = sa.getNonConfigurationString(
   5739                         com.android.internal.R.styleable.AndroidManifestData_port, 0);
   5740                 if (host != null) {
   5741                     outInfo.addDataAuthority(host, port);
   5742                 }
   5743 
   5744                 str = sa.getNonConfigurationString(
   5745                         com.android.internal.R.styleable.AndroidManifestData_path, 0);
   5746                 if (str != null) {
   5747                     outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
   5748                 }
   5749 
   5750                 str = sa.getNonConfigurationString(
   5751                         com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0);
   5752                 if (str != null) {
   5753                     outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
   5754                 }
   5755 
   5756                 str = sa.getNonConfigurationString(
   5757                         com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
   5758                 if (str != null) {
   5759                     if (!allowGlobs) {
   5760                         outError[0] = "pathPattern not allowed here; path must be literal";
   5761                         return false;
   5762                     }
   5763                     outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
   5764                 }
   5765 
   5766                 str = sa.getNonConfigurationString(
   5767                         com.android.internal.R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
   5768                 if (str != null) {
   5769                     if (!allowGlobs) {
   5770                         outError[0] = "pathAdvancedPattern not allowed here; path must be literal";
   5771                         return false;
   5772                     }
   5773                     outInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB);
   5774                 }
   5775 
   5776                 sa.recycle();
   5777                 XmlUtils.skipCurrentTag(parser);
   5778             } else if (!RIGID_PARSER) {
   5779                 Slog.w(TAG, "Unknown element under <intent-filter>: "
   5780                         + parser.getName() + " at " + mArchiveSourcePath + " "
   5781                         + parser.getPositionDescription());
   5782                 XmlUtils.skipCurrentTag(parser);
   5783             } else {
   5784                 outError[0] = "Bad element under <intent-filter>: " + parser.getName();
   5785                 return false;
   5786             }
   5787         }
   5788 
   5789         outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
   5790 
   5791         if (DEBUG_PARSER) {
   5792             final StringBuilder cats = new StringBuilder("Intent d=");
   5793             cats.append(outInfo.hasDefault);
   5794             cats.append(", cat=");
   5795 
   5796             final Iterator<String> it = outInfo.categoriesIterator();
   5797             if (it != null) {
   5798                 while (it.hasNext()) {
   5799                     cats.append(' ');
   5800                     cats.append(it.next());
   5801                 }
   5802             }
   5803             Slog.d(TAG, cats.toString());
   5804         }
   5805 
   5806         return true;
   5807     }
   5808 
   5809     /**
   5810      * Representation of a full package parsed from APK files on disk. A package
   5811      * consists of a single base APK, and zero or more split APKs.
   5812      */
   5813     public final static class Package implements Parcelable {
   5814 
   5815         public String packageName;
   5816 
   5817         // The package name declared in the manifest as the package can be
   5818         // renamed, for example static shared libs use synthetic package names.
   5819         public String manifestPackageName;
   5820 
   5821         /** Names of any split APKs, ordered by parsed splitName */
   5822         public String[] splitNames;
   5823 
   5824         // TODO: work towards making these paths invariant
   5825 
   5826         public String volumeUuid;
   5827 
   5828         /**
   5829          * Path where this package was found on disk. For monolithic packages
   5830          * this is path to single base APK file; for cluster packages this is
   5831          * path to the cluster directory.
   5832          */
   5833         public String codePath;
   5834 
   5835         /** Path of base APK */
   5836         public String baseCodePath;
   5837         /** Paths of any split APKs, ordered by parsed splitName */
   5838         public String[] splitCodePaths;
   5839 
   5840         /** Revision code of base APK */
   5841         public int baseRevisionCode;
   5842         /** Revision codes of any split APKs, ordered by parsed splitName */
   5843         public int[] splitRevisionCodes;
   5844 
   5845         /** Flags of any split APKs; ordered by parsed splitName */
   5846         public int[] splitFlags;
   5847 
   5848         /**
   5849          * Private flags of any split APKs; ordered by parsed splitName.
   5850          *
   5851          * {@hide}
   5852          */
   5853         public int[] splitPrivateFlags;
   5854 
   5855         public boolean baseHardwareAccelerated;
   5856 
   5857         // For now we only support one application per package.
   5858         public ApplicationInfo applicationInfo = new ApplicationInfo();
   5859 
   5860         public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
   5861         public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
   5862         public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
   5863         public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
   5864         public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
   5865         public final ArrayList<Service> services = new ArrayList<Service>(0);
   5866         public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
   5867 
   5868         public final ArrayList<String> requestedPermissions = new ArrayList<String>();
   5869 
   5870         public ArrayList<String> protectedBroadcasts;
   5871 
   5872         public Package parentPackage;
   5873         public ArrayList<Package> childPackages;
   5874 
   5875         public String staticSharedLibName = null;
   5876         public int staticSharedLibVersion = 0;
   5877         public ArrayList<String> libraryNames = null;
   5878         public ArrayList<String> usesLibraries = null;
   5879         public ArrayList<String> usesStaticLibraries = null;
   5880         public int[] usesStaticLibrariesVersions = null;
   5881         public String[][] usesStaticLibrariesCertDigests = null;
   5882         public ArrayList<String> usesOptionalLibraries = null;
   5883         public String[] usesLibraryFiles = null;
   5884 
   5885         public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
   5886 
   5887         public ArrayList<String> mOriginalPackages = null;
   5888         public String mRealPackage = null;
   5889         public ArrayList<String> mAdoptPermissions = null;
   5890 
   5891         // We store the application meta-data independently to avoid multiple unwanted references
   5892         public Bundle mAppMetaData = null;
   5893 
   5894         // The version code declared for this package.
   5895         public int mVersionCode;
   5896 
   5897         // The version name declared for this package.
   5898         public String mVersionName;
   5899 
   5900         // The shared user id that this package wants to use.
   5901         public String mSharedUserId;
   5902 
   5903         // The shared user label that this package wants to use.
   5904         public int mSharedUserLabel;
   5905 
   5906         // Signatures that were read from the package.
   5907         public Signature[] mSignatures;
   5908         public Certificate[][] mCertificates;
   5909 
   5910         // For use by package manager service for quick lookup of
   5911         // preferred up order.
   5912         public int mPreferredOrder = 0;
   5913 
   5914         // For use by package manager to keep track of when a package was last used.
   5915         public long[] mLastPackageUsageTimeInMills =
   5916                 new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];
   5917 
   5918         // // User set enabled state.
   5919         // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
   5920         //
   5921         // // Whether the package has been stopped.
   5922         // public boolean mSetStopped = false;
   5923 
   5924         // Additional data supplied by callers.
   5925         public Object mExtras;
   5926 
   5927         // Applications hardware preferences
   5928         public ArrayList<ConfigurationInfo> configPreferences = null;
   5929 
   5930         // Applications requested features
   5931         public ArrayList<FeatureInfo> reqFeatures = null;
   5932 
   5933         // Applications requested feature groups
   5934         public ArrayList<FeatureGroupInfo> featureGroups = null;
   5935 
   5936         public int installLocation;
   5937 
   5938         public boolean coreApp;
   5939 
   5940         /* An app that's required for all users and cannot be uninstalled for a user */
   5941         public boolean mRequiredForAllUsers;
   5942 
   5943         /* The restricted account authenticator type that is used by this application */
   5944         public String mRestrictedAccountType;
   5945 
   5946         /* The required account type without which this application will not function */
   5947         public String mRequiredAccountType;
   5948 
   5949         public String mOverlayTarget;
   5950         public int mOverlayPriority;
   5951         public boolean mIsStaticOverlay;
   5952         public boolean mTrustedOverlay;
   5953 
   5954         /**
   5955          * Data used to feed the KeySetManagerService
   5956          */
   5957         public ArraySet<PublicKey> mSigningKeys;
   5958         public ArraySet<String> mUpgradeKeySets;
   5959         public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
   5960 
   5961         /**
   5962          * The install time abi override for this package, if any.
   5963          *
   5964          * TODO: This seems like a horrible place to put the abiOverride because
   5965          * this isn't something the packageParser parsers. However, this fits in with
   5966          * the rest of the PackageManager where package scanning randomly pushes
   5967          * and prods fields out of {@code this.applicationInfo}.
   5968          */
   5969         public String cpuAbiOverride;
   5970         /**
   5971          * The install time abi override to choose 32bit abi's when multiple abi's
   5972          * are present. This is only meaningfull for multiarch applications.
   5973          * The use32bitAbi attribute is ignored if cpuAbiOverride is also set.
   5974          */
   5975         public boolean use32bitAbi;
   5976 
   5977         public byte[] restrictUpdateHash;
   5978 
   5979         /** Set if the app or any of its components are visible to instant applications. */
   5980         public boolean visibleToInstantApps;
   5981         /** Whether or not the package is a stub and must be replaced by the full version. */
   5982         public boolean isStub;
   5983 
   5984         public Package(String packageName) {
   5985             this.packageName = packageName;
   5986             this.manifestPackageName = packageName;
   5987             applicationInfo.packageName = packageName;
   5988             applicationInfo.uid = -1;
   5989         }
   5990 
   5991         public void setApplicationVolumeUuid(String volumeUuid) {
   5992             final UUID storageUuid = StorageManager.convert(volumeUuid);
   5993             this.applicationInfo.volumeUuid = volumeUuid;
   5994             this.applicationInfo.storageUuid = storageUuid;
   5995             if (childPackages != null) {
   5996                 final int packageCount = childPackages.size();
   5997                 for (int i = 0; i < packageCount; i++) {
   5998                     childPackages.get(i).applicationInfo.volumeUuid = volumeUuid;
   5999                     childPackages.get(i).applicationInfo.storageUuid = storageUuid;
   6000                 }
   6001             }
   6002         }
   6003 
   6004         public void setApplicationInfoCodePath(String codePath) {
   6005             this.applicationInfo.setCodePath(codePath);
   6006             if (childPackages != null) {
   6007                 final int packageCount = childPackages.size();
   6008                 for (int i = 0; i < packageCount; i++) {
   6009                     childPackages.get(i).applicationInfo.setCodePath(codePath);
   6010                 }
   6011             }
   6012         }
   6013 
   6014         public void setApplicationInfoResourcePath(String resourcePath) {
   6015             this.applicationInfo.setResourcePath(resourcePath);
   6016             if (childPackages != null) {
   6017                 final int packageCount = childPackages.size();
   6018                 for (int i = 0; i < packageCount; i++) {
   6019                     childPackages.get(i).applicationInfo.setResourcePath(resourcePath);
   6020                 }
   6021             }
   6022         }
   6023 
   6024         public void setApplicationInfoBaseResourcePath(String resourcePath) {
   6025             this.applicationInfo.setBaseResourcePath(resourcePath);
   6026             if (childPackages != null) {
   6027                 final int packageCount = childPackages.size();
   6028                 for (int i = 0; i < packageCount; i++) {
   6029                     childPackages.get(i).applicationInfo.setBaseResourcePath(resourcePath);
   6030                 }
   6031             }
   6032         }
   6033 
   6034         public void setApplicationInfoBaseCodePath(String baseCodePath) {
   6035             this.applicationInfo.setBaseCodePath(baseCodePath);
   6036             if (childPackages != null) {
   6037                 final int packageCount = childPackages.size();
   6038                 for (int i = 0; i < packageCount; i++) {
   6039                     childPackages.get(i).applicationInfo.setBaseCodePath(baseCodePath);
   6040                 }
   6041             }
   6042         }
   6043 
   6044         public List<String> getChildPackageNames() {
   6045             if (childPackages == null) {
   6046                 return null;
   6047             }
   6048             final int childCount = childPackages.size();
   6049             final List<String> childPackageNames = new ArrayList<>(childCount);
   6050             for (int i = 0; i < childCount; i++) {
   6051                 String childPackageName = childPackages.get(i).packageName;
   6052                 childPackageNames.add(childPackageName);
   6053             }
   6054             return childPackageNames;
   6055         }
   6056 
   6057         public boolean hasChildPackage(String packageName) {
   6058             final int childCount = (childPackages != null) ? childPackages.size() : 0;
   6059             for (int i = 0; i < childCount; i++) {
   6060                 if (childPackages.get(i).packageName.equals(packageName)) {
   6061                     return true;
   6062                 }
   6063             }
   6064             return false;
   6065         }
   6066 
   6067         public void setApplicationInfoSplitCodePaths(String[] splitCodePaths) {
   6068             this.applicationInfo.setSplitCodePaths(splitCodePaths);
   6069             // Children have no splits
   6070         }
   6071 
   6072         public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) {
   6073             this.applicationInfo.setSplitResourcePaths(resroucePaths);
   6074             // Children have no splits
   6075         }
   6076 
   6077         public void setSplitCodePaths(String[] codePaths) {
   6078             this.splitCodePaths = codePaths;
   6079         }
   6080 
   6081         public void setCodePath(String codePath) {
   6082             this.codePath = codePath;
   6083             if (childPackages != null) {
   6084                 final int packageCount = childPackages.size();
   6085                 for (int i = 0; i < packageCount; i++) {
   6086                     childPackages.get(i).codePath = codePath;
   6087                 }
   6088             }
   6089         }
   6090 
   6091         public void setBaseCodePath(String baseCodePath) {
   6092             this.baseCodePath = baseCodePath;
   6093             if (childPackages != null) {
   6094                 final int packageCount = childPackages.size();
   6095                 for (int i = 0; i < packageCount; i++) {
   6096                     childPackages.get(i).baseCodePath = baseCodePath;
   6097                 }
   6098             }
   6099         }
   6100 
   6101         public void setSignatures(Signature[] signatures) {
   6102             this.mSignatures = signatures;
   6103             if (childPackages != null) {
   6104                 final int packageCount = childPackages.size();
   6105                 for (int i = 0; i < packageCount; i++) {
   6106                     childPackages.get(i).mSignatures = signatures;
   6107                 }
   6108             }
   6109         }
   6110 
   6111         public void setVolumeUuid(String volumeUuid) {
   6112             this.volumeUuid = volumeUuid;
   6113             if (childPackages != null) {
   6114                 final int packageCount = childPackages.size();
   6115                 for (int i = 0; i < packageCount; i++) {
   6116                     childPackages.get(i).volumeUuid = volumeUuid;
   6117                 }
   6118             }
   6119         }
   6120 
   6121         public void setApplicationInfoFlags(int mask, int flags) {
   6122             applicationInfo.flags = (applicationInfo.flags & ~mask) | (mask & flags);
   6123             if (childPackages != null) {
   6124                 final int packageCount = childPackages.size();
   6125                 for (int i = 0; i < packageCount; i++) {
   6126                     childPackages.get(i).applicationInfo.flags =
   6127                             (applicationInfo.flags & ~mask) | (mask & flags);
   6128                 }
   6129             }
   6130         }
   6131 
   6132         public void setUse32bitAbi(boolean use32bitAbi) {
   6133             this.use32bitAbi = use32bitAbi;
   6134             if (childPackages != null) {
   6135                 final int packageCount = childPackages.size();
   6136                 for (int i = 0; i < packageCount; i++) {
   6137                     childPackages.get(i).use32bitAbi = use32bitAbi;
   6138                 }
   6139             }
   6140         }
   6141 
   6142         public boolean isLibrary() {
   6143             return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames);
   6144         }
   6145 
   6146         public List<String> getAllCodePaths() {
   6147             ArrayList<String> paths = new ArrayList<>();
   6148             paths.add(baseCodePath);
   6149             if (!ArrayUtils.isEmpty(splitCodePaths)) {
   6150                 Collections.addAll(paths, splitCodePaths);
   6151             }
   6152             return paths;
   6153         }
   6154 
   6155         /**
   6156          * Filtered set of {@link #getAllCodePaths()} that excludes
   6157          * resource-only APKs.
   6158          */
   6159         public List<String> getAllCodePathsExcludingResourceOnly() {
   6160             ArrayList<String> paths = new ArrayList<>();
   6161             if ((applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
   6162                 paths.add(baseCodePath);
   6163             }
   6164             if (!ArrayUtils.isEmpty(splitCodePaths)) {
   6165                 for (int i = 0; i < splitCodePaths.length; i++) {
   6166                     if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
   6167                         paths.add(splitCodePaths[i]);
   6168                     }
   6169                 }
   6170             }
   6171             return paths;
   6172         }
   6173 
   6174         public void setPackageName(String newName) {
   6175             packageName = newName;
   6176             applicationInfo.packageName = newName;
   6177             for (int i=permissions.size()-1; i>=0; i--) {
   6178                 permissions.get(i).setPackageName(newName);
   6179             }
   6180             for (int i=permissionGroups.size()-1; i>=0; i--) {
   6181                 permissionGroups.get(i).setPackageName(newName);
   6182             }
   6183             for (int i=activities.size()-1; i>=0; i--) {
   6184                 activities.get(i).setPackageName(newName);
   6185             }
   6186             for (int i=receivers.size()-1; i>=0; i--) {
   6187                 receivers.get(i).setPackageName(newName);
   6188             }
   6189             for (int i=providers.size()-1; i>=0; i--) {
   6190                 providers.get(i).setPackageName(newName);
   6191             }
   6192             for (int i=services.size()-1; i>=0; i--) {
   6193                 services.get(i).setPackageName(newName);
   6194             }
   6195             for (int i=instrumentation.size()-1; i>=0; i--) {
   6196                 instrumentation.get(i).setPackageName(newName);
   6197             }
   6198         }
   6199 
   6200         public boolean hasComponentClassName(String name) {
   6201             for (int i=activities.size()-1; i>=0; i--) {
   6202                 if (name.equals(activities.get(i).className)) {
   6203                     return true;
   6204                 }
   6205             }
   6206             for (int i=receivers.size()-1; i>=0; i--) {
   6207                 if (name.equals(receivers.get(i).className)) {
   6208                     return true;
   6209                 }
   6210             }
   6211             for (int i=providers.size()-1; i>=0; i--) {
   6212                 if (name.equals(providers.get(i).className)) {
   6213                     return true;
   6214                 }
   6215             }
   6216             for (int i=services.size()-1; i>=0; i--) {
   6217                 if (name.equals(services.get(i).className)) {
   6218                     return true;
   6219                 }
   6220             }
   6221             for (int i=instrumentation.size()-1; i>=0; i--) {
   6222                 if (name.equals(instrumentation.get(i).className)) {
   6223                     return true;
   6224                 }
   6225             }
   6226             return false;
   6227         }
   6228 
   6229         /**
   6230          * @hide
   6231          */
   6232         public boolean isForwardLocked() {
   6233             return applicationInfo.isForwardLocked();
   6234         }
   6235 
   6236         /**
   6237          * @hide
   6238          */
   6239         public boolean isSystemApp() {
   6240             return applicationInfo.isSystemApp();
   6241         }
   6242 
   6243         /**
   6244          * @hide
   6245          */
   6246         public boolean isPrivilegedApp() {
   6247             return applicationInfo.isPrivilegedApp();
   6248         }
   6249 
   6250         /**
   6251          * @hide
   6252          */
   6253         public boolean isUpdatedSystemApp() {
   6254             return applicationInfo.isUpdatedSystemApp();
   6255         }
   6256 
   6257         /**
   6258          * @hide
   6259          */
   6260         public boolean canHaveOatDir() {
   6261             // The following app types CANNOT have oat directory
   6262             // - non-updated system apps
   6263             // - forward-locked apps or apps installed in ASEC containers
   6264             return (!isSystemApp() || isUpdatedSystemApp())
   6265                     && !isForwardLocked() && !applicationInfo.isExternalAsec();
   6266         }
   6267 
   6268         public boolean isMatch(int flags) {
   6269             if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
   6270                 return isSystemApp();
   6271             }
   6272             return true;
   6273         }
   6274 
   6275         public long getLatestPackageUseTimeInMills() {
   6276             long latestUse = 0L;
   6277             for (long use : mLastPackageUsageTimeInMills) {
   6278                 latestUse = Math.max(latestUse, use);
   6279             }
   6280             return latestUse;
   6281         }
   6282 
   6283         public long getLatestForegroundPackageUseTimeInMills() {
   6284             int[] foregroundReasons = {
   6285                 PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY,
   6286                 PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE
   6287             };
   6288 
   6289             long latestUse = 0L;
   6290             for (int reason : foregroundReasons) {
   6291                 latestUse = Math.max(latestUse, mLastPackageUsageTimeInMills[reason]);
   6292             }
   6293             return latestUse;
   6294         }
   6295 
   6296         public String toString() {
   6297             return "Package{"
   6298                 + Integer.toHexString(System.identityHashCode(this))
   6299                 + " " + packageName + "}";
   6300         }
   6301 
   6302         @Override
   6303         public int describeContents() {
   6304             return 0;
   6305         }
   6306 
   6307         public Package(Parcel dest) {
   6308             // We use the boot classloader for all classes that we load.
   6309             final ClassLoader boot = Object.class.getClassLoader();
   6310 
   6311             packageName = dest.readString().intern();
   6312             manifestPackageName = dest.readString();
   6313             splitNames = dest.readStringArray();
   6314             volumeUuid = dest.readString();
   6315             codePath = dest.readString();
   6316             baseCodePath = dest.readString();
   6317             splitCodePaths = dest.readStringArray();
   6318             baseRevisionCode = dest.readInt();
   6319             splitRevisionCodes = dest.createIntArray();
   6320             splitFlags = dest.createIntArray();
   6321             splitPrivateFlags = dest.createIntArray();
   6322             baseHardwareAccelerated = (dest.readInt() == 1);
   6323             applicationInfo = dest.readParcelable(boot);
   6324             if (applicationInfo.permission != null) {
   6325                 applicationInfo.permission = applicationInfo.permission.intern();
   6326             }
   6327 
   6328             // We don't serialize the "owner" package and the application info object for each of
   6329             // these components, in order to save space and to avoid circular dependencies while
   6330             // serialization. We need to fix them all up here.
   6331             dest.readParcelableList(permissions, boot);
   6332             fixupOwner(permissions);
   6333             dest.readParcelableList(permissionGroups, boot);
   6334             fixupOwner(permissionGroups);
   6335             dest.readParcelableList(activities, boot);
   6336             fixupOwner(activities);
   6337             dest.readParcelableList(receivers, boot);
   6338             fixupOwner(receivers);
   6339             dest.readParcelableList(providers, boot);
   6340             fixupOwner(providers);
   6341             dest.readParcelableList(services, boot);
   6342             fixupOwner(services);
   6343             dest.readParcelableList(instrumentation, boot);
   6344             fixupOwner(instrumentation);
   6345 
   6346             dest.readStringList(requestedPermissions);
   6347             internStringArrayList(requestedPermissions);
   6348             protectedBroadcasts = dest.createStringArrayList();
   6349             internStringArrayList(protectedBroadcasts);
   6350 
   6351             parentPackage = dest.readParcelable(boot);
   6352 
   6353             childPackages = new ArrayList<>();
   6354             dest.readParcelableList(childPackages, boot);
   6355             if (childPackages.size() == 0) {
   6356                 childPackages = null;
   6357             }
   6358 
   6359             staticSharedLibName = dest.readString();
   6360             if (staticSharedLibName != null) {
   6361                 staticSharedLibName = staticSharedLibName.intern();
   6362             }
   6363             staticSharedLibVersion = dest.readInt();
   6364             libraryNames = dest.createStringArrayList();
   6365             internStringArrayList(libraryNames);
   6366             usesLibraries = dest.createStringArrayList();
   6367             internStringArrayList(usesLibraries);
   6368             usesOptionalLibraries = dest.createStringArrayList();
   6369             internStringArrayList(usesOptionalLibraries);
   6370             usesLibraryFiles = dest.readStringArray();
   6371 
   6372             final int libCount = dest.readInt();
   6373             if (libCount > 0) {
   6374                 usesStaticLibraries = new ArrayList<>(libCount);
   6375                 dest.readStringList(usesStaticLibraries);
   6376                 internStringArrayList(usesStaticLibraries);
   6377                 usesStaticLibrariesVersions = new int[libCount];
   6378                 dest.readIntArray(usesStaticLibrariesVersions);
   6379                 usesStaticLibrariesCertDigests = new String[libCount][];
   6380                 for (int i = 0; i < libCount; i++) {
   6381                     usesStaticLibrariesCertDigests[i] = dest.createStringArray();
   6382                 }
   6383             }
   6384 
   6385             preferredActivityFilters = new ArrayList<>();
   6386             dest.readParcelableList(preferredActivityFilters, boot);
   6387             if (preferredActivityFilters.size() == 0) {
   6388                 preferredActivityFilters = null;
   6389             }
   6390 
   6391             mOriginalPackages = dest.createStringArrayList();
   6392             mRealPackage = dest.readString();
   6393             mAdoptPermissions = dest.createStringArrayList();
   6394             mAppMetaData = dest.readBundle();
   6395             mVersionCode = dest.readInt();
   6396             mVersionName = dest.readString();
   6397             if (mVersionName != null) {
   6398                 mVersionName = mVersionName.intern();
   6399             }
   6400             mSharedUserId = dest.readString();
   6401             if (mSharedUserId != null) {
   6402                 mSharedUserId = mSharedUserId.intern();
   6403             }
   6404             mSharedUserLabel = dest.readInt();
   6405 
   6406             mSignatures = (Signature[]) dest.readParcelableArray(boot, Signature.class);
   6407             mCertificates = (Certificate[][]) dest.readSerializable();
   6408 
   6409             mPreferredOrder = dest.readInt();
   6410 
   6411             // long[] packageUsageTimeMillis is not persisted because it isn't information that
   6412             // is parsed from the APK.
   6413 
   6414             // Object mExtras is not persisted because it is not information that is read from
   6415             // the APK, rather, it is supplied by callers.
   6416 
   6417 
   6418             configPreferences = new ArrayList<>();
   6419             dest.readParcelableList(configPreferences, boot);
   6420             if (configPreferences.size() == 0) {
   6421                 configPreferences = null;
   6422             }
   6423 
   6424             reqFeatures = new ArrayList<>();
   6425             dest.readParcelableList(reqFeatures, boot);
   6426             if (reqFeatures.size() == 0) {
   6427                 reqFeatures = null;
   6428             }
   6429 
   6430             featureGroups = new ArrayList<>();
   6431             dest.readParcelableList(featureGroups, boot);
   6432             if (featureGroups.size() == 0) {
   6433                 featureGroups = null;
   6434             }
   6435 
   6436             installLocation = dest.readInt();
   6437             coreApp = (dest.readInt() == 1);
   6438             mRequiredForAllUsers = (dest.readInt() == 1);
   6439             mRestrictedAccountType = dest.readString();
   6440             mRequiredAccountType = dest.readString();
   6441             mOverlayTarget = dest.readString();
   6442             mOverlayPriority = dest.readInt();
   6443             mIsStaticOverlay = (dest.readInt() == 1);
   6444             mTrustedOverlay = (dest.readInt() == 1);
   6445             mSigningKeys = (ArraySet<PublicKey>) dest.readArraySet(boot);
   6446             mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);
   6447 
   6448             mKeySetMapping = readKeySetMapping(dest);
   6449 
   6450             cpuAbiOverride = dest.readString();
   6451             use32bitAbi = (dest.readInt() == 1);
   6452             restrictUpdateHash = dest.createByteArray();
   6453             visibleToInstantApps = dest.readInt() == 1;
   6454         }
   6455 
   6456         private static void internStringArrayList(List<String> list) {
   6457             if (list != null) {
   6458                 final int N = list.size();
   6459                 for (int i = 0; i < N; ++i) {
   6460                     list.set(i, list.get(i).intern());
   6461                 }
   6462             }
   6463         }
   6464 
   6465         /**
   6466          * Sets the package owner and the the {@code applicationInfo} for every component
   6467          * owner by this package.
   6468          */
   6469         private void fixupOwner(List<? extends Component<?>> list) {
   6470             if (list != null) {
   6471                 for (Component<?> c : list) {
   6472                     c.owner = this;
   6473                     if (c instanceof Activity) {
   6474                         ((Activity) c).info.applicationInfo = this.applicationInfo;
   6475                     } else if (c instanceof Service) {
   6476                         ((Service) c).info.applicationInfo = this.applicationInfo;
   6477                     } else if (c instanceof Provider) {
   6478                         ((Provider) c).info.applicationInfo = this.applicationInfo;
   6479                     }
   6480                 }
   6481             }
   6482         }
   6483 
   6484         @Override
   6485         public void writeToParcel(Parcel dest, int flags) {
   6486             dest.writeString(packageName);
   6487             dest.writeString(manifestPackageName);
   6488             dest.writeStringArray(splitNames);
   6489             dest.writeString(volumeUuid);
   6490             dest.writeString(codePath);
   6491             dest.writeString(baseCodePath);
   6492             dest.writeStringArray(splitCodePaths);
   6493             dest.writeInt(baseRevisionCode);
   6494             dest.writeIntArray(splitRevisionCodes);
   6495             dest.writeIntArray(splitFlags);
   6496             dest.writeIntArray(splitPrivateFlags);
   6497             dest.writeInt(baseHardwareAccelerated ? 1 : 0);
   6498             dest.writeParcelable(applicationInfo, flags);
   6499 
   6500             dest.writeParcelableList(permissions, flags);
   6501             dest.writeParcelableList(permissionGroups, flags);
   6502             dest.writeParcelableList(activities, flags);
   6503             dest.writeParcelableList(receivers, flags);
   6504             dest.writeParcelableList(providers, flags);
   6505             dest.writeParcelableList(services, flags);
   6506             dest.writeParcelableList(instrumentation, flags);
   6507 
   6508             dest.writeStringList(requestedPermissions);
   6509             dest.writeStringList(protectedBroadcasts);
   6510 
   6511             // TODO: This doesn't work: b/64295061
   6512             dest.writeParcelable(parentPackage, flags);
   6513             dest.writeParcelableList(childPackages, flags);
   6514 
   6515             dest.writeString(staticSharedLibName);
   6516             dest.writeInt(staticSharedLibVersion);
   6517             dest.writeStringList(libraryNames);
   6518             dest.writeStringList(usesLibraries);
   6519             dest.writeStringList(usesOptionalLibraries);
   6520             dest.writeStringArray(usesLibraryFiles);
   6521 
   6522             if (ArrayUtils.isEmpty(usesStaticLibraries)) {
   6523                 dest.writeInt(-1);
   6524             } else {
   6525                 dest.writeInt(usesStaticLibraries.size());
   6526                 dest.writeStringList(usesStaticLibraries);
   6527                 dest.writeIntArray(usesStaticLibrariesVersions);
   6528                 for (String[] usesStaticLibrariesCertDigest : usesStaticLibrariesCertDigests) {
   6529                     dest.writeStringArray(usesStaticLibrariesCertDigest);
   6530                 }
   6531             }
   6532 
   6533             dest.writeParcelableList(preferredActivityFilters, flags);
   6534 
   6535             dest.writeStringList(mOriginalPackages);
   6536             dest.writeString(mRealPackage);
   6537             dest.writeStringList(mAdoptPermissions);
   6538             dest.writeBundle(mAppMetaData);
   6539             dest.writeInt(mVersionCode);
   6540             dest.writeString(mVersionName);
   6541             dest.writeString(mSharedUserId);
   6542             dest.writeInt(mSharedUserLabel);
   6543 
   6544             dest.writeParcelableArray(mSignatures, flags);
   6545             dest.writeSerializable(mCertificates);
   6546 
   6547             dest.writeInt(mPreferredOrder);
   6548 
   6549             // long[] packageUsageTimeMillis is not persisted because it isn't information that
   6550             // is parsed from the APK.
   6551 
   6552             // Object mExtras is not persisted because it is not information that is read from
   6553             // the APK, rather, it is supplied by callers.
   6554 
   6555             dest.writeParcelableList(configPreferences, flags);
   6556             dest.writeParcelableList(reqFeatures, flags);
   6557             dest.writeParcelableList(featureGroups, flags);
   6558 
   6559             dest.writeInt(installLocation);
   6560             dest.writeInt(coreApp ? 1 : 0);
   6561             dest.writeInt(mRequiredForAllUsers ? 1 : 0);
   6562             dest.writeString(mRestrictedAccountType);
   6563             dest.writeString(mRequiredAccountType);
   6564             dest.writeString(mOverlayTarget);
   6565             dest.writeInt(mOverlayPriority);
   6566             dest.writeInt(mIsStaticOverlay ? 1 : 0);
   6567             dest.writeInt(mTrustedOverlay ? 1 : 0);
   6568             dest.writeArraySet(mSigningKeys);
   6569             dest.writeArraySet(mUpgradeKeySets);
   6570             writeKeySetMapping(dest, mKeySetMapping);
   6571             dest.writeString(cpuAbiOverride);
   6572             dest.writeInt(use32bitAbi ? 1 : 0);
   6573             dest.writeByteArray(restrictUpdateHash);
   6574             dest.writeInt(visibleToInstantApps ? 1 : 0);
   6575         }
   6576 
   6577 
   6578         /**
   6579          * Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
   6580          */
   6581         private static void writeKeySetMapping(
   6582                 Parcel dest, ArrayMap<String, ArraySet<PublicKey>> keySetMapping) {
   6583             if (keySetMapping == null) {
   6584                 dest.writeInt(-1);
   6585                 return;
   6586             }
   6587 
   6588             final int N = keySetMapping.size();
   6589             dest.writeInt(N);
   6590 
   6591             for (int i = 0; i < N; i++) {
   6592                 dest.writeString(keySetMapping.keyAt(i));
   6593                 ArraySet<PublicKey> keys = keySetMapping.valueAt(i);
   6594                 if (keys == null) {
   6595                     dest.writeInt(-1);
   6596                     continue;
   6597                 }
   6598 
   6599                 final int M = keys.size();
   6600                 dest.writeInt(M);
   6601                 for (int j = 0; j < M; j++) {
   6602                     dest.writeSerializable(keys.valueAt(j));
   6603                 }
   6604             }
   6605         }
   6606 
   6607         /**
   6608          * Reads a keyset mapping from the given parcel at the given data position. May return
   6609          * {@code null} if the serialized mapping was {@code null}.
   6610          */
   6611         private static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(Parcel in) {
   6612             final int N = in.readInt();
   6613             if (N == -1) {
   6614                 return null;
   6615             }
   6616 
   6617             ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>();
   6618             for (int i = 0; i < N; ++i) {
   6619                 String key = in.readString();
   6620                 final int M = in.readInt();
   6621                 if (M == -1) {
   6622                     keySetMapping.put(key, null);
   6623                     continue;
   6624                 }
   6625 
   6626                 ArraySet<PublicKey> keys = new ArraySet<>(M);
   6627                 for (int j = 0; j < M; ++j) {
   6628                     PublicKey pk = (PublicKey) in.readSerializable();
   6629                     keys.add(pk);
   6630                 }
   6631 
   6632                 keySetMapping.put(key, keys);
   6633             }
   6634 
   6635             return keySetMapping;
   6636         }
   6637 
   6638         public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Package>() {
   6639             public Package createFromParcel(Parcel in) {
   6640                 return new Package(in);
   6641             }
   6642 
   6643             public Package[] newArray(int size) {
   6644                 return new Package[size];
   6645             }
   6646         };
   6647     }
   6648 
   6649     public static abstract class Component<II extends IntentInfo> {
   6650         public final ArrayList<II> intents;
   6651         public final String className;
   6652 
   6653         public Bundle metaData;
   6654         public Package owner;
   6655 
   6656         ComponentName componentName;
   6657         String componentShortName;
   6658 
   6659         public Component(Package _owner) {
   6660             owner = _owner;
   6661             intents = null;
   6662             className = null;
   6663         }
   6664 
   6665         public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
   6666             owner = args.owner;
   6667             intents = new ArrayList<II>(0);
   6668             if (parsePackageItemInfo(args.owner, outInfo, args.outError, args.tag, args.sa,
   6669                     true /*nameRequired*/, args.nameRes, args.labelRes, args.iconRes,
   6670                     args.roundIconRes, args.logoRes, args.bannerRes)) {
   6671                 className = outInfo.name;
   6672             } else {
   6673                 className = null;
   6674             }
   6675         }
   6676 
   6677         public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
   6678             this(args, (PackageItemInfo)outInfo);
   6679             if (args.outError[0] != null) {
   6680                 return;
   6681             }
   6682 
   6683             if (args.processRes != 0) {
   6684                 CharSequence pname;
   6685                 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
   6686                     pname = args.sa.getNonConfigurationString(args.processRes,
   6687                             Configuration.NATIVE_CONFIG_VERSION);
   6688                 } else {
   6689                     // Some older apps have been seen to use a resource reference
   6690                     // here that on older builds was ignored (with a warning).  We
   6691                     // need to continue to do this for them so they don't break.
   6692                     pname = args.sa.getNonResourceString(args.processRes);
   6693                 }
   6694                 outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
   6695                         owner.applicationInfo.processName, pname,
   6696                         args.flags, args.sepProcesses, args.outError);
   6697             }
   6698 
   6699             if (args.descriptionRes != 0) {
   6700                 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
   6701             }
   6702 
   6703             outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
   6704         }
   6705 
   6706         public Component(Component<II> clone) {
   6707             owner = clone.owner;
   6708             intents = clone.intents;
   6709             className = clone.className;
   6710             componentName = clone.componentName;
   6711             componentShortName = clone.componentShortName;
   6712         }
   6713 
   6714         public ComponentName getComponentName() {
   6715             if (componentName != null) {
   6716                 return componentName;
   6717             }
   6718             if (className != null) {
   6719                 componentName = new ComponentName(owner.applicationInfo.packageName,
   6720                         className);
   6721             }
   6722             return componentName;
   6723         }
   6724 
   6725         protected Component(Parcel in) {
   6726             className = in.readString();
   6727             metaData = in.readBundle();
   6728             intents = createIntentsList(in);
   6729 
   6730             owner = null;
   6731         }
   6732 
   6733         protected void writeToParcel(Parcel dest, int flags) {
   6734             dest.writeString(className);
   6735             dest.writeBundle(metaData);
   6736 
   6737             writeIntentsList(intents, dest, flags);
   6738         }
   6739 
   6740         /**
   6741          * <p>
   6742          * Implementation note: The serialized form for the intent list also contains the name
   6743          * of the concrete class that's stored in the list, and assumes that every element of the
   6744          * list is of the same type. This is very similar to the original parcelable mechanism.
   6745          * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable
   6746          * and is public API. It also declares Parcelable related methods as final which means
   6747          * we can't extend them. The approach of using composition instead of inheritance leads to
   6748          * a large set of cascading changes in the PackageManagerService, which seem undesirable.
   6749          *
   6750          * <p>
   6751          * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up
   6752          * to make sure their owner fields are consistent. See {@code fixupOwner}.
   6753          */
   6754         private static void writeIntentsList(ArrayList<? extends IntentInfo> list, Parcel out,
   6755                                              int flags) {
   6756             if (list == null) {
   6757                 out.writeInt(-1);
   6758                 return;
   6759             }
   6760 
   6761             final int N = list.size();
   6762             out.writeInt(N);
   6763 
   6764             // Don't bother writing the component name if the list is empty.
   6765             if (N > 0) {
   6766                 IntentInfo info = list.get(0);
   6767                 out.writeString(info.getClass().getName());
   6768 
   6769                 for (int i = 0; i < N;i++) {
   6770                     list.get(i).writeIntentInfoToParcel(out, flags);
   6771                 }
   6772             }
   6773         }
   6774 
   6775         private static <T extends IntentInfo> ArrayList<T> createIntentsList(Parcel in) {
   6776             int N = in.readInt();
   6777             if (N == -1) {
   6778                 return null;
   6779             }
   6780 
   6781             if (N == 0) {
   6782                 return new ArrayList<>(0);
   6783             }
   6784 
   6785             String componentName = in.readString();
   6786             final ArrayList<T> intentsList;
   6787             try {
   6788                 final Class<T> cls = (Class<T>) Class.forName(componentName);
   6789                 final Constructor<T> cons = cls.getConstructor(Parcel.class);
   6790 
   6791                 intentsList = new ArrayList<>(N);
   6792                 for (int i = 0; i < N; ++i) {
   6793                     intentsList.add(cons.newInstance(in));
   6794                 }
   6795             } catch (ReflectiveOperationException ree) {
   6796                 throw new AssertionError("Unable to construct intent list for: " + componentName);
   6797             }
   6798 
   6799             return intentsList;
   6800         }
   6801 
   6802         public void appendComponentShortName(StringBuilder sb) {
   6803             ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className);
   6804         }
   6805 
   6806         public void printComponentShortName(PrintWriter pw) {
   6807             ComponentName.printShortString(pw, owner.applicationInfo.packageName, className);
   6808         }
   6809 
   6810         public void setPackageName(String packageName) {
   6811             componentName = null;
   6812             componentShortName = null;
   6813         }
   6814     }
   6815 
   6816     public final static class Permission extends Component<IntentInfo> implements Parcelable {
   6817         public final PermissionInfo info;
   6818         public boolean tree;
   6819         public PermissionGroup group;
   6820 
   6821         public Permission(Package _owner) {
   6822             super(_owner);
   6823             info = new PermissionInfo();
   6824         }
   6825 
   6826         public Permission(Package _owner, PermissionInfo _info) {
   6827             super(_owner);
   6828             info = _info;
   6829         }
   6830 
   6831         public void setPackageName(String packageName) {
   6832             super.setPackageName(packageName);
   6833             info.packageName = packageName;
   6834         }
   6835 
   6836         public String toString() {
   6837             return "Permission{"
   6838                 + Integer.toHexString(System.identityHashCode(this))
   6839                 + " " + info.name + "}";
   6840         }
   6841 
   6842         @Override
   6843         public int describeContents() {
   6844             return 0;
   6845         }
   6846 
   6847         @Override
   6848         public void writeToParcel(Parcel dest, int flags) {
   6849             super.writeToParcel(dest, flags);
   6850             dest.writeParcelable(info, flags);
   6851             dest.writeInt(tree ? 1 : 0);
   6852             dest.writeParcelable(group, flags);
   6853         }
   6854 
   6855         private Permission(Parcel in) {
   6856             super(in);
   6857             final ClassLoader boot = Object.class.getClassLoader();
   6858             info = in.readParcelable(boot);
   6859             if (info.group != null) {
   6860                 info.group = info.group.intern();
   6861             }
   6862 
   6863             tree = (in.readInt() == 1);
   6864             group = in.readParcelable(boot);
   6865         }
   6866 
   6867         public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Permission>() {
   6868             public Permission createFromParcel(Parcel in) {
   6869                 return new Permission(in);
   6870             }
   6871 
   6872             public Permission[] newArray(int size) {
   6873                 return new Permission[size];
   6874             }
   6875         };
   6876     }
   6877 
   6878     public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable {
   6879         public final PermissionGroupInfo info;
   6880 
   6881         public PermissionGroup(Package _owner) {
   6882             super(_owner);
   6883             info = new PermissionGroupInfo();
   6884         }
   6885 
   6886         public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
   6887             super(_owner);
   6888             info = _info;
   6889         }
   6890 
   6891         public void setPackageName(String packageName) {
   6892             super.setPackageName(packageName);
   6893             info.packageName = packageName;
   6894         }
   6895 
   6896         public String toString() {
   6897             return "PermissionGroup{"
   6898                 + Integer.toHexString(System.identityHashCode(this))
   6899                 + " " + info.name + "}";
   6900         }
   6901 
   6902         @Override
   6903         public int describeContents() {
   6904             return 0;
   6905         }
   6906 
   6907         @Override
   6908         public void writeToParcel(Parcel dest, int flags) {
   6909             super.writeToParcel(dest, flags);
   6910             dest.writeParcelable(info, flags);
   6911         }
   6912 
   6913         private PermissionGroup(Parcel in) {
   6914             super(in);
   6915             info = in.readParcelable(Object.class.getClassLoader());
   6916         }
   6917 
   6918         public static final Parcelable.Creator CREATOR = new Parcelable.Creator<PermissionGroup>() {
   6919             public PermissionGroup createFromParcel(Parcel in) {
   6920                 return new PermissionGroup(in);
   6921             }
   6922 
   6923             public PermissionGroup[] newArray(int size) {
   6924                 return new PermissionGroup[size];
   6925             }
   6926         };
   6927     }
   6928 
   6929     private static boolean copyNeeded(int flags, Package p,
   6930             PackageUserState state, Bundle metaData, int userId) {
   6931         if (userId != UserHandle.USER_SYSTEM) {
   6932             // We always need to copy for other users, since we need
   6933             // to fix up the uid.
   6934             return true;
   6935         }
   6936         if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
   6937             boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
   6938             if (p.applicationInfo.enabled != enabled) {
   6939                 return true;
   6940             }
   6941         }
   6942         boolean suspended = (p.applicationInfo.flags & FLAG_SUSPENDED) != 0;
   6943         if (state.suspended != suspended) {
   6944             return true;
   6945         }
   6946         if (!state.installed || state.hidden) {
   6947             return true;
   6948         }
   6949         if (state.stopped) {
   6950             return true;
   6951         }
   6952         if (state.instantApp != p.applicationInfo.isInstantApp()) {
   6953             return true;
   6954         }
   6955         if ((flags & PackageManager.GET_META_DATA) != 0
   6956                 && (metaData != null || p.mAppMetaData != null)) {
   6957             return true;
   6958         }
   6959         if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
   6960                 && p.usesLibraryFiles != null) {
   6961             return true;
   6962         }
   6963         if (p.staticSharedLibName != null) {
   6964             return true;
   6965         }
   6966         return false;
   6967     }
   6968 
   6969     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
   6970             PackageUserState state) {
   6971         return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
   6972     }
   6973 
   6974     private static void updateApplicationInfo(ApplicationInfo ai, int flags,
   6975             PackageUserState state) {
   6976         // CompatibilityMode is global state.
   6977         if (!sCompatibilityModeEnabled) {
   6978             ai.disableCompatibilityMode();
   6979         }
   6980         if (state.installed) {
   6981             ai.flags |= ApplicationInfo.FLAG_INSTALLED;
   6982         } else {
   6983             ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
   6984         }
   6985         if (state.suspended) {
   6986             ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
   6987         } else {
   6988             ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
   6989         }
   6990         if (state.instantApp) {
   6991             ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT;
   6992         } else {
   6993             ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT;
   6994         }
   6995         if (state.virtualPreload) {
   6996             ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
   6997         } else {
   6998             ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
   6999         }
   7000         if (state.hidden) {
   7001             ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
   7002         } else {
   7003             ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
   7004         }
   7005         if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
   7006             ai.enabled = true;
   7007         } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
   7008             ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
   7009         } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
   7010                 || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
   7011             ai.enabled = false;
   7012         }
   7013         ai.enabledSetting = state.enabled;
   7014         if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
   7015             ai.category = state.categoryHint;
   7016         }
   7017         if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
   7018             ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
   7019         }
   7020         ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
   7021         ai.resourceDirs = state.overlayPaths;
   7022     }
   7023 
   7024     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
   7025             PackageUserState state, int userId) {
   7026         if (p == null) return null;
   7027         if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
   7028             return null;
   7029         }
   7030         if (!copyNeeded(flags, p, state, null, userId)
   7031                 && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0
   7032                         || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
   7033             // In this case it is safe to directly modify the internal ApplicationInfo state:
   7034             // - CompatibilityMode is global state, so will be the same for every call.
   7035             // - We only come in to here if the app should reported as installed; this is the
   7036             // default state, and we will do a copy otherwise.
   7037             // - The enable state will always be reported the same for the application across
   7038             // calls; the only exception is for the UNTIL_USED mode, and in that case we will
   7039             // be doing a copy.
   7040             updateApplicationInfo(p.applicationInfo, flags, state);
   7041             return p.applicationInfo;
   7042         }
   7043 
   7044         // Make shallow copy so we can store the metadata/libraries safely
   7045         ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
   7046         ai.initForUser(userId);
   7047         if ((flags & PackageManager.GET_META_DATA) != 0) {
   7048             ai.metaData = p.mAppMetaData;
   7049         }
   7050         if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
   7051             ai.sharedLibraryFiles = p.usesLibraryFiles;
   7052         }
   7053         if (state.stopped) {
   7054             ai.flags |= ApplicationInfo.FLAG_STOPPED;
   7055         } else {
   7056             ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
   7057         }
   7058         updateApplicationInfo(ai, flags, state);
   7059         return ai;
   7060     }
   7061 
   7062     public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags,
   7063             PackageUserState state, int userId) {
   7064         if (ai == null) return null;
   7065         if (!checkUseInstalledOrHidden(flags, state, ai)) {
   7066             return null;
   7067         }
   7068         // This is only used to return the ResolverActivity; we will just always
   7069         // make a copy.
   7070         ai = new ApplicationInfo(ai);
   7071         ai.initForUser(userId);
   7072         if (state.stopped) {
   7073             ai.flags |= ApplicationInfo.FLAG_STOPPED;
   7074         } else {
   7075             ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
   7076         }
   7077         updateApplicationInfo(ai, flags, state);
   7078         return ai;
   7079     }
   7080 
   7081     public static final PermissionInfo generatePermissionInfo(
   7082             Permission p, int flags) {
   7083         if (p == null) return null;
   7084         if ((flags&PackageManager.GET_META_DATA) == 0) {
   7085             return p.info;
   7086         }
   7087         PermissionInfo pi = new PermissionInfo(p.info);
   7088         pi.metaData = p.metaData;
   7089         return pi;
   7090     }
   7091 
   7092     public static final PermissionGroupInfo generatePermissionGroupInfo(
   7093             PermissionGroup pg, int flags) {
   7094         if (pg == null) return null;
   7095         if ((flags&PackageManager.GET_META_DATA) == 0) {
   7096             return pg.info;
   7097         }
   7098         PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);
   7099         pgi.metaData = pg.metaData;
   7100         return pgi;
   7101     }
   7102 
   7103     public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
   7104         public final ActivityInfo info;
   7105         private boolean mHasMaxAspectRatio;
   7106 
   7107         private boolean hasMaxAspectRatio() {
   7108             return mHasMaxAspectRatio;
   7109         }
   7110 
   7111         public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
   7112             super(args, _info);
   7113             info = _info;
   7114             info.applicationInfo = args.owner.applicationInfo;
   7115         }
   7116 
   7117         public void setPackageName(String packageName) {
   7118             super.setPackageName(packageName);
   7119             info.packageName = packageName;
   7120         }
   7121 
   7122 
   7123         private void setMaxAspectRatio(float maxAspectRatio) {
   7124             if (info.resizeMode == RESIZE_MODE_RESIZEABLE
   7125                     || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
   7126                 // Resizeable activities can be put in any aspect ratio.
   7127                 return;
   7128             }
   7129 
   7130             if (maxAspectRatio < 1.0f && maxAspectRatio != 0) {
   7131                 // Ignore any value lesser than 1.0.
   7132                 return;
   7133             }
   7134 
   7135             info.maxAspectRatio = maxAspectRatio;
   7136             mHasMaxAspectRatio = true;
   7137         }
   7138 
   7139         public String toString() {
   7140             StringBuilder sb = new StringBuilder(128);
   7141             sb.append("Activity{");
   7142             sb.append(Integer.toHexString(System.identityHashCode(this)));
   7143             sb.append(' ');
   7144             appendComponentShortName(sb);
   7145             sb.append('}');
   7146             return sb.toString();
   7147         }
   7148 
   7149         @Override
   7150         public int describeContents() {
   7151             return 0;
   7152         }
   7153 
   7154         @Override
   7155         public void writeToParcel(Parcel dest, int flags) {
   7156             super.writeToParcel(dest, flags);
   7157             dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
   7158             dest.writeBoolean(mHasMaxAspectRatio);
   7159         }
   7160 
   7161         private Activity(Parcel in) {
   7162             super(in);
   7163             info = in.readParcelable(Object.class.getClassLoader());
   7164             mHasMaxAspectRatio = in.readBoolean();
   7165 
   7166             for (ActivityIntentInfo aii : intents) {
   7167                 aii.activity = this;
   7168             }
   7169 
   7170             if (info.permission != null) {
   7171                 info.permission = info.permission.intern();
   7172             }
   7173         }
   7174 
   7175         public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Activity>() {
   7176             public Activity createFromParcel(Parcel in) {
   7177                 return new Activity(in);
   7178             }
   7179 
   7180             public Activity[] newArray(int size) {
   7181                 return new Activity[size];
   7182             }
   7183         };
   7184     }
   7185 
   7186     public static final ActivityInfo generateActivityInfo(Activity a, int flags,
   7187             PackageUserState state, int userId) {
   7188         if (a == null) return null;
   7189         if (!checkUseInstalledOrHidden(flags, state, a.owner.applicationInfo)) {
   7190             return null;
   7191         }
   7192         if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
   7193             updateApplicationInfo(a.info.applicationInfo, flags, state);
   7194             return a.info;
   7195         }
   7196         // Make shallow copies so we can store the metadata safely
   7197         ActivityInfo ai = new ActivityInfo(a.info);
   7198         ai.metaData = a.metaData;
   7199         ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);
   7200         return ai;
   7201     }
   7202 
   7203     public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags,
   7204             PackageUserState state, int userId) {
   7205         if (ai == null) return null;
   7206         if (!checkUseInstalledOrHidden(flags, state, ai.applicationInfo)) {
   7207             return null;
   7208         }
   7209         // This is only used to return the ResolverActivity; we will just always
   7210         // make a copy.
   7211         ai = new ActivityInfo(ai);
   7212         ai.applicationInfo = generateApplicationInfo(ai.applicationInfo, flags, state, userId);
   7213         return ai;
   7214     }
   7215 
   7216     public final static class Service extends Component<ServiceIntentInfo> implements Parcelable {
   7217         public final ServiceInfo info;
   7218 
   7219         public Service(final ParseComponentArgs args, final ServiceInfo _info) {
   7220             super(args, _info);
   7221             info = _info;
   7222             info.applicationInfo = args.owner.applicationInfo;
   7223         }
   7224 
   7225         public void setPackageName(String packageName) {
   7226             super.setPackageName(packageName);
   7227             info.packageName = packageName;
   7228         }
   7229 
   7230         public String toString() {
   7231             StringBuilder sb = new StringBuilder(128);
   7232             sb.append("Service{");
   7233             sb.append(Integer.toHexString(System.identityHashCode(this)));
   7234             sb.append(' ');
   7235             appendComponentShortName(sb);
   7236             sb.append('}');
   7237             return sb.toString();
   7238         }
   7239 
   7240         @Override
   7241         public int describeContents() {
   7242             return 0;
   7243         }
   7244 
   7245         @Override
   7246         public void writeToParcel(Parcel dest, int flags) {
   7247             super.writeToParcel(dest, flags);
   7248             dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
   7249         }
   7250 
   7251         private Service(Parcel in) {
   7252             super(in);
   7253             info = in.readParcelable(Object.class.getClassLoader());
   7254 
   7255             for (ServiceIntentInfo aii : intents) {
   7256                 aii.service = this;
   7257             }
   7258 
   7259             if (info.permission != null) {
   7260                 info.permission = info.permission.intern();
   7261             }
   7262         }
   7263 
   7264         public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Service>() {
   7265             public Service createFromParcel(Parcel in) {
   7266                 return new Service(in);
   7267             }
   7268 
   7269             public Service[] newArray(int size) {
   7270                 return new Service[size];
   7271             }
   7272         };
   7273     }
   7274 
   7275     public static final ServiceInfo generateServiceInfo(Service s, int flags,
   7276             PackageUserState state, int userId) {
   7277         if (s == null) return null;
   7278         if (!checkUseInstalledOrHidden(flags, state, s.owner.applicationInfo)) {
   7279             return null;
   7280         }
   7281         if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
   7282             updateApplicationInfo(s.info.applicationInfo, flags, state);
   7283             return s.info;
   7284         }
   7285         // Make shallow copies so we can store the metadata safely
   7286         ServiceInfo si = new ServiceInfo(s.info);
   7287         si.metaData = s.metaData;
   7288         si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId);
   7289         return si;
   7290     }
   7291 
   7292     public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable {
   7293         public final ProviderInfo info;
   7294         public boolean syncable;
   7295 
   7296         public Provider(final ParseComponentArgs args, final ProviderInfo _info) {
   7297             super(args, _info);
   7298             info = _info;
   7299             info.applicationInfo = args.owner.applicationInfo;
   7300             syncable = false;
   7301         }
   7302 
   7303         public Provider(Provider existingProvider) {
   7304             super(existingProvider);
   7305             this.info = existingProvider.info;
   7306             this.syncable = existingProvider.syncable;
   7307         }
   7308 
   7309         public void setPackageName(String packageName) {
   7310             super.setPackageName(packageName);
   7311             info.packageName = packageName;
   7312         }
   7313 
   7314         public String toString() {
   7315             StringBuilder sb = new StringBuilder(128);
   7316             sb.append("Provider{");
   7317             sb.append(Integer.toHexString(System.identityHashCode(this)));
   7318             sb.append(' ');
   7319             appendComponentShortName(sb);
   7320             sb.append('}');
   7321             return sb.toString();
   7322         }
   7323 
   7324         @Override
   7325         public int describeContents() {
   7326             return 0;
   7327         }
   7328 
   7329         @Override
   7330         public void writeToParcel(Parcel dest, int flags) {
   7331             super.writeToParcel(dest, flags);
   7332             dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
   7333             dest.writeInt((syncable) ? 1 : 0);
   7334         }
   7335 
   7336         private Provider(Parcel in) {
   7337             super(in);
   7338             info = in.readParcelable(Object.class.getClassLoader());
   7339             syncable = (in.readInt() == 1);
   7340 
   7341             for (ProviderIntentInfo aii : intents) {
   7342                 aii.provider = this;
   7343             }
   7344 
   7345             if (info.readPermission != null) {
   7346                 info.readPermission = info.readPermission.intern();
   7347             }
   7348 
   7349             if (info.writePermission != null) {
   7350                 info.writePermission = info.writePermission.intern();
   7351             }
   7352 
   7353             if (info.authority != null) {
   7354                 info.authority = info.authority.intern();
   7355             }
   7356         }
   7357 
   7358         public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Provider>() {
   7359             public Provider createFromParcel(Parcel in) {
   7360                 return new Provider(in);
   7361             }
   7362 
   7363             public Provider[] newArray(int size) {
   7364                 return new Provider[size];
   7365             }
   7366         };
   7367     }
   7368 
   7369     public static final ProviderInfo generateProviderInfo(Provider p, int flags,
   7370             PackageUserState state, int userId) {
   7371         if (p == null) return null;
   7372         if (!checkUseInstalledOrHidden(flags, state, p.owner.applicationInfo)) {
   7373             return null;
   7374         }
   7375         if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
   7376                 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
   7377                         || p.info.uriPermissionPatterns == null)) {
   7378             updateApplicationInfo(p.info.applicationInfo, flags, state);
   7379             return p.info;
   7380         }
   7381         // Make shallow copies so we can store the metadata safely
   7382         ProviderInfo pi = new ProviderInfo(p.info);
   7383         pi.metaData = p.metaData;
   7384         if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
   7385             pi.uriPermissionPatterns = null;
   7386         }
   7387         pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId);
   7388         return pi;
   7389     }
   7390 
   7391     public final static class Instrumentation extends Component<IntentInfo> implements
   7392             Parcelable {
   7393         public final InstrumentationInfo info;
   7394 
   7395         public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
   7396             super(args, _info);
   7397             info = _info;
   7398         }
   7399 
   7400         public void setPackageName(String packageName) {
   7401             super.setPackageName(packageName);
   7402             info.packageName = packageName;
   7403         }
   7404 
   7405         public String toString() {
   7406             StringBuilder sb = new StringBuilder(128);
   7407             sb.append("Instrumentation{");
   7408             sb.append(Integer.toHexString(System.identityHashCode(this)));
   7409             sb.append(' ');
   7410             appendComponentShortName(sb);
   7411             sb.append('}');
   7412             return sb.toString();
   7413         }
   7414 
   7415         @Override
   7416         public int describeContents() {
   7417             return 0;
   7418         }
   7419 
   7420         @Override
   7421         public void writeToParcel(Parcel dest, int flags) {
   7422             super.writeToParcel(dest, flags);
   7423             dest.writeParcelable(info, flags);
   7424         }
   7425 
   7426         private Instrumentation(Parcel in) {
   7427             super(in);
   7428             info = in.readParcelable(Object.class.getClassLoader());
   7429 
   7430             if (info.targetPackage != null) {
   7431                 info.targetPackage = info.targetPackage.intern();
   7432             }
   7433 
   7434             if (info.targetProcesses != null) {
   7435                 info.targetProcesses = info.targetProcesses.intern();
   7436             }
   7437         }
   7438 
   7439         public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Instrumentation>() {
   7440             public Instrumentation createFromParcel(Parcel in) {
   7441                 return new Instrumentation(in);
   7442             }
   7443 
   7444             public Instrumentation[] newArray(int size) {
   7445                 return new Instrumentation[size];
   7446             }
   7447         };
   7448     }
   7449 
   7450     public static final InstrumentationInfo generateInstrumentationInfo(
   7451             Instrumentation i, int flags) {
   7452         if (i == null) return null;
   7453         if ((flags&PackageManager.GET_META_DATA) == 0) {
   7454             return i.info;
   7455         }
   7456         InstrumentationInfo ii = new InstrumentationInfo(i.info);
   7457         ii.metaData = i.metaData;
   7458         return ii;
   7459     }
   7460 
   7461     public static abstract class IntentInfo extends IntentFilter {
   7462         public boolean hasDefault;
   7463         public int labelRes;
   7464         public CharSequence nonLocalizedLabel;
   7465         public int icon;
   7466         public int logo;
   7467         public int banner;
   7468         public int preferred;
   7469 
   7470         protected IntentInfo() {
   7471         }
   7472 
   7473         protected IntentInfo(Parcel dest) {
   7474             super(dest);
   7475             hasDefault = (dest.readInt() == 1);
   7476             labelRes = dest.readInt();
   7477             nonLocalizedLabel = dest.readCharSequence();
   7478             icon = dest.readInt();
   7479             logo = dest.readInt();
   7480             banner = dest.readInt();
   7481             preferred = dest.readInt();
   7482         }
   7483 
   7484 
   7485         public void writeIntentInfoToParcel(Parcel dest, int flags) {
   7486             super.writeToParcel(dest, flags);
   7487             dest.writeInt(hasDefault ? 1 : 0);
   7488             dest.writeInt(labelRes);
   7489             dest.writeCharSequence(nonLocalizedLabel);
   7490             dest.writeInt(icon);
   7491             dest.writeInt(logo);
   7492             dest.writeInt(banner);
   7493             dest.writeInt(preferred);
   7494         }
   7495     }
   7496 
   7497     public final static class ActivityIntentInfo extends IntentInfo {
   7498         public Activity activity;
   7499 
   7500         public ActivityIntentInfo(Activity _activity) {
   7501             activity = _activity;
   7502         }
   7503 
   7504         public String toString() {
   7505             StringBuilder sb = new StringBuilder(128);
   7506             sb.append("ActivityIntentInfo{");
   7507             sb.append(Integer.toHexString(System.identityHashCode(this)));
   7508             sb.append(' ');
   7509             activity.appendComponentShortName(sb);
   7510             sb.append('}');
   7511             return sb.toString();
   7512         }
   7513 
   7514         public ActivityIntentInfo(Parcel in) {
   7515             super(in);
   7516         }
   7517     }
   7518 
   7519     public final static class ServiceIntentInfo extends IntentInfo {
   7520         public Service service;
   7521 
   7522         public ServiceIntentInfo(Service _service) {
   7523             service = _service;
   7524         }
   7525 
   7526         public String toString() {
   7527             StringBuilder sb = new StringBuilder(128);
   7528             sb.append("ServiceIntentInfo{");
   7529             sb.append(Integer.toHexString(System.identityHashCode(this)));
   7530             sb.append(' ');
   7531             service.appendComponentShortName(sb);
   7532             sb.append('}');
   7533             return sb.toString();
   7534         }
   7535 
   7536         public ServiceIntentInfo(Parcel in) {
   7537             super(in);
   7538         }
   7539     }
   7540 
   7541     public static final class ProviderIntentInfo extends IntentInfo {
   7542         public Provider provider;
   7543 
   7544         public ProviderIntentInfo(Provider provider) {
   7545             this.provider = provider;
   7546         }
   7547 
   7548         public String toString() {
   7549             StringBuilder sb = new StringBuilder(128);
   7550             sb.append("ProviderIntentInfo{");
   7551             sb.append(Integer.toHexString(System.identityHashCode(this)));
   7552             sb.append(' ');
   7553             provider.appendComponentShortName(sb);
   7554             sb.append('}');
   7555             return sb.toString();
   7556         }
   7557 
   7558         public ProviderIntentInfo(Parcel in) {
   7559             super(in);
   7560         }
   7561     }
   7562 
   7563     /**
   7564      * @hide
   7565      */
   7566     public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
   7567         sCompatibilityModeEnabled = compatibilityModeEnabled;
   7568     }
   7569 
   7570     private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>();
   7571 
   7572     public static long readFullyIgnoringContents(InputStream in) throws IOException {
   7573         byte[] buffer = sBuffer.getAndSet(null);
   7574         if (buffer == null) {
   7575             buffer = new byte[4096];
   7576         }
   7577 
   7578         int n = 0;
   7579         int count = 0;
   7580         while ((n = in.read(buffer, 0, buffer.length)) != -1) {
   7581             count += n;
   7582         }
   7583 
   7584         sBuffer.set(buffer);
   7585         return count;
   7586     }
   7587 
   7588     public static void closeQuietly(StrictJarFile jarFile) {
   7589         if (jarFile != null) {
   7590             try {
   7591                 jarFile.close();
   7592             } catch (Exception ignored) {
   7593             }
   7594         }
   7595     }
   7596 
   7597     public static class PackageParserException extends Exception {
   7598         public final int error;
   7599 
   7600         public PackageParserException(int error, String detailMessage) {
   7601             super(detailMessage);
   7602             this.error = error;
   7603         }
   7604 
   7605         public PackageParserException(int error, String detailMessage, Throwable throwable) {
   7606             super(detailMessage, throwable);
   7607             this.error = error;
   7608         }
   7609     }
   7610 }
   7611