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