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