PackageParser.java revision 613dde4aa651e11dac3db859723cc6faf8fc0a82
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 supportsXLargeScreens = 1;
795        int resizeable = 1;
796        int anyDensity = 1;
797
798        int outerDepth = parser.getDepth();
799        while ((type=parser.next()) != parser.END_DOCUMENT
800               && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {
801            if (type == parser.END_TAG || type == parser.TEXT) {
802                continue;
803            }
804
805            String tagName = parser.getName();
806            if (tagName.equals("application")) {
807                if (foundApp) {
808                    if (RIGID_PARSER) {
809                        outError[0] = "<manifest> has more than one <application>";
810                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
811                        return null;
812                    } else {
813                        Log.w(TAG, "<manifest> has more than one <application>");
814                        XmlUtils.skipCurrentTag(parser);
815                        continue;
816                    }
817                }
818
819                foundApp = true;
820                if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
821                    return null;
822                }
823            } else if (tagName.equals("permission-group")) {
824                if (parsePermissionGroup(pkg, res, parser, attrs, outError) == null) {
825                    return null;
826                }
827            } else if (tagName.equals("permission")) {
828                if (parsePermission(pkg, res, parser, attrs, outError) == null) {
829                    return null;
830                }
831            } else if (tagName.equals("permission-tree")) {
832                if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
833                    return null;
834                }
835            } else if (tagName.equals("uses-permission")) {
836                sa = res.obtainAttributes(attrs,
837                        com.android.internal.R.styleable.AndroidManifestUsesPermission);
838
839                // Note: don't allow this value to be a reference to a resource
840                // that may change.
841                String name = sa.getNonResourceString(
842                        com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
843
844                sa.recycle();
845
846                if (name != null && !pkg.requestedPermissions.contains(name)) {
847                    pkg.requestedPermissions.add(name.intern());
848                }
849
850                XmlUtils.skipCurrentTag(parser);
851
852            } else if (tagName.equals("uses-configuration")) {
853                ConfigurationInfo cPref = new ConfigurationInfo();
854                sa = res.obtainAttributes(attrs,
855                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration);
856                cPref.reqTouchScreen = sa.getInt(
857                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
858                        Configuration.TOUCHSCREEN_UNDEFINED);
859                cPref.reqKeyboardType = sa.getInt(
860                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
861                        Configuration.KEYBOARD_UNDEFINED);
862                if (sa.getBoolean(
863                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
864                        false)) {
865                    cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
866                }
867                cPref.reqNavigation = sa.getInt(
868                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
869                        Configuration.NAVIGATION_UNDEFINED);
870                if (sa.getBoolean(
871                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
872                        false)) {
873                    cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
874                }
875                sa.recycle();
876                pkg.configPreferences.add(cPref);
877
878                XmlUtils.skipCurrentTag(parser);
879
880            } else if (tagName.equals("uses-feature")) {
881                FeatureInfo fi = new FeatureInfo();
882                sa = res.obtainAttributes(attrs,
883                        com.android.internal.R.styleable.AndroidManifestUsesFeature);
884                // Note: don't allow this value to be a reference to a resource
885                // that may change.
886                fi.name = sa.getNonResourceString(
887                        com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
888                if (fi.name == null) {
889                    fi.reqGlEsVersion = sa.getInt(
890                            com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
891                            FeatureInfo.GL_ES_VERSION_UNDEFINED);
892                }
893                if (sa.getBoolean(
894                        com.android.internal.R.styleable.AndroidManifestUsesFeature_required,
895                        true)) {
896                    fi.flags |= FeatureInfo.FLAG_REQUIRED;
897                }
898                sa.recycle();
899                if (pkg.reqFeatures == null) {
900                    pkg.reqFeatures = new ArrayList<FeatureInfo>();
901                }
902                pkg.reqFeatures.add(fi);
903
904                if (fi.name == null) {
905                    ConfigurationInfo cPref = new ConfigurationInfo();
906                    cPref.reqGlEsVersion = fi.reqGlEsVersion;
907                    pkg.configPreferences.add(cPref);
908                }
909
910                XmlUtils.skipCurrentTag(parser);
911
912            } else if (tagName.equals("uses-sdk")) {
913                if (SDK_VERSION > 0) {
914                    sa = res.obtainAttributes(attrs,
915                            com.android.internal.R.styleable.AndroidManifestUsesSdk);
916
917                    int minVers = 0;
918                    String minCode = null;
919                    int targetVers = 0;
920                    String targetCode = null;
921
922                    TypedValue val = sa.peekValue(
923                            com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
924                    if (val != null) {
925                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
926                            targetCode = minCode = val.string.toString();
927                        } else {
928                            // If it's not a string, it's an integer.
929                            targetVers = minVers = val.data;
930                        }
931                    }
932
933                    val = sa.peekValue(
934                            com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
935                    if (val != null) {
936                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
937                            targetCode = minCode = val.string.toString();
938                        } else {
939                            // If it's not a string, it's an integer.
940                            targetVers = val.data;
941                        }
942                    }
943
944                    sa.recycle();
945
946                    if (minCode != null) {
947                        if (!minCode.equals(SDK_CODENAME)) {
948                            if (SDK_CODENAME != null) {
949                                outError[0] = "Requires development platform " + minCode
950                                        + " (current platform is " + SDK_CODENAME + ")";
951                            } else {
952                                outError[0] = "Requires development platform " + minCode
953                                        + " but this is a release platform.";
954                            }
955                            mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
956                            return null;
957                        }
958                    } else if (minVers > SDK_VERSION) {
959                        outError[0] = "Requires newer sdk version #" + minVers
960                                + " (current version is #" + SDK_VERSION + ")";
961                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
962                        return null;
963                    }
964
965                    if (targetCode != null) {
966                        if (!targetCode.equals(SDK_CODENAME)) {
967                            if (SDK_CODENAME != null) {
968                                outError[0] = "Requires development platform " + targetCode
969                                        + " (current platform is " + SDK_CODENAME + ")";
970                            } else {
971                                outError[0] = "Requires development platform " + targetCode
972                                        + " but this is a release platform.";
973                            }
974                            mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
975                            return null;
976                        }
977                        // If the code matches, it definitely targets this SDK.
978                        pkg.applicationInfo.targetSdkVersion
979                                = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
980                    } else {
981                        pkg.applicationInfo.targetSdkVersion = targetVers;
982                    }
983                }
984
985                XmlUtils.skipCurrentTag(parser);
986
987            } else if (tagName.equals("supports-screens")) {
988                sa = res.obtainAttributes(attrs,
989                        com.android.internal.R.styleable.AndroidManifestSupportsScreens);
990
991                // This is a trick to get a boolean and still able to detect
992                // if a value was actually set.
993                supportsSmallScreens = sa.getInteger(
994                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens,
995                        supportsSmallScreens);
996                supportsNormalScreens = sa.getInteger(
997                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens,
998                        supportsNormalScreens);
999                supportsLargeScreens = sa.getInteger(
1000                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens,
1001                        supportsLargeScreens);
1002                supportsXLargeScreens = sa.getInteger(
1003                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens,
1004                        supportsXLargeScreens);
1005                resizeable = sa.getInteger(
1006                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable,
1007                        resizeable);
1008                anyDensity = sa.getInteger(
1009                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity,
1010                        anyDensity);
1011
1012                sa.recycle();
1013
1014                XmlUtils.skipCurrentTag(parser);
1015
1016            } else if (tagName.equals("protected-broadcast")) {
1017                sa = res.obtainAttributes(attrs,
1018                        com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
1019
1020                // Note: don't allow this value to be a reference to a resource
1021                // that may change.
1022                String name = sa.getNonResourceString(
1023                        com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name);
1024
1025                sa.recycle();
1026
1027                if (name != null && (flags&PARSE_IS_SYSTEM) != 0) {
1028                    if (pkg.protectedBroadcasts == null) {
1029                        pkg.protectedBroadcasts = new ArrayList<String>();
1030                    }
1031                    if (!pkg.protectedBroadcasts.contains(name)) {
1032                        pkg.protectedBroadcasts.add(name.intern());
1033                    }
1034                }
1035
1036                XmlUtils.skipCurrentTag(parser);
1037
1038            } else if (tagName.equals("instrumentation")) {
1039                if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {
1040                    return null;
1041                }
1042
1043            } else if (tagName.equals("original-package")) {
1044                sa = res.obtainAttributes(attrs,
1045                        com.android.internal.R.styleable.AndroidManifestOriginalPackage);
1046
1047                String orig =sa.getNonConfigurationString(
1048                        com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
1049                if (!pkg.packageName.equals(orig)) {
1050                    if (pkg.mOriginalPackages == null) {
1051                        pkg.mOriginalPackages = new ArrayList<String>();
1052                        pkg.mRealPackage = pkg.packageName;
1053                    }
1054                    pkg.mOriginalPackages.add(orig);
1055                }
1056
1057                sa.recycle();
1058
1059                XmlUtils.skipCurrentTag(parser);
1060
1061            } else if (tagName.equals("adopt-permissions")) {
1062                sa = res.obtainAttributes(attrs,
1063                        com.android.internal.R.styleable.AndroidManifestOriginalPackage);
1064
1065                String name = sa.getNonConfigurationString(
1066                        com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
1067
1068                sa.recycle();
1069
1070                if (name != null) {
1071                    if (pkg.mAdoptPermissions == null) {
1072                        pkg.mAdoptPermissions = new ArrayList<String>();
1073                    }
1074                    pkg.mAdoptPermissions.add(name);
1075                }
1076
1077                XmlUtils.skipCurrentTag(parser);
1078
1079            } else if (tagName.equals("eat-comment")) {
1080                // Just skip this tag
1081                XmlUtils.skipCurrentTag(parser);
1082                continue;
1083
1084            } else if (RIGID_PARSER) {
1085                outError[0] = "Bad element under <manifest>: "
1086                    + parser.getName();
1087                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1088                return null;
1089
1090            } else {
1091                Log.w(TAG, "Unknown element under <manifest>: " + parser.getName()
1092                        + " at " + mArchiveSourcePath + " "
1093                        + parser.getPositionDescription());
1094                XmlUtils.skipCurrentTag(parser);
1095                continue;
1096            }
1097        }
1098
1099        if (!foundApp && pkg.instrumentation.size() == 0) {
1100            outError[0] = "<manifest> does not contain an <application> or <instrumentation>";
1101            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
1102        }
1103
1104        final int NP = PackageParser.NEW_PERMISSIONS.length;
1105        StringBuilder implicitPerms = null;
1106        for (int ip=0; ip<NP; ip++) {
1107            final PackageParser.NewPermissionInfo npi
1108                    = PackageParser.NEW_PERMISSIONS[ip];
1109            if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
1110                break;
1111            }
1112            if (!pkg.requestedPermissions.contains(npi.name)) {
1113                if (implicitPerms == null) {
1114                    implicitPerms = new StringBuilder(128);
1115                    implicitPerms.append(pkg.packageName);
1116                    implicitPerms.append(": compat added ");
1117                } else {
1118                    implicitPerms.append(' ');
1119                }
1120                implicitPerms.append(npi.name);
1121                pkg.requestedPermissions.add(npi.name);
1122            }
1123        }
1124        if (implicitPerms != null) {
1125            Log.i(TAG, implicitPerms.toString());
1126        }
1127
1128        if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
1129                && pkg.applicationInfo.targetSdkVersion
1130                        >= android.os.Build.VERSION_CODES.DONUT)) {
1131            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
1132        }
1133        if (supportsNormalScreens != 0) {
1134            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
1135        }
1136        if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
1137                && pkg.applicationInfo.targetSdkVersion
1138                        >= android.os.Build.VERSION_CODES.DONUT)) {
1139            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
1140        }
1141        if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
1142                && pkg.applicationInfo.targetSdkVersion
1143                        >= android.os.Build.VERSION_CODES.GINGERBREAD)) {
1144            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
1145        }
1146        if (resizeable < 0 || (resizeable > 0
1147                && pkg.applicationInfo.targetSdkVersion
1148                        >= android.os.Build.VERSION_CODES.DONUT)) {
1149            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
1150        }
1151        if (anyDensity < 0 || (anyDensity > 0
1152                && pkg.applicationInfo.targetSdkVersion
1153                        >= android.os.Build.VERSION_CODES.DONUT)) {
1154            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
1155        }
1156
1157        return pkg;
1158    }
1159
1160    private static String buildClassName(String pkg, CharSequence clsSeq,
1161            String[] outError) {
1162        if (clsSeq == null || clsSeq.length() <= 0) {
1163            outError[0] = "Empty class name in package " + pkg;
1164            return null;
1165        }
1166        String cls = clsSeq.toString();
1167        char c = cls.charAt(0);
1168        if (c == '.') {
1169            return (pkg + cls).intern();
1170        }
1171        if (cls.indexOf('.') < 0) {
1172            StringBuilder b = new StringBuilder(pkg);
1173            b.append('.');
1174            b.append(cls);
1175            return b.toString().intern();
1176        }
1177        if (c >= 'a' && c <= 'z') {
1178            return cls.intern();
1179        }
1180        outError[0] = "Bad class name " + cls + " in package " + pkg;
1181        return null;
1182    }
1183
1184    private static String buildCompoundName(String pkg,
1185            CharSequence procSeq, String type, String[] outError) {
1186        String proc = procSeq.toString();
1187        char c = proc.charAt(0);
1188        if (pkg != null && c == ':') {
1189            if (proc.length() < 2) {
1190                outError[0] = "Bad " + type + " name " + proc + " in package " + pkg
1191                        + ": must be at least two characters";
1192                return null;
1193            }
1194            String subName = proc.substring(1);
1195            String nameError = validateName(subName, false);
1196            if (nameError != null) {
1197                outError[0] = "Invalid " + type + " name " + proc + " in package "
1198                        + pkg + ": " + nameError;
1199                return null;
1200            }
1201            return (pkg + proc).intern();
1202        }
1203        String nameError = validateName(proc, true);
1204        if (nameError != null && !"system".equals(proc)) {
1205            outError[0] = "Invalid " + type + " name " + proc + " in package "
1206                    + pkg + ": " + nameError;
1207            return null;
1208        }
1209        return proc.intern();
1210    }
1211
1212    private static String buildProcessName(String pkg, String defProc,
1213            CharSequence procSeq, int flags, String[] separateProcesses,
1214            String[] outError) {
1215        if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
1216            return defProc != null ? defProc : pkg;
1217        }
1218        if (separateProcesses != null) {
1219            for (int i=separateProcesses.length-1; i>=0; i--) {
1220                String sp = separateProcesses[i];
1221                if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) {
1222                    return pkg;
1223                }
1224            }
1225        }
1226        if (procSeq == null || procSeq.length() <= 0) {
1227            return defProc;
1228        }
1229        return buildCompoundName(pkg, procSeq, "process", outError);
1230    }
1231
1232    private static String buildTaskAffinityName(String pkg, String defProc,
1233            CharSequence procSeq, String[] outError) {
1234        if (procSeq == null) {
1235            return defProc;
1236        }
1237        if (procSeq.length() <= 0) {
1238            return null;
1239        }
1240        return buildCompoundName(pkg, procSeq, "taskAffinity", outError);
1241    }
1242
1243    private PermissionGroup parsePermissionGroup(Package owner, Resources res,
1244            XmlPullParser parser, AttributeSet attrs, String[] outError)
1245        throws XmlPullParserException, IOException {
1246        PermissionGroup perm = new PermissionGroup(owner);
1247
1248        TypedArray sa = res.obtainAttributes(attrs,
1249                com.android.internal.R.styleable.AndroidManifestPermissionGroup);
1250
1251        if (!parsePackageItemInfo(owner, perm.info, outError,
1252                "<permission-group>", sa,
1253                com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
1254                com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
1255                com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
1256                com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo)) {
1257            sa.recycle();
1258            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1259            return null;
1260        }
1261
1262        perm.info.descriptionRes = sa.getResourceId(
1263                com.android.internal.R.styleable.AndroidManifestPermissionGroup_description,
1264                0);
1265
1266        sa.recycle();
1267
1268        if (!parseAllMetaData(res, parser, attrs, "<permission-group>", perm,
1269                outError)) {
1270            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1271            return null;
1272        }
1273
1274        owner.permissionGroups.add(perm);
1275
1276        return perm;
1277    }
1278
1279    private Permission parsePermission(Package owner, Resources res,
1280            XmlPullParser parser, AttributeSet attrs, String[] outError)
1281        throws XmlPullParserException, IOException {
1282        Permission perm = new Permission(owner);
1283
1284        TypedArray sa = res.obtainAttributes(attrs,
1285                com.android.internal.R.styleable.AndroidManifestPermission);
1286
1287        if (!parsePackageItemInfo(owner, perm.info, outError,
1288                "<permission>", sa,
1289                com.android.internal.R.styleable.AndroidManifestPermission_name,
1290                com.android.internal.R.styleable.AndroidManifestPermission_label,
1291                com.android.internal.R.styleable.AndroidManifestPermission_icon,
1292                com.android.internal.R.styleable.AndroidManifestPermission_logo)) {
1293            sa.recycle();
1294            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1295            return null;
1296        }
1297
1298        // Note: don't allow this value to be a reference to a resource
1299        // that may change.
1300        perm.info.group = sa.getNonResourceString(
1301                com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup);
1302        if (perm.info.group != null) {
1303            perm.info.group = perm.info.group.intern();
1304        }
1305
1306        perm.info.descriptionRes = sa.getResourceId(
1307                com.android.internal.R.styleable.AndroidManifestPermission_description,
1308                0);
1309
1310        perm.info.protectionLevel = sa.getInt(
1311                com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel,
1312                PermissionInfo.PROTECTION_NORMAL);
1313
1314        sa.recycle();
1315
1316        if (perm.info.protectionLevel == -1) {
1317            outError[0] = "<permission> does not specify protectionLevel";
1318            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1319            return null;
1320        }
1321
1322        if (!parseAllMetaData(res, parser, attrs, "<permission>", perm,
1323                outError)) {
1324            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1325            return null;
1326        }
1327
1328        owner.permissions.add(perm);
1329
1330        return perm;
1331    }
1332
1333    private Permission parsePermissionTree(Package owner, Resources res,
1334            XmlPullParser parser, AttributeSet attrs, String[] outError)
1335        throws XmlPullParserException, IOException {
1336        Permission perm = new Permission(owner);
1337
1338        TypedArray sa = res.obtainAttributes(attrs,
1339                com.android.internal.R.styleable.AndroidManifestPermissionTree);
1340
1341        if (!parsePackageItemInfo(owner, perm.info, outError,
1342                "<permission-tree>", sa,
1343                com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
1344                com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
1345                com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
1346                com.android.internal.R.styleable.AndroidManifestPermissionTree_logo)) {
1347            sa.recycle();
1348            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1349            return null;
1350        }
1351
1352        sa.recycle();
1353
1354        int index = perm.info.name.indexOf('.');
1355        if (index > 0) {
1356            index = perm.info.name.indexOf('.', index+1);
1357        }
1358        if (index < 0) {
1359            outError[0] = "<permission-tree> name has less than three segments: "
1360                + perm.info.name;
1361            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1362            return null;
1363        }
1364
1365        perm.info.descriptionRes = 0;
1366        perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
1367        perm.tree = true;
1368
1369        if (!parseAllMetaData(res, parser, attrs, "<permission-tree>", perm,
1370                outError)) {
1371            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1372            return null;
1373        }
1374
1375        owner.permissions.add(perm);
1376
1377        return perm;
1378    }
1379
1380    private Instrumentation parseInstrumentation(Package owner, Resources res,
1381            XmlPullParser parser, AttributeSet attrs, String[] outError)
1382        throws XmlPullParserException, IOException {
1383        TypedArray sa = res.obtainAttributes(attrs,
1384                com.android.internal.R.styleable.AndroidManifestInstrumentation);
1385
1386        if (mParseInstrumentationArgs == null) {
1387            mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError,
1388                    com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
1389                    com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
1390                    com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
1391                    com.android.internal.R.styleable.AndroidManifestInstrumentation_logo);
1392            mParseInstrumentationArgs.tag = "<instrumentation>";
1393        }
1394
1395        mParseInstrumentationArgs.sa = sa;
1396
1397        Instrumentation a = new Instrumentation(mParseInstrumentationArgs,
1398                new InstrumentationInfo());
1399        if (outError[0] != null) {
1400            sa.recycle();
1401            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1402            return null;
1403        }
1404
1405        String str;
1406        // Note: don't allow this value to be a reference to a resource
1407        // that may change.
1408        str = sa.getNonResourceString(
1409                com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage);
1410        a.info.targetPackage = str != null ? str.intern() : null;
1411
1412        a.info.handleProfiling = sa.getBoolean(
1413                com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling,
1414                false);
1415
1416        a.info.functionalTest = sa.getBoolean(
1417                com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest,
1418                false);
1419
1420        sa.recycle();
1421
1422        if (a.info.targetPackage == null) {
1423            outError[0] = "<instrumentation> does not specify targetPackage";
1424            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1425            return null;
1426        }
1427
1428        if (!parseAllMetaData(res, parser, attrs, "<instrumentation>", a,
1429                outError)) {
1430            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1431            return null;
1432        }
1433
1434        owner.instrumentation.add(a);
1435
1436        return a;
1437    }
1438
1439    private boolean parseApplication(Package owner, Resources res,
1440            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
1441        throws XmlPullParserException, IOException {
1442        final ApplicationInfo ai = owner.applicationInfo;
1443        final String pkgName = owner.applicationInfo.packageName;
1444
1445        TypedArray sa = res.obtainAttributes(attrs,
1446                com.android.internal.R.styleable.AndroidManifestApplication);
1447
1448        String name = sa.getNonConfigurationString(
1449                com.android.internal.R.styleable.AndroidManifestApplication_name, 0);
1450        if (name != null) {
1451            ai.className = buildClassName(pkgName, name, outError);
1452            if (ai.className == null) {
1453                sa.recycle();
1454                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1455                return false;
1456            }
1457        }
1458
1459        String manageSpaceActivity = sa.getNonConfigurationString(
1460                com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity, 0);
1461        if (manageSpaceActivity != null) {
1462            ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
1463                    outError);
1464        }
1465
1466        boolean allowBackup = sa.getBoolean(
1467                com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
1468        if (allowBackup) {
1469            ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
1470
1471            // backupAgent, killAfterRestore, and restoreAnyVersion are only relevant
1472            // if backup is possible for the given application.
1473            String backupAgent = sa.getNonConfigurationString(
1474                    com.android.internal.R.styleable.AndroidManifestApplication_backupAgent, 0);
1475            if (backupAgent != null) {
1476                ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
1477                if (false) {
1478                    Log.v(TAG, "android:backupAgent = " + ai.backupAgentName
1479                            + " from " + pkgName + "+" + backupAgent);
1480                }
1481
1482                if (sa.getBoolean(
1483                        com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore,
1484                        true)) {
1485                    ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
1486                }
1487                if (sa.getBoolean(
1488                        com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion,
1489                        false)) {
1490                    ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
1491                }
1492            }
1493        }
1494
1495        TypedValue v = sa.peekValue(
1496                com.android.internal.R.styleable.AndroidManifestApplication_label);
1497        if (v != null && (ai.labelRes=v.resourceId) == 0) {
1498            ai.nonLocalizedLabel = v.coerceToString();
1499        }
1500
1501        ai.icon = sa.getResourceId(
1502                com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
1503        ai.logo = sa.getResourceId(
1504                com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
1505        ai.theme = sa.getResourceId(
1506                com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
1507        ai.descriptionRes = sa.getResourceId(
1508                com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
1509
1510        if ((flags&PARSE_IS_SYSTEM) != 0) {
1511            if (sa.getBoolean(
1512                    com.android.internal.R.styleable.AndroidManifestApplication_persistent,
1513                    false)) {
1514                ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
1515            }
1516        }
1517
1518        if ((flags & PARSE_FORWARD_LOCK) != 0) {
1519            ai.flags |= ApplicationInfo.FLAG_FORWARD_LOCK;
1520        }
1521
1522        if ((flags & PARSE_ON_SDCARD) != 0) {
1523            ai.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
1524        }
1525
1526        if (sa.getBoolean(
1527                com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
1528                false)) {
1529            ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
1530        }
1531
1532        if (sa.getBoolean(
1533                com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode,
1534                false)) {
1535            ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE;
1536        }
1537
1538        if (sa.getBoolean(
1539                com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
1540                true)) {
1541            ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
1542        }
1543
1544        if (sa.getBoolean(
1545                com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
1546                false)) {
1547            ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
1548        }
1549
1550        if (sa.getBoolean(
1551                com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
1552                true)) {
1553            ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
1554        }
1555
1556        if (sa.getBoolean(
1557                com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
1558                false)) {
1559            ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
1560        }
1561
1562        if (sa.getBoolean(
1563                com.android.internal.R.styleable.AndroidManifestApplication_neverEncrypt,
1564                false)) {
1565            ai.flags |= ApplicationInfo.FLAG_NEVER_ENCRYPT;
1566        }
1567
1568        String str;
1569        str = sa.getNonConfigurationString(
1570                com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
1571        ai.permission = (str != null && str.length() > 0) ? str.intern() : null;
1572
1573        if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
1574            str = sa.getNonConfigurationString(
1575                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, 0);
1576        } else {
1577            // Some older apps have been seen to use a resource reference
1578            // here that on older builds was ignored (with a warning).  We
1579            // need to continue to do this for them so they don't break.
1580            str = sa.getNonResourceString(
1581                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
1582        }
1583        ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
1584                str, outError);
1585
1586        if (outError[0] == null) {
1587            CharSequence pname;
1588            if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
1589                pname = sa.getNonConfigurationString(
1590                        com.android.internal.R.styleable.AndroidManifestApplication_process, 0);
1591            } else {
1592                // Some older apps have been seen to use a resource reference
1593                // here that on older builds was ignored (with a warning).  We
1594                // need to continue to do this for them so they don't break.
1595                pname = sa.getNonResourceString(
1596                        com.android.internal.R.styleable.AndroidManifestApplication_process);
1597            }
1598            ai.processName = buildProcessName(ai.packageName, null, pname,
1599                    flags, mSeparateProcesses, outError);
1600
1601            ai.enabled = sa.getBoolean(
1602                    com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
1603
1604            if (sa.getBoolean(
1605                    com.android.internal.R.styleable.AndroidManifestApplication_heavyWeight,
1606                    false)) {
1607                ai.flags |= ApplicationInfo.FLAG_HEAVY_WEIGHT;
1608
1609                // A heavy-weight application can not be in a custom process.
1610                // We can do direct compare because we intern all strings.
1611                if (ai.processName != null && ai.processName != ai.packageName) {
1612                    outError[0] = "Heavy-weight applications can not use custom processes";
1613                }
1614            }
1615        }
1616
1617        sa.recycle();
1618
1619        if (outError[0] != null) {
1620            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1621            return false;
1622        }
1623
1624        final int innerDepth = parser.getDepth();
1625
1626        int type;
1627        while ((type=parser.next()) != parser.END_DOCUMENT
1628               && (type != parser.END_TAG || parser.getDepth() > innerDepth)) {
1629            if (type == parser.END_TAG || type == parser.TEXT) {
1630                continue;
1631            }
1632
1633            String tagName = parser.getName();
1634            if (tagName.equals("activity")) {
1635                Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false);
1636                if (a == null) {
1637                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1638                    return false;
1639                }
1640
1641                owner.activities.add(a);
1642
1643            } else if (tagName.equals("receiver")) {
1644                Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true);
1645                if (a == null) {
1646                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1647                    return false;
1648                }
1649
1650                owner.receivers.add(a);
1651
1652            } else if (tagName.equals("service")) {
1653                Service s = parseService(owner, res, parser, attrs, flags, outError);
1654                if (s == null) {
1655                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1656                    return false;
1657                }
1658
1659                owner.services.add(s);
1660
1661            } else if (tagName.equals("provider")) {
1662                Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
1663                if (p == null) {
1664                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1665                    return false;
1666                }
1667
1668                owner.providers.add(p);
1669
1670            } else if (tagName.equals("activity-alias")) {
1671                Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);
1672                if (a == null) {
1673                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1674                    return false;
1675                }
1676
1677                owner.activities.add(a);
1678
1679            } else if (parser.getName().equals("meta-data")) {
1680                // note: application meta-data is stored off to the side, so it can
1681                // remain null in the primary copy (we like to avoid extra copies because
1682                // it can be large)
1683                if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData,
1684                        outError)) == null) {
1685                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1686                    return false;
1687                }
1688
1689            } else if (tagName.equals("uses-library")) {
1690                sa = res.obtainAttributes(attrs,
1691                        com.android.internal.R.styleable.AndroidManifestUsesLibrary);
1692
1693                // Note: don't allow this value to be a reference to a resource
1694                // that may change.
1695                String lname = sa.getNonResourceString(
1696                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
1697                boolean req = sa.getBoolean(
1698                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
1699                        true);
1700
1701                sa.recycle();
1702
1703                if (lname != null) {
1704                    if (req) {
1705                        if (owner.usesLibraries == null) {
1706                            owner.usesLibraries = new ArrayList<String>();
1707                        }
1708                        if (!owner.usesLibraries.contains(lname)) {
1709                            owner.usesLibraries.add(lname.intern());
1710                        }
1711                    } else {
1712                        if (owner.usesOptionalLibraries == null) {
1713                            owner.usesOptionalLibraries = new ArrayList<String>();
1714                        }
1715                        if (!owner.usesOptionalLibraries.contains(lname)) {
1716                            owner.usesOptionalLibraries.add(lname.intern());
1717                        }
1718                    }
1719                }
1720
1721                XmlUtils.skipCurrentTag(parser);
1722
1723            } else {
1724                if (!RIGID_PARSER) {
1725                    Log.w(TAG, "Unknown element under <application>: " + tagName
1726                            + " at " + mArchiveSourcePath + " "
1727                            + parser.getPositionDescription());
1728                    XmlUtils.skipCurrentTag(parser);
1729                    continue;
1730                } else {
1731                    outError[0] = "Bad element under <application>: " + tagName;
1732                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1733                    return false;
1734                }
1735            }
1736        }
1737
1738        return true;
1739    }
1740
1741    private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
1742            String[] outError, String tag, TypedArray sa,
1743            int nameRes, int labelRes, int iconRes, int logoRes) {
1744        String name = sa.getNonConfigurationString(nameRes, 0);
1745        if (name == null) {
1746            outError[0] = tag + " does not specify android:name";
1747            return false;
1748        }
1749
1750        outInfo.name
1751            = buildClassName(owner.applicationInfo.packageName, name, outError);
1752        if (outInfo.name == null) {
1753            return false;
1754        }
1755
1756        int iconVal = sa.getResourceId(iconRes, 0);
1757        if (iconVal != 0) {
1758            outInfo.icon = iconVal;
1759            outInfo.nonLocalizedLabel = null;
1760        }
1761
1762        int logoVal = sa.getResourceId(logoRes, 0);
1763        if (logoVal != 0) {
1764            outInfo.logo = logoVal;
1765        }
1766
1767        TypedValue v = sa.peekValue(labelRes);
1768        if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
1769            outInfo.nonLocalizedLabel = v.coerceToString();
1770        }
1771
1772        outInfo.packageName = owner.packageName;
1773
1774        return true;
1775    }
1776
1777    private Activity parseActivity(Package owner, Resources res,
1778            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
1779            boolean receiver) throws XmlPullParserException, IOException {
1780        TypedArray sa = res.obtainAttributes(attrs,
1781                com.android.internal.R.styleable.AndroidManifestActivity);
1782
1783        if (mParseActivityArgs == null) {
1784            mParseActivityArgs = new ParseComponentArgs(owner, outError,
1785                    com.android.internal.R.styleable.AndroidManifestActivity_name,
1786                    com.android.internal.R.styleable.AndroidManifestActivity_label,
1787                    com.android.internal.R.styleable.AndroidManifestActivity_icon,
1788                    com.android.internal.R.styleable.AndroidManifestActivity_logo,
1789                    mSeparateProcesses,
1790                    com.android.internal.R.styleable.AndroidManifestActivity_process,
1791                    com.android.internal.R.styleable.AndroidManifestActivity_description,
1792                    com.android.internal.R.styleable.AndroidManifestActivity_enabled);
1793        }
1794
1795        mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
1796        mParseActivityArgs.sa = sa;
1797        mParseActivityArgs.flags = flags;
1798
1799        Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
1800        if (outError[0] != null) {
1801            sa.recycle();
1802            return null;
1803        }
1804
1805        final boolean setExported = sa.hasValue(
1806                com.android.internal.R.styleable.AndroidManifestActivity_exported);
1807        if (setExported) {
1808            a.info.exported = sa.getBoolean(
1809                    com.android.internal.R.styleable.AndroidManifestActivity_exported, false);
1810        }
1811
1812        a.info.theme = sa.getResourceId(
1813                com.android.internal.R.styleable.AndroidManifestActivity_theme, 0);
1814
1815        String str;
1816        str = sa.getNonConfigurationString(
1817                com.android.internal.R.styleable.AndroidManifestActivity_permission, 0);
1818        if (str == null) {
1819            a.info.permission = owner.applicationInfo.permission;
1820        } else {
1821            a.info.permission = str.length() > 0 ? str.toString().intern() : null;
1822        }
1823
1824        str = sa.getNonConfigurationString(
1825                com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity, 0);
1826        a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
1827                owner.applicationInfo.taskAffinity, str, outError);
1828
1829        a.info.flags = 0;
1830        if (sa.getBoolean(
1831                com.android.internal.R.styleable.AndroidManifestActivity_multiprocess,
1832                false)) {
1833            a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
1834        }
1835
1836        if (sa.getBoolean(
1837                com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch,
1838                false)) {
1839            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
1840        }
1841
1842        if (sa.getBoolean(
1843                com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch,
1844                false)) {
1845            a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
1846        }
1847
1848        if (sa.getBoolean(
1849                com.android.internal.R.styleable.AndroidManifestActivity_noHistory,
1850                false)) {
1851            a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
1852        }
1853
1854        if (sa.getBoolean(
1855                com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState,
1856                false)) {
1857            a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
1858        }
1859
1860        if (sa.getBoolean(
1861                com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded,
1862                false)) {
1863            a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
1864        }
1865
1866        if (sa.getBoolean(
1867                com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents,
1868                false)) {
1869            a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
1870        }
1871
1872        if (sa.getBoolean(
1873                com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting,
1874                (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
1875            a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
1876        }
1877
1878        if (sa.getBoolean(
1879                com.android.internal.R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
1880                false)) {
1881            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
1882        }
1883
1884        if (sa.getBoolean(
1885                com.android.internal.R.styleable.AndroidManifestActivity_immersive,
1886                false)) {
1887            a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
1888        }
1889
1890        if (!receiver) {
1891            a.info.launchMode = sa.getInt(
1892                    com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
1893                    ActivityInfo.LAUNCH_MULTIPLE);
1894            a.info.screenOrientation = sa.getInt(
1895                    com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
1896                    ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
1897            a.info.configChanges = sa.getInt(
1898                    com.android.internal.R.styleable.AndroidManifestActivity_configChanges,
1899                    0);
1900            a.info.softInputMode = sa.getInt(
1901                    com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
1902                    0);
1903        } else {
1904            a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
1905            a.info.configChanges = 0;
1906        }
1907
1908        sa.recycle();
1909
1910        if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
1911            // A heavy-weight application can not have receives in its main process
1912            // We can do direct compare because we intern all strings.
1913            if (a.info.processName == owner.packageName) {
1914                outError[0] = "Heavy-weight applications can not have receivers in main process";
1915            }
1916        }
1917
1918        if (outError[0] != null) {
1919            return null;
1920        }
1921
1922        int outerDepth = parser.getDepth();
1923        int type;
1924        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1925               && (type != XmlPullParser.END_TAG
1926                       || parser.getDepth() > outerDepth)) {
1927            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1928                continue;
1929            }
1930
1931            if (parser.getName().equals("intent-filter")) {
1932                ActivityIntentInfo intent = new ActivityIntentInfo(a);
1933                if (!parseIntent(res, parser, attrs, flags, intent, outError, !receiver)) {
1934                    return null;
1935                }
1936                if (intent.countActions() == 0) {
1937                    Log.w(TAG, "No actions in intent filter at "
1938                            + mArchiveSourcePath + " "
1939                            + parser.getPositionDescription());
1940                } else {
1941                    a.intents.add(intent);
1942                }
1943            } else if (parser.getName().equals("meta-data")) {
1944                if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
1945                        outError)) == null) {
1946                    return null;
1947                }
1948            } else {
1949                if (!RIGID_PARSER) {
1950                    Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
1951                    if (receiver) {
1952                        Log.w(TAG, "Unknown element under <receiver>: " + parser.getName()
1953                                + " at " + mArchiveSourcePath + " "
1954                                + parser.getPositionDescription());
1955                    } else {
1956                        Log.w(TAG, "Unknown element under <activity>: " + parser.getName()
1957                                + " at " + mArchiveSourcePath + " "
1958                                + parser.getPositionDescription());
1959                    }
1960                    XmlUtils.skipCurrentTag(parser);
1961                    continue;
1962                }
1963                if (receiver) {
1964                    outError[0] = "Bad element under <receiver>: " + parser.getName();
1965                } else {
1966                    outError[0] = "Bad element under <activity>: " + parser.getName();
1967                }
1968                return null;
1969            }
1970        }
1971
1972        if (!setExported) {
1973            a.info.exported = a.intents.size() > 0;
1974        }
1975
1976        return a;
1977    }
1978
1979    private Activity parseActivityAlias(Package owner, Resources res,
1980            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
1981            throws XmlPullParserException, IOException {
1982        TypedArray sa = res.obtainAttributes(attrs,
1983                com.android.internal.R.styleable.AndroidManifestActivityAlias);
1984
1985        String targetActivity = sa.getNonConfigurationString(
1986                com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity, 0);
1987        if (targetActivity == null) {
1988            outError[0] = "<activity-alias> does not specify android:targetActivity";
1989            sa.recycle();
1990            return null;
1991        }
1992
1993        targetActivity = buildClassName(owner.applicationInfo.packageName,
1994                targetActivity, outError);
1995        if (targetActivity == null) {
1996            sa.recycle();
1997            return null;
1998        }
1999
2000        if (mParseActivityAliasArgs == null) {
2001            mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
2002                    com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
2003                    com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
2004                    com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
2005                    com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
2006                    mSeparateProcesses,
2007                    0,
2008                    com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
2009                    com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
2010            mParseActivityAliasArgs.tag = "<activity-alias>";
2011        }
2012
2013        mParseActivityAliasArgs.sa = sa;
2014        mParseActivityAliasArgs.flags = flags;
2015
2016        Activity target = null;
2017
2018        final int NA = owner.activities.size();
2019        for (int i=0; i<NA; i++) {
2020            Activity t = owner.activities.get(i);
2021            if (targetActivity.equals(t.info.name)) {
2022                target = t;
2023                break;
2024            }
2025        }
2026
2027        if (target == null) {
2028            outError[0] = "<activity-alias> target activity " + targetActivity
2029                    + " not found in manifest";
2030            sa.recycle();
2031            return null;
2032        }
2033
2034        ActivityInfo info = new ActivityInfo();
2035        info.targetActivity = targetActivity;
2036        info.configChanges = target.info.configChanges;
2037        info.flags = target.info.flags;
2038        info.icon = target.info.icon;
2039        info.logo = target.info.logo;
2040        info.labelRes = target.info.labelRes;
2041        info.nonLocalizedLabel = target.info.nonLocalizedLabel;
2042        info.launchMode = target.info.launchMode;
2043        info.processName = target.info.processName;
2044        if (info.descriptionRes == 0) {
2045            info.descriptionRes = target.info.descriptionRes;
2046        }
2047        info.screenOrientation = target.info.screenOrientation;
2048        info.taskAffinity = target.info.taskAffinity;
2049        info.theme = target.info.theme;
2050
2051        Activity a = new Activity(mParseActivityAliasArgs, info);
2052        if (outError[0] != null) {
2053            sa.recycle();
2054            return null;
2055        }
2056
2057        final boolean setExported = sa.hasValue(
2058                com.android.internal.R.styleable.AndroidManifestActivityAlias_exported);
2059        if (setExported) {
2060            a.info.exported = sa.getBoolean(
2061                    com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false);
2062        }
2063
2064        String str;
2065        str = sa.getNonConfigurationString(
2066                com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0);
2067        if (str != null) {
2068            a.info.permission = str.length() > 0 ? str.toString().intern() : null;
2069        }
2070
2071        sa.recycle();
2072
2073        if (outError[0] != null) {
2074            return null;
2075        }
2076
2077        int outerDepth = parser.getDepth();
2078        int type;
2079        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2080               && (type != XmlPullParser.END_TAG
2081                       || parser.getDepth() > outerDepth)) {
2082            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2083                continue;
2084            }
2085
2086            if (parser.getName().equals("intent-filter")) {
2087                ActivityIntentInfo intent = new ActivityIntentInfo(a);
2088                if (!parseIntent(res, parser, attrs, flags, intent, outError, true)) {
2089                    return null;
2090                }
2091                if (intent.countActions() == 0) {
2092                    Log.w(TAG, "No actions in intent filter at "
2093                            + mArchiveSourcePath + " "
2094                            + parser.getPositionDescription());
2095                } else {
2096                    a.intents.add(intent);
2097                }
2098            } else if (parser.getName().equals("meta-data")) {
2099                if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
2100                        outError)) == null) {
2101                    return null;
2102                }
2103            } else {
2104                if (!RIGID_PARSER) {
2105                    Log.w(TAG, "Unknown element under <activity-alias>: " + parser.getName()
2106                            + " at " + mArchiveSourcePath + " "
2107                            + parser.getPositionDescription());
2108                    XmlUtils.skipCurrentTag(parser);
2109                    continue;
2110                }
2111                outError[0] = "Bad element under <activity-alias>: " + parser.getName();
2112                return null;
2113            }
2114        }
2115
2116        if (!setExported) {
2117            a.info.exported = a.intents.size() > 0;
2118        }
2119
2120        return a;
2121    }
2122
2123    private Provider parseProvider(Package owner, Resources res,
2124            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
2125            throws XmlPullParserException, IOException {
2126        TypedArray sa = res.obtainAttributes(attrs,
2127                com.android.internal.R.styleable.AndroidManifestProvider);
2128
2129        if (mParseProviderArgs == null) {
2130            mParseProviderArgs = new ParseComponentArgs(owner, outError,
2131                    com.android.internal.R.styleable.AndroidManifestProvider_name,
2132                    com.android.internal.R.styleable.AndroidManifestProvider_label,
2133                    com.android.internal.R.styleable.AndroidManifestProvider_icon,
2134                    com.android.internal.R.styleable.AndroidManifestProvider_logo,
2135                    mSeparateProcesses,
2136                    com.android.internal.R.styleable.AndroidManifestProvider_process,
2137                    com.android.internal.R.styleable.AndroidManifestProvider_description,
2138                    com.android.internal.R.styleable.AndroidManifestProvider_enabled);
2139            mParseProviderArgs.tag = "<provider>";
2140        }
2141
2142        mParseProviderArgs.sa = sa;
2143        mParseProviderArgs.flags = flags;
2144
2145        Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
2146        if (outError[0] != null) {
2147            sa.recycle();
2148            return null;
2149        }
2150
2151        p.info.exported = sa.getBoolean(
2152                com.android.internal.R.styleable.AndroidManifestProvider_exported, true);
2153
2154        String cpname = sa.getNonConfigurationString(
2155                com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0);
2156
2157        p.info.isSyncable = sa.getBoolean(
2158                com.android.internal.R.styleable.AndroidManifestProvider_syncable,
2159                false);
2160
2161        String permission = sa.getNonConfigurationString(
2162                com.android.internal.R.styleable.AndroidManifestProvider_permission, 0);
2163        String str = sa.getNonConfigurationString(
2164                com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0);
2165        if (str == null) {
2166            str = permission;
2167        }
2168        if (str == null) {
2169            p.info.readPermission = owner.applicationInfo.permission;
2170        } else {
2171            p.info.readPermission =
2172                str.length() > 0 ? str.toString().intern() : null;
2173        }
2174        str = sa.getNonConfigurationString(
2175                com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0);
2176        if (str == null) {
2177            str = permission;
2178        }
2179        if (str == null) {
2180            p.info.writePermission = owner.applicationInfo.permission;
2181        } else {
2182            p.info.writePermission =
2183                str.length() > 0 ? str.toString().intern() : null;
2184        }
2185
2186        p.info.grantUriPermissions = sa.getBoolean(
2187                com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
2188                false);
2189
2190        p.info.multiprocess = sa.getBoolean(
2191                com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
2192                false);
2193
2194        p.info.initOrder = sa.getInt(
2195                com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
2196                0);
2197
2198        sa.recycle();
2199
2200        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
2201            // A heavy-weight application can not have providers in its main process
2202            // We can do direct compare because we intern all strings.
2203            if (p.info.processName == owner.packageName) {
2204                outError[0] = "Heavy-weight applications can not have providers in main process";
2205                return null;
2206            }
2207        }
2208
2209        if (cpname == null) {
2210            outError[0] = "<provider> does not incude authorities attribute";
2211            return null;
2212        }
2213        p.info.authority = cpname.intern();
2214
2215        if (!parseProviderTags(res, parser, attrs, p, outError)) {
2216            return null;
2217        }
2218
2219        return p;
2220    }
2221
2222    private boolean parseProviderTags(Resources res,
2223            XmlPullParser parser, AttributeSet attrs,
2224            Provider outInfo, String[] outError)
2225            throws XmlPullParserException, IOException {
2226        int outerDepth = parser.getDepth();
2227        int type;
2228        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2229               && (type != XmlPullParser.END_TAG
2230                       || parser.getDepth() > outerDepth)) {
2231            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2232                continue;
2233            }
2234
2235            if (parser.getName().equals("meta-data")) {
2236                if ((outInfo.metaData=parseMetaData(res, parser, attrs,
2237                        outInfo.metaData, outError)) == null) {
2238                    return false;
2239                }
2240
2241            } else if (parser.getName().equals("grant-uri-permission")) {
2242                TypedArray sa = res.obtainAttributes(attrs,
2243                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
2244
2245                PatternMatcher pa = null;
2246
2247                String str = sa.getNonConfigurationString(
2248                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0);
2249                if (str != null) {
2250                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
2251                }
2252
2253                str = sa.getNonConfigurationString(
2254                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
2255                if (str != null) {
2256                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
2257                }
2258
2259                str = sa.getNonConfigurationString(
2260                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
2261                if (str != null) {
2262                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
2263                }
2264
2265                sa.recycle();
2266
2267                if (pa != null) {
2268                    if (outInfo.info.uriPermissionPatterns == null) {
2269                        outInfo.info.uriPermissionPatterns = new PatternMatcher[1];
2270                        outInfo.info.uriPermissionPatterns[0] = pa;
2271                    } else {
2272                        final int N = outInfo.info.uriPermissionPatterns.length;
2273                        PatternMatcher[] newp = new PatternMatcher[N+1];
2274                        System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N);
2275                        newp[N] = pa;
2276                        outInfo.info.uriPermissionPatterns = newp;
2277                    }
2278                    outInfo.info.grantUriPermissions = true;
2279                } else {
2280                    if (!RIGID_PARSER) {
2281                        Log.w(TAG, "Unknown element under <path-permission>: "
2282                                + parser.getName() + " at " + mArchiveSourcePath + " "
2283                                + parser.getPositionDescription());
2284                        XmlUtils.skipCurrentTag(parser);
2285                        continue;
2286                    }
2287                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
2288                    return false;
2289                }
2290                XmlUtils.skipCurrentTag(parser);
2291
2292            } else if (parser.getName().equals("path-permission")) {
2293                TypedArray sa = res.obtainAttributes(attrs,
2294                        com.android.internal.R.styleable.AndroidManifestPathPermission);
2295
2296                PathPermission pa = null;
2297
2298                String permission = sa.getNonConfigurationString(
2299                        com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0);
2300                String readPermission = sa.getNonConfigurationString(
2301                        com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0);
2302                if (readPermission == null) {
2303                    readPermission = permission;
2304                }
2305                String writePermission = sa.getNonConfigurationString(
2306                        com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0);
2307                if (writePermission == null) {
2308                    writePermission = permission;
2309                }
2310
2311                boolean havePerm = false;
2312                if (readPermission != null) {
2313                    readPermission = readPermission.intern();
2314                    havePerm = true;
2315                }
2316                if (writePermission != null) {
2317                    writePermission = writePermission.intern();
2318                    havePerm = true;
2319                }
2320
2321                if (!havePerm) {
2322                    if (!RIGID_PARSER) {
2323                        Log.w(TAG, "No readPermission or writePermssion for <path-permission>: "
2324                                + parser.getName() + " at " + mArchiveSourcePath + " "
2325                                + parser.getPositionDescription());
2326                        XmlUtils.skipCurrentTag(parser);
2327                        continue;
2328                    }
2329                    outError[0] = "No readPermission or writePermssion for <path-permission>";
2330                    return false;
2331                }
2332
2333                String path = sa.getNonConfigurationString(
2334                        com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0);
2335                if (path != null) {
2336                    pa = new PathPermission(path,
2337                            PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
2338                }
2339
2340                path = sa.getNonConfigurationString(
2341                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
2342                if (path != null) {
2343                    pa = new PathPermission(path,
2344                            PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
2345                }
2346
2347                path = sa.getNonConfigurationString(
2348                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0);
2349                if (path != null) {
2350                    pa = new PathPermission(path,
2351                            PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
2352                }
2353
2354                sa.recycle();
2355
2356                if (pa != null) {
2357                    if (outInfo.info.pathPermissions == null) {
2358                        outInfo.info.pathPermissions = new PathPermission[1];
2359                        outInfo.info.pathPermissions[0] = pa;
2360                    } else {
2361                        final int N = outInfo.info.pathPermissions.length;
2362                        PathPermission[] newp = new PathPermission[N+1];
2363                        System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
2364                        newp[N] = pa;
2365                        outInfo.info.pathPermissions = newp;
2366                    }
2367                } else {
2368                    if (!RIGID_PARSER) {
2369                        Log.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
2370                                + parser.getName() + " at " + mArchiveSourcePath + " "
2371                                + parser.getPositionDescription());
2372                        XmlUtils.skipCurrentTag(parser);
2373                        continue;
2374                    }
2375                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
2376                    return false;
2377                }
2378                XmlUtils.skipCurrentTag(parser);
2379
2380            } else {
2381                if (!RIGID_PARSER) {
2382                    Log.w(TAG, "Unknown element under <provider>: "
2383                            + parser.getName() + " at " + mArchiveSourcePath + " "
2384                            + parser.getPositionDescription());
2385                    XmlUtils.skipCurrentTag(parser);
2386                    continue;
2387                }
2388                outError[0] = "Bad element under <provider>: "
2389                    + parser.getName();
2390                return false;
2391            }
2392        }
2393        return true;
2394    }
2395
2396    private Service parseService(Package owner, Resources res,
2397            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
2398            throws XmlPullParserException, IOException {
2399        TypedArray sa = res.obtainAttributes(attrs,
2400                com.android.internal.R.styleable.AndroidManifestService);
2401
2402        if (mParseServiceArgs == null) {
2403            mParseServiceArgs = new ParseComponentArgs(owner, outError,
2404                    com.android.internal.R.styleable.AndroidManifestService_name,
2405                    com.android.internal.R.styleable.AndroidManifestService_label,
2406                    com.android.internal.R.styleable.AndroidManifestService_icon,
2407                    com.android.internal.R.styleable.AndroidManifestService_logo,
2408                    mSeparateProcesses,
2409                    com.android.internal.R.styleable.AndroidManifestService_process,
2410                    com.android.internal.R.styleable.AndroidManifestService_description,
2411                    com.android.internal.R.styleable.AndroidManifestService_enabled);
2412            mParseServiceArgs.tag = "<service>";
2413        }
2414
2415        mParseServiceArgs.sa = sa;
2416        mParseServiceArgs.flags = flags;
2417
2418        Service s = new Service(mParseServiceArgs, new ServiceInfo());
2419        if (outError[0] != null) {
2420            sa.recycle();
2421            return null;
2422        }
2423
2424        final boolean setExported = sa.hasValue(
2425                com.android.internal.R.styleable.AndroidManifestService_exported);
2426        if (setExported) {
2427            s.info.exported = sa.getBoolean(
2428                    com.android.internal.R.styleable.AndroidManifestService_exported, false);
2429        }
2430
2431        String str = sa.getNonConfigurationString(
2432                com.android.internal.R.styleable.AndroidManifestService_permission, 0);
2433        if (str == null) {
2434            s.info.permission = owner.applicationInfo.permission;
2435        } else {
2436            s.info.permission = str.length() > 0 ? str.toString().intern() : null;
2437        }
2438
2439        sa.recycle();
2440
2441        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
2442            // A heavy-weight application can not have services in its main process
2443            // We can do direct compare because we intern all strings.
2444            if (s.info.processName == owner.packageName) {
2445                outError[0] = "Heavy-weight applications can not have services in main process";
2446                return null;
2447            }
2448        }
2449
2450        int outerDepth = parser.getDepth();
2451        int type;
2452        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2453               && (type != XmlPullParser.END_TAG
2454                       || parser.getDepth() > outerDepth)) {
2455            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2456                continue;
2457            }
2458
2459            if (parser.getName().equals("intent-filter")) {
2460                ServiceIntentInfo intent = new ServiceIntentInfo(s);
2461                if (!parseIntent(res, parser, attrs, flags, intent, outError, false)) {
2462                    return null;
2463                }
2464
2465                s.intents.add(intent);
2466            } else if (parser.getName().equals("meta-data")) {
2467                if ((s.metaData=parseMetaData(res, parser, attrs, s.metaData,
2468                        outError)) == null) {
2469                    return null;
2470                }
2471            } else {
2472                if (!RIGID_PARSER) {
2473                    Log.w(TAG, "Unknown element under <service>: "
2474                            + parser.getName() + " at " + mArchiveSourcePath + " "
2475                            + parser.getPositionDescription());
2476                    XmlUtils.skipCurrentTag(parser);
2477                    continue;
2478                }
2479                outError[0] = "Bad element under <service>: "
2480                    + parser.getName();
2481                return null;
2482            }
2483        }
2484
2485        if (!setExported) {
2486            s.info.exported = s.intents.size() > 0;
2487        }
2488
2489        return s;
2490    }
2491
2492    private boolean parseAllMetaData(Resources res,
2493            XmlPullParser parser, AttributeSet attrs, String tag,
2494            Component outInfo, String[] outError)
2495            throws XmlPullParserException, IOException {
2496        int outerDepth = parser.getDepth();
2497        int type;
2498        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2499               && (type != XmlPullParser.END_TAG
2500                       || parser.getDepth() > outerDepth)) {
2501            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2502                continue;
2503            }
2504
2505            if (parser.getName().equals("meta-data")) {
2506                if ((outInfo.metaData=parseMetaData(res, parser, attrs,
2507                        outInfo.metaData, outError)) == null) {
2508                    return false;
2509                }
2510            } else {
2511                if (!RIGID_PARSER) {
2512                    Log.w(TAG, "Unknown element under " + tag + ": "
2513                            + parser.getName() + " at " + mArchiveSourcePath + " "
2514                            + parser.getPositionDescription());
2515                    XmlUtils.skipCurrentTag(parser);
2516                    continue;
2517                }
2518                outError[0] = "Bad element under " + tag + ": "
2519                    + parser.getName();
2520                return false;
2521            }
2522        }
2523        return true;
2524    }
2525
2526    private Bundle parseMetaData(Resources res,
2527            XmlPullParser parser, AttributeSet attrs,
2528            Bundle data, String[] outError)
2529            throws XmlPullParserException, IOException {
2530
2531        TypedArray sa = res.obtainAttributes(attrs,
2532                com.android.internal.R.styleable.AndroidManifestMetaData);
2533
2534        if (data == null) {
2535            data = new Bundle();
2536        }
2537
2538        String name = sa.getNonConfigurationString(
2539                com.android.internal.R.styleable.AndroidManifestMetaData_name, 0);
2540        if (name == null) {
2541            outError[0] = "<meta-data> requires an android:name attribute";
2542            sa.recycle();
2543            return null;
2544        }
2545
2546        name = name.intern();
2547
2548        TypedValue v = sa.peekValue(
2549                com.android.internal.R.styleable.AndroidManifestMetaData_resource);
2550        if (v != null && v.resourceId != 0) {
2551            //Log.i(TAG, "Meta data ref " + name + ": " + v);
2552            data.putInt(name, v.resourceId);
2553        } else {
2554            v = sa.peekValue(
2555                    com.android.internal.R.styleable.AndroidManifestMetaData_value);
2556            //Log.i(TAG, "Meta data " + name + ": " + v);
2557            if (v != null) {
2558                if (v.type == TypedValue.TYPE_STRING) {
2559                    CharSequence cs = v.coerceToString();
2560                    data.putString(name, cs != null ? cs.toString().intern() : null);
2561                } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
2562                    data.putBoolean(name, v.data != 0);
2563                } else if (v.type >= TypedValue.TYPE_FIRST_INT
2564                        && v.type <= TypedValue.TYPE_LAST_INT) {
2565                    data.putInt(name, v.data);
2566                } else if (v.type == TypedValue.TYPE_FLOAT) {
2567                    data.putFloat(name, v.getFloat());
2568                } else {
2569                    if (!RIGID_PARSER) {
2570                        Log.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: "
2571                                + parser.getName() + " at " + mArchiveSourcePath + " "
2572                                + parser.getPositionDescription());
2573                    } else {
2574                        outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types";
2575                        data = null;
2576                    }
2577                }
2578            } else {
2579                outError[0] = "<meta-data> requires an android:value or android:resource attribute";
2580                data = null;
2581            }
2582        }
2583
2584        sa.recycle();
2585
2586        XmlUtils.skipCurrentTag(parser);
2587
2588        return data;
2589    }
2590
2591    private static final String ANDROID_RESOURCES
2592            = "http://schemas.android.com/apk/res/android";
2593
2594    private boolean parseIntent(Resources res,
2595            XmlPullParser parser, AttributeSet attrs, int flags,
2596            IntentInfo outInfo, String[] outError, boolean isActivity)
2597            throws XmlPullParserException, IOException {
2598
2599        TypedArray sa = res.obtainAttributes(attrs,
2600                com.android.internal.R.styleable.AndroidManifestIntentFilter);
2601
2602        int priority = sa.getInt(
2603                com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
2604        if (priority > 0 && isActivity && (flags&PARSE_IS_SYSTEM) == 0) {
2605            Log.w(TAG, "Activity with priority > 0, forcing to 0 at "
2606                    + mArchiveSourcePath + " "
2607                    + parser.getPositionDescription());
2608            priority = 0;
2609        }
2610        outInfo.setPriority(priority);
2611
2612        TypedValue v = sa.peekValue(
2613                com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
2614        if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
2615            outInfo.nonLocalizedLabel = v.coerceToString();
2616        }
2617
2618        outInfo.icon = sa.getResourceId(
2619                com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
2620
2621        outInfo.logo = sa.getResourceId(
2622                com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
2623
2624        sa.recycle();
2625
2626        int outerDepth = parser.getDepth();
2627        int type;
2628        while ((type=parser.next()) != parser.END_DOCUMENT
2629               && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {
2630            if (type == parser.END_TAG || type == parser.TEXT) {
2631                continue;
2632            }
2633
2634            String nodeName = parser.getName();
2635            if (nodeName.equals("action")) {
2636                String value = attrs.getAttributeValue(
2637                        ANDROID_RESOURCES, "name");
2638                if (value == null || value == "") {
2639                    outError[0] = "No value supplied for <android:name>";
2640                    return false;
2641                }
2642                XmlUtils.skipCurrentTag(parser);
2643
2644                outInfo.addAction(value);
2645            } else if (nodeName.equals("category")) {
2646                String value = attrs.getAttributeValue(
2647                        ANDROID_RESOURCES, "name");
2648                if (value == null || value == "") {
2649                    outError[0] = "No value supplied for <android:name>";
2650                    return false;
2651                }
2652                XmlUtils.skipCurrentTag(parser);
2653
2654                outInfo.addCategory(value);
2655
2656            } else if (nodeName.equals("data")) {
2657                sa = res.obtainAttributes(attrs,
2658                        com.android.internal.R.styleable.AndroidManifestData);
2659
2660                String str = sa.getNonConfigurationString(
2661                        com.android.internal.R.styleable.AndroidManifestData_mimeType, 0);
2662                if (str != null) {
2663                    try {
2664                        outInfo.addDataType(str);
2665                    } catch (IntentFilter.MalformedMimeTypeException e) {
2666                        outError[0] = e.toString();
2667                        sa.recycle();
2668                        return false;
2669                    }
2670                }
2671
2672                str = sa.getNonConfigurationString(
2673                        com.android.internal.R.styleable.AndroidManifestData_scheme, 0);
2674                if (str != null) {
2675                    outInfo.addDataScheme(str);
2676                }
2677
2678                String host = sa.getNonConfigurationString(
2679                        com.android.internal.R.styleable.AndroidManifestData_host, 0);
2680                String port = sa.getNonConfigurationString(
2681                        com.android.internal.R.styleable.AndroidManifestData_port, 0);
2682                if (host != null) {
2683                    outInfo.addDataAuthority(host, port);
2684                }
2685
2686                str = sa.getNonConfigurationString(
2687                        com.android.internal.R.styleable.AndroidManifestData_path, 0);
2688                if (str != null) {
2689                    outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
2690                }
2691
2692                str = sa.getNonConfigurationString(
2693                        com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0);
2694                if (str != null) {
2695                    outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
2696                }
2697
2698                str = sa.getNonConfigurationString(
2699                        com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
2700                if (str != null) {
2701                    outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
2702                }
2703
2704                sa.recycle();
2705                XmlUtils.skipCurrentTag(parser);
2706            } else if (!RIGID_PARSER) {
2707                Log.w(TAG, "Unknown element under <intent-filter>: "
2708                        + parser.getName() + " at " + mArchiveSourcePath + " "
2709                        + parser.getPositionDescription());
2710                XmlUtils.skipCurrentTag(parser);
2711            } else {
2712                outError[0] = "Bad element under <intent-filter>: " + parser.getName();
2713                return false;
2714            }
2715        }
2716
2717        outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
2718        if (false) {
2719            String cats = "";
2720            Iterator<String> it = outInfo.categoriesIterator();
2721            while (it != null && it.hasNext()) {
2722                cats += " " + it.next();
2723            }
2724            System.out.println("Intent d=" +
2725                    outInfo.hasDefault + ", cat=" + cats);
2726        }
2727
2728        return true;
2729    }
2730
2731    public final static class Package {
2732        public String packageName;
2733
2734        // For now we only support one application per package.
2735        public final ApplicationInfo applicationInfo = new ApplicationInfo();
2736
2737        public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
2738        public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
2739        public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
2740        public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
2741        public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
2742        public final ArrayList<Service> services = new ArrayList<Service>(0);
2743        public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
2744
2745        public final ArrayList<String> requestedPermissions = new ArrayList<String>();
2746
2747        public ArrayList<String> protectedBroadcasts;
2748
2749        public ArrayList<String> usesLibraries = null;
2750        public ArrayList<String> usesOptionalLibraries = null;
2751        public String[] usesLibraryFiles = null;
2752
2753        public ArrayList<String> mOriginalPackages = null;
2754        public String mRealPackage = null;
2755        public ArrayList<String> mAdoptPermissions = null;
2756
2757        // We store the application meta-data independently to avoid multiple unwanted references
2758        public Bundle mAppMetaData = null;
2759
2760        // If this is a 3rd party app, this is the path of the zip file.
2761        public String mPath;
2762
2763        // The version code declared for this package.
2764        public int mVersionCode;
2765
2766        // The version name declared for this package.
2767        public String mVersionName;
2768
2769        // The shared user id that this package wants to use.
2770        public String mSharedUserId;
2771
2772        // The shared user label that this package wants to use.
2773        public int mSharedUserLabel;
2774
2775        // Signatures that were read from the package.
2776        public Signature mSignatures[];
2777
2778        // For use by package manager service for quick lookup of
2779        // preferred up order.
2780        public int mPreferredOrder = 0;
2781
2782        // For use by the package manager to keep track of the path to the
2783        // file an app came from.
2784        public String mScanPath;
2785
2786        // For use by package manager to keep track of where it has done dexopt.
2787        public boolean mDidDexOpt;
2788
2789        // Additional data supplied by callers.
2790        public Object mExtras;
2791
2792        /*
2793         *  Applications hardware preferences
2794         */
2795        public final ArrayList<ConfigurationInfo> configPreferences =
2796                new ArrayList<ConfigurationInfo>();
2797
2798        /*
2799         *  Applications requested features
2800         */
2801        public ArrayList<FeatureInfo> reqFeatures = null;
2802
2803        public int installLocation;
2804
2805        public Package(String _name) {
2806            packageName = _name;
2807            applicationInfo.packageName = _name;
2808            applicationInfo.uid = -1;
2809        }
2810
2811        public void setPackageName(String newName) {
2812            packageName = newName;
2813            applicationInfo.packageName = newName;
2814            for (int i=permissions.size()-1; i>=0; i--) {
2815                permissions.get(i).setPackageName(newName);
2816            }
2817            for (int i=permissionGroups.size()-1; i>=0; i--) {
2818                permissionGroups.get(i).setPackageName(newName);
2819            }
2820            for (int i=activities.size()-1; i>=0; i--) {
2821                activities.get(i).setPackageName(newName);
2822            }
2823            for (int i=receivers.size()-1; i>=0; i--) {
2824                receivers.get(i).setPackageName(newName);
2825            }
2826            for (int i=providers.size()-1; i>=0; i--) {
2827                providers.get(i).setPackageName(newName);
2828            }
2829            for (int i=services.size()-1; i>=0; i--) {
2830                services.get(i).setPackageName(newName);
2831            }
2832            for (int i=instrumentation.size()-1; i>=0; i--) {
2833                instrumentation.get(i).setPackageName(newName);
2834            }
2835        }
2836
2837        public String toString() {
2838            return "Package{"
2839                + Integer.toHexString(System.identityHashCode(this))
2840                + " " + packageName + "}";
2841        }
2842    }
2843
2844    public static class Component<II extends IntentInfo> {
2845        public final Package owner;
2846        public final ArrayList<II> intents;
2847        public final String className;
2848        public Bundle metaData;
2849
2850        ComponentName componentName;
2851        String componentShortName;
2852
2853        public Component(Package _owner) {
2854            owner = _owner;
2855            intents = null;
2856            className = null;
2857        }
2858
2859        public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
2860            owner = args.owner;
2861            intents = new ArrayList<II>(0);
2862            String name = args.sa.getNonConfigurationString(args.nameRes, 0);
2863            if (name == null) {
2864                className = null;
2865                args.outError[0] = args.tag + " does not specify android:name";
2866                return;
2867            }
2868
2869            outInfo.name
2870                = buildClassName(owner.applicationInfo.packageName, name, args.outError);
2871            if (outInfo.name == null) {
2872                className = null;
2873                args.outError[0] = args.tag + " does not have valid android:name";
2874                return;
2875            }
2876
2877            className = outInfo.name;
2878
2879            int iconVal = args.sa.getResourceId(args.iconRes, 0);
2880            if (iconVal != 0) {
2881                outInfo.icon = iconVal;
2882                outInfo.nonLocalizedLabel = null;
2883            }
2884
2885            int logoVal = args.sa.getResourceId(args.logoRes, 0);
2886            if (logoVal != 0) {
2887                outInfo.logo = logoVal;
2888            }
2889
2890            TypedValue v = args.sa.peekValue(args.labelRes);
2891            if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
2892                outInfo.nonLocalizedLabel = v.coerceToString();
2893            }
2894
2895            outInfo.packageName = owner.packageName;
2896        }
2897
2898        public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
2899            this(args, (PackageItemInfo)outInfo);
2900            if (args.outError[0] != null) {
2901                return;
2902            }
2903
2904            if (args.processRes != 0) {
2905                CharSequence pname;
2906                if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
2907                    pname = args.sa.getNonConfigurationString(args.processRes, 0);
2908                } else {
2909                    // Some older apps have been seen to use a resource reference
2910                    // here that on older builds was ignored (with a warning).  We
2911                    // need to continue to do this for them so they don't break.
2912                    pname = args.sa.getNonResourceString(args.processRes);
2913                }
2914                outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
2915                        owner.applicationInfo.processName, pname,
2916                        args.flags, args.sepProcesses, args.outError);
2917            }
2918
2919            if (args.descriptionRes != 0) {
2920                outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
2921            }
2922
2923            outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
2924        }
2925
2926        public Component(Component<II> clone) {
2927            owner = clone.owner;
2928            intents = clone.intents;
2929            className = clone.className;
2930            componentName = clone.componentName;
2931            componentShortName = clone.componentShortName;
2932        }
2933
2934        public ComponentName getComponentName() {
2935            if (componentName != null) {
2936                return componentName;
2937            }
2938            if (className != null) {
2939                componentName = new ComponentName(owner.applicationInfo.packageName,
2940                        className);
2941            }
2942            return componentName;
2943        }
2944
2945        public String getComponentShortName() {
2946            if (componentShortName != null) {
2947                return componentShortName;
2948            }
2949            ComponentName component = getComponentName();
2950            if (component != null) {
2951                componentShortName = component.flattenToShortString();
2952            }
2953            return componentShortName;
2954        }
2955
2956        public void setPackageName(String packageName) {
2957            componentName = null;
2958            componentShortName = null;
2959        }
2960    }
2961
2962    public final static class Permission extends Component<IntentInfo> {
2963        public final PermissionInfo info;
2964        public boolean tree;
2965        public PermissionGroup group;
2966
2967        public Permission(Package _owner) {
2968            super(_owner);
2969            info = new PermissionInfo();
2970        }
2971
2972        public Permission(Package _owner, PermissionInfo _info) {
2973            super(_owner);
2974            info = _info;
2975        }
2976
2977        public void setPackageName(String packageName) {
2978            super.setPackageName(packageName);
2979            info.packageName = packageName;
2980        }
2981
2982        public String toString() {
2983            return "Permission{"
2984                + Integer.toHexString(System.identityHashCode(this))
2985                + " " + info.name + "}";
2986        }
2987    }
2988
2989    public final static class PermissionGroup extends Component<IntentInfo> {
2990        public final PermissionGroupInfo info;
2991
2992        public PermissionGroup(Package _owner) {
2993            super(_owner);
2994            info = new PermissionGroupInfo();
2995        }
2996
2997        public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
2998            super(_owner);
2999            info = _info;
3000        }
3001
3002        public void setPackageName(String packageName) {
3003            super.setPackageName(packageName);
3004            info.packageName = packageName;
3005        }
3006
3007        public String toString() {
3008            return "PermissionGroup{"
3009                + Integer.toHexString(System.identityHashCode(this))
3010                + " " + info.name + "}";
3011        }
3012    }
3013
3014    private static boolean copyNeeded(int flags, Package p, Bundle metaData) {
3015        if ((flags & PackageManager.GET_META_DATA) != 0
3016                && (metaData != null || p.mAppMetaData != null)) {
3017            return true;
3018        }
3019        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
3020                && p.usesLibraryFiles != null) {
3021            return true;
3022        }
3023        return false;
3024    }
3025
3026    public static ApplicationInfo generateApplicationInfo(Package p, int flags) {
3027        if (p == null) return null;
3028        if (!copyNeeded(flags, p, null)) {
3029            // CompatibilityMode is global state. It's safe to modify the instance
3030            // of the package.
3031            if (!sCompatibilityModeEnabled) {
3032                p.applicationInfo.disableCompatibilityMode();
3033            }
3034            return p.applicationInfo;
3035        }
3036
3037        // Make shallow copy so we can store the metadata/libraries safely
3038        ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
3039        if ((flags & PackageManager.GET_META_DATA) != 0) {
3040            ai.metaData = p.mAppMetaData;
3041        }
3042        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
3043            ai.sharedLibraryFiles = p.usesLibraryFiles;
3044        }
3045        if (!sCompatibilityModeEnabled) {
3046            ai.disableCompatibilityMode();
3047        }
3048        return ai;
3049    }
3050
3051    public static final PermissionInfo generatePermissionInfo(
3052            Permission p, int flags) {
3053        if (p == null) return null;
3054        if ((flags&PackageManager.GET_META_DATA) == 0) {
3055            return p.info;
3056        }
3057        PermissionInfo pi = new PermissionInfo(p.info);
3058        pi.metaData = p.metaData;
3059        return pi;
3060    }
3061
3062    public static final PermissionGroupInfo generatePermissionGroupInfo(
3063            PermissionGroup pg, int flags) {
3064        if (pg == null) return null;
3065        if ((flags&PackageManager.GET_META_DATA) == 0) {
3066            return pg.info;
3067        }
3068        PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);
3069        pgi.metaData = pg.metaData;
3070        return pgi;
3071    }
3072
3073    public final static class Activity extends Component<ActivityIntentInfo> {
3074        public final ActivityInfo info;
3075
3076        public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
3077            super(args, _info);
3078            info = _info;
3079            info.applicationInfo = args.owner.applicationInfo;
3080        }
3081
3082        public void setPackageName(String packageName) {
3083            super.setPackageName(packageName);
3084            info.packageName = packageName;
3085        }
3086
3087        public String toString() {
3088            return "Activity{"
3089                + Integer.toHexString(System.identityHashCode(this))
3090                + " " + getComponentShortName() + "}";
3091        }
3092    }
3093
3094    public static final ActivityInfo generateActivityInfo(Activity a,
3095            int flags) {
3096        if (a == null) return null;
3097        if (!copyNeeded(flags, a.owner, a.metaData)) {
3098            return a.info;
3099        }
3100        // Make shallow copies so we can store the metadata safely
3101        ActivityInfo ai = new ActivityInfo(a.info);
3102        ai.metaData = a.metaData;
3103        ai.applicationInfo = generateApplicationInfo(a.owner, flags);
3104        return ai;
3105    }
3106
3107    public final static class Service extends Component<ServiceIntentInfo> {
3108        public final ServiceInfo info;
3109
3110        public Service(final ParseComponentArgs args, final ServiceInfo _info) {
3111            super(args, _info);
3112            info = _info;
3113            info.applicationInfo = args.owner.applicationInfo;
3114        }
3115
3116        public void setPackageName(String packageName) {
3117            super.setPackageName(packageName);
3118            info.packageName = packageName;
3119        }
3120
3121        public String toString() {
3122            return "Service{"
3123                + Integer.toHexString(System.identityHashCode(this))
3124                + " " + getComponentShortName() + "}";
3125        }
3126    }
3127
3128    public static final ServiceInfo generateServiceInfo(Service s, int flags) {
3129        if (s == null) return null;
3130        if (!copyNeeded(flags, s.owner, s.metaData)) {
3131            return s.info;
3132        }
3133        // Make shallow copies so we can store the metadata safely
3134        ServiceInfo si = new ServiceInfo(s.info);
3135        si.metaData = s.metaData;
3136        si.applicationInfo = generateApplicationInfo(s.owner, flags);
3137        return si;
3138    }
3139
3140    public final static class Provider extends Component {
3141        public final ProviderInfo info;
3142        public boolean syncable;
3143
3144        public Provider(final ParseComponentArgs args, final ProviderInfo _info) {
3145            super(args, _info);
3146            info = _info;
3147            info.applicationInfo = args.owner.applicationInfo;
3148            syncable = false;
3149        }
3150
3151        public Provider(Provider existingProvider) {
3152            super(existingProvider);
3153            this.info = existingProvider.info;
3154            this.syncable = existingProvider.syncable;
3155        }
3156
3157        public void setPackageName(String packageName) {
3158            super.setPackageName(packageName);
3159            info.packageName = packageName;
3160        }
3161
3162        public String toString() {
3163            return "Provider{"
3164                + Integer.toHexString(System.identityHashCode(this))
3165                + " " + info.name + "}";
3166        }
3167    }
3168
3169    public static final ProviderInfo generateProviderInfo(Provider p,
3170            int flags) {
3171        if (p == null) return null;
3172        if (!copyNeeded(flags, p.owner, p.metaData)
3173                && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
3174                        || p.info.uriPermissionPatterns == null)) {
3175            return p.info;
3176        }
3177        // Make shallow copies so we can store the metadata safely
3178        ProviderInfo pi = new ProviderInfo(p.info);
3179        pi.metaData = p.metaData;
3180        if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
3181            pi.uriPermissionPatterns = null;
3182        }
3183        pi.applicationInfo = generateApplicationInfo(p.owner, flags);
3184        return pi;
3185    }
3186
3187    public final static class Instrumentation extends Component {
3188        public final InstrumentationInfo info;
3189
3190        public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
3191            super(args, _info);
3192            info = _info;
3193        }
3194
3195        public void setPackageName(String packageName) {
3196            super.setPackageName(packageName);
3197            info.packageName = packageName;
3198        }
3199
3200        public String toString() {
3201            return "Instrumentation{"
3202                + Integer.toHexString(System.identityHashCode(this))
3203                + " " + getComponentShortName() + "}";
3204        }
3205    }
3206
3207    public static final InstrumentationInfo generateInstrumentationInfo(
3208            Instrumentation i, int flags) {
3209        if (i == null) return null;
3210        if ((flags&PackageManager.GET_META_DATA) == 0) {
3211            return i.info;
3212        }
3213        InstrumentationInfo ii = new InstrumentationInfo(i.info);
3214        ii.metaData = i.metaData;
3215        return ii;
3216    }
3217
3218    public static class IntentInfo extends IntentFilter {
3219        public boolean hasDefault;
3220        public int labelRes;
3221        public CharSequence nonLocalizedLabel;
3222        public int icon;
3223        public int logo;
3224    }
3225
3226    public final static class ActivityIntentInfo extends IntentInfo {
3227        public final Activity activity;
3228
3229        public ActivityIntentInfo(Activity _activity) {
3230            activity = _activity;
3231        }
3232
3233        public String toString() {
3234            return "ActivityIntentInfo{"
3235                + Integer.toHexString(System.identityHashCode(this))
3236                + " " + activity.info.name + "}";
3237        }
3238    }
3239
3240    public final static class ServiceIntentInfo extends IntentInfo {
3241        public final Service service;
3242
3243        public ServiceIntentInfo(Service _service) {
3244            service = _service;
3245        }
3246
3247        public String toString() {
3248            return "ServiceIntentInfo{"
3249                + Integer.toHexString(System.identityHashCode(this))
3250                + " " + service.info.name + "}";
3251        }
3252    }
3253
3254    /**
3255     * @hide
3256     */
3257    public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
3258        sCompatibilityModeEnabled = compatibilityModeEnabled;
3259    }
3260}
3261