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