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