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