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