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