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