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