PackageParser.java revision 6c55b8b143b4cc8335789bff58a2ac545bd58806
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_hardwareAccelerated,
1540                false)) {
1541            ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
1542        }
1543
1544        if (sa.getBoolean(
1545                com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
1546                true)) {
1547            ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
1548        }
1549
1550        if (sa.getBoolean(
1551                com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
1552                false)) {
1553            ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
1554        }
1555
1556        if (sa.getBoolean(
1557                com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
1558                true)) {
1559            ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
1560        }
1561
1562        if (sa.getBoolean(
1563                com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
1564                false)) {
1565            ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
1566        }
1567
1568        if (sa.getBoolean(
1569                com.android.internal.R.styleable.AndroidManifestApplication_neverEncrypt,
1570                false)) {
1571            ai.flags |= ApplicationInfo.FLAG_NEVER_ENCRYPT;
1572        }
1573
1574        String str;
1575        str = sa.getNonConfigurationString(
1576                com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
1577        ai.permission = (str != null && str.length() > 0) ? str.intern() : null;
1578
1579        if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
1580            str = sa.getNonConfigurationString(
1581                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, 0);
1582        } else {
1583            // Some older apps have been seen to use a resource reference
1584            // here that on older builds was ignored (with a warning).  We
1585            // need to continue to do this for them so they don't break.
1586            str = sa.getNonResourceString(
1587                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
1588        }
1589        ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
1590                str, outError);
1591
1592        if (outError[0] == null) {
1593            CharSequence pname;
1594            if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
1595                pname = sa.getNonConfigurationString(
1596                        com.android.internal.R.styleable.AndroidManifestApplication_process, 0);
1597            } else {
1598                // Some older apps have been seen to use a resource reference
1599                // here that on older builds was ignored (with a warning).  We
1600                // need to continue to do this for them so they don't break.
1601                pname = sa.getNonResourceString(
1602                        com.android.internal.R.styleable.AndroidManifestApplication_process);
1603            }
1604            ai.processName = buildProcessName(ai.packageName, null, pname,
1605                    flags, mSeparateProcesses, outError);
1606
1607            ai.enabled = sa.getBoolean(
1608                    com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
1609
1610            if (sa.getBoolean(
1611                    com.android.internal.R.styleable.AndroidManifestApplication_heavyWeight,
1612                    false)) {
1613                ai.flags |= ApplicationInfo.FLAG_HEAVY_WEIGHT;
1614
1615                // A heavy-weight application can not be in a custom process.
1616                // We can do direct compare because we intern all strings.
1617                if (ai.processName != null && ai.processName != ai.packageName) {
1618                    outError[0] = "Heavy-weight applications can not use custom processes";
1619                }
1620            }
1621        }
1622
1623        sa.recycle();
1624
1625        if (outError[0] != null) {
1626            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1627            return false;
1628        }
1629
1630        final int innerDepth = parser.getDepth();
1631
1632        int type;
1633        while ((type=parser.next()) != parser.END_DOCUMENT
1634               && (type != parser.END_TAG || parser.getDepth() > innerDepth)) {
1635            if (type == parser.END_TAG || type == parser.TEXT) {
1636                continue;
1637            }
1638
1639            String tagName = parser.getName();
1640            if (tagName.equals("activity")) {
1641                Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false);
1642                if (a == null) {
1643                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1644                    return false;
1645                }
1646
1647                owner.activities.add(a);
1648
1649            } else if (tagName.equals("receiver")) {
1650                Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true);
1651                if (a == null) {
1652                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1653                    return false;
1654                }
1655
1656                owner.receivers.add(a);
1657
1658            } else if (tagName.equals("service")) {
1659                Service s = parseService(owner, res, parser, attrs, flags, outError);
1660                if (s == null) {
1661                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1662                    return false;
1663                }
1664
1665                owner.services.add(s);
1666
1667            } else if (tagName.equals("provider")) {
1668                Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
1669                if (p == null) {
1670                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1671                    return false;
1672                }
1673
1674                owner.providers.add(p);
1675
1676            } else if (tagName.equals("activity-alias")) {
1677                Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);
1678                if (a == null) {
1679                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1680                    return false;
1681                }
1682
1683                owner.activities.add(a);
1684
1685            } else if (parser.getName().equals("meta-data")) {
1686                // note: application meta-data is stored off to the side, so it can
1687                // remain null in the primary copy (we like to avoid extra copies because
1688                // it can be large)
1689                if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData,
1690                        outError)) == null) {
1691                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1692                    return false;
1693                }
1694
1695            } else if (tagName.equals("uses-library")) {
1696                sa = res.obtainAttributes(attrs,
1697                        com.android.internal.R.styleable.AndroidManifestUsesLibrary);
1698
1699                // Note: don't allow this value to be a reference to a resource
1700                // that may change.
1701                String lname = sa.getNonResourceString(
1702                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
1703                boolean req = sa.getBoolean(
1704                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
1705                        true);
1706
1707                sa.recycle();
1708
1709                if (lname != null) {
1710                    if (req) {
1711                        if (owner.usesLibraries == null) {
1712                            owner.usesLibraries = new ArrayList<String>();
1713                        }
1714                        if (!owner.usesLibraries.contains(lname)) {
1715                            owner.usesLibraries.add(lname.intern());
1716                        }
1717                    } else {
1718                        if (owner.usesOptionalLibraries == null) {
1719                            owner.usesOptionalLibraries = new ArrayList<String>();
1720                        }
1721                        if (!owner.usesOptionalLibraries.contains(lname)) {
1722                            owner.usesOptionalLibraries.add(lname.intern());
1723                        }
1724                    }
1725                }
1726
1727                XmlUtils.skipCurrentTag(parser);
1728
1729            } else {
1730                if (!RIGID_PARSER) {
1731                    Log.w(TAG, "Unknown element under <application>: " + tagName
1732                            + " at " + mArchiveSourcePath + " "
1733                            + parser.getPositionDescription());
1734                    XmlUtils.skipCurrentTag(parser);
1735                    continue;
1736                } else {
1737                    outError[0] = "Bad element under <application>: " + tagName;
1738                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1739                    return false;
1740                }
1741            }
1742        }
1743
1744        return true;
1745    }
1746
1747    private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
1748            String[] outError, String tag, TypedArray sa,
1749            int nameRes, int labelRes, int iconRes, int logoRes) {
1750        String name = sa.getNonConfigurationString(nameRes, 0);
1751        if (name == null) {
1752            outError[0] = tag + " does not specify android:name";
1753            return false;
1754        }
1755
1756        outInfo.name
1757            = buildClassName(owner.applicationInfo.packageName, name, outError);
1758        if (outInfo.name == null) {
1759            return false;
1760        }
1761
1762        int iconVal = sa.getResourceId(iconRes, 0);
1763        if (iconVal != 0) {
1764            outInfo.icon = iconVal;
1765            outInfo.nonLocalizedLabel = null;
1766        }
1767
1768        int logoVal = sa.getResourceId(logoRes, 0);
1769        if (logoVal != 0) {
1770            outInfo.logo = logoVal;
1771        }
1772
1773        TypedValue v = sa.peekValue(labelRes);
1774        if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
1775            outInfo.nonLocalizedLabel = v.coerceToString();
1776        }
1777
1778        outInfo.packageName = owner.packageName;
1779
1780        return true;
1781    }
1782
1783    private Activity parseActivity(Package owner, Resources res,
1784            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
1785            boolean receiver) throws XmlPullParserException, IOException {
1786        TypedArray sa = res.obtainAttributes(attrs,
1787                com.android.internal.R.styleable.AndroidManifestActivity);
1788
1789        if (mParseActivityArgs == null) {
1790            mParseActivityArgs = new ParseComponentArgs(owner, outError,
1791                    com.android.internal.R.styleable.AndroidManifestActivity_name,
1792                    com.android.internal.R.styleable.AndroidManifestActivity_label,
1793                    com.android.internal.R.styleable.AndroidManifestActivity_icon,
1794                    com.android.internal.R.styleable.AndroidManifestActivity_logo,
1795                    mSeparateProcesses,
1796                    com.android.internal.R.styleable.AndroidManifestActivity_process,
1797                    com.android.internal.R.styleable.AndroidManifestActivity_description,
1798                    com.android.internal.R.styleable.AndroidManifestActivity_enabled);
1799        }
1800
1801        mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
1802        mParseActivityArgs.sa = sa;
1803        mParseActivityArgs.flags = flags;
1804
1805        Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
1806        if (outError[0] != null) {
1807            sa.recycle();
1808            return null;
1809        }
1810
1811        final boolean setExported = sa.hasValue(
1812                com.android.internal.R.styleable.AndroidManifestActivity_exported);
1813        if (setExported) {
1814            a.info.exported = sa.getBoolean(
1815                    com.android.internal.R.styleable.AndroidManifestActivity_exported, false);
1816        }
1817
1818        a.info.theme = sa.getResourceId(
1819                com.android.internal.R.styleable.AndroidManifestActivity_theme, 0);
1820
1821        String str;
1822        str = sa.getNonConfigurationString(
1823                com.android.internal.R.styleable.AndroidManifestActivity_permission, 0);
1824        if (str == null) {
1825            a.info.permission = owner.applicationInfo.permission;
1826        } else {
1827            a.info.permission = str.length() > 0 ? str.toString().intern() : null;
1828        }
1829
1830        str = sa.getNonConfigurationString(
1831                com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity, 0);
1832        a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
1833                owner.applicationInfo.taskAffinity, str, outError);
1834
1835        a.info.flags = 0;
1836        if (sa.getBoolean(
1837                com.android.internal.R.styleable.AndroidManifestActivity_multiprocess,
1838                false)) {
1839            a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
1840        }
1841
1842        if (sa.getBoolean(
1843                com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch,
1844                false)) {
1845            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
1846        }
1847
1848        if (sa.getBoolean(
1849                com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch,
1850                false)) {
1851            a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
1852        }
1853
1854        if (sa.getBoolean(
1855                com.android.internal.R.styleable.AndroidManifestActivity_noHistory,
1856                false)) {
1857            a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
1858        }
1859
1860        if (sa.getBoolean(
1861                com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState,
1862                false)) {
1863            a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
1864        }
1865
1866        if (sa.getBoolean(
1867                com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded,
1868                false)) {
1869            a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
1870        }
1871
1872        if (sa.getBoolean(
1873                com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents,
1874                false)) {
1875            a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
1876        }
1877
1878        if (sa.getBoolean(
1879                com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting,
1880                (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
1881            a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
1882        }
1883
1884        if (sa.getBoolean(
1885                com.android.internal.R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
1886                false)) {
1887            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
1888        }
1889
1890        if (sa.getBoolean(
1891                com.android.internal.R.styleable.AndroidManifestActivity_immersive,
1892                false)) {
1893            a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
1894        }
1895
1896        if (!receiver) {
1897            a.info.launchMode = sa.getInt(
1898                    com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
1899                    ActivityInfo.LAUNCH_MULTIPLE);
1900            a.info.screenOrientation = sa.getInt(
1901                    com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
1902                    ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
1903            a.info.configChanges = sa.getInt(
1904                    com.android.internal.R.styleable.AndroidManifestActivity_configChanges,
1905                    0);
1906            a.info.softInputMode = sa.getInt(
1907                    com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
1908                    0);
1909        } else {
1910            a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
1911            a.info.configChanges = 0;
1912        }
1913
1914        sa.recycle();
1915
1916        if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
1917            // A heavy-weight application can not have receives in its main process
1918            // We can do direct compare because we intern all strings.
1919            if (a.info.processName == owner.packageName) {
1920                outError[0] = "Heavy-weight applications can not have receivers in main process";
1921            }
1922        }
1923
1924        if (outError[0] != null) {
1925            return null;
1926        }
1927
1928        int outerDepth = parser.getDepth();
1929        int type;
1930        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1931               && (type != XmlPullParser.END_TAG
1932                       || parser.getDepth() > outerDepth)) {
1933            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1934                continue;
1935            }
1936
1937            if (parser.getName().equals("intent-filter")) {
1938                ActivityIntentInfo intent = new ActivityIntentInfo(a);
1939                if (!parseIntent(res, parser, attrs, flags, intent, outError, !receiver)) {
1940                    return null;
1941                }
1942                if (intent.countActions() == 0) {
1943                    Log.w(TAG, "No actions in intent filter at "
1944                            + mArchiveSourcePath + " "
1945                            + parser.getPositionDescription());
1946                } else {
1947                    a.intents.add(intent);
1948                }
1949            } else if (parser.getName().equals("meta-data")) {
1950                if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
1951                        outError)) == null) {
1952                    return null;
1953                }
1954            } else {
1955                if (!RIGID_PARSER) {
1956                    Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
1957                    if (receiver) {
1958                        Log.w(TAG, "Unknown element under <receiver>: " + parser.getName()
1959                                + " at " + mArchiveSourcePath + " "
1960                                + parser.getPositionDescription());
1961                    } else {
1962                        Log.w(TAG, "Unknown element under <activity>: " + parser.getName()
1963                                + " at " + mArchiveSourcePath + " "
1964                                + parser.getPositionDescription());
1965                    }
1966                    XmlUtils.skipCurrentTag(parser);
1967                    continue;
1968                }
1969                if (receiver) {
1970                    outError[0] = "Bad element under <receiver>: " + parser.getName();
1971                } else {
1972                    outError[0] = "Bad element under <activity>: " + parser.getName();
1973                }
1974                return null;
1975            }
1976        }
1977
1978        if (!setExported) {
1979            a.info.exported = a.intents.size() > 0;
1980        }
1981
1982        return a;
1983    }
1984
1985    private Activity parseActivityAlias(Package owner, Resources res,
1986            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
1987            throws XmlPullParserException, IOException {
1988        TypedArray sa = res.obtainAttributes(attrs,
1989                com.android.internal.R.styleable.AndroidManifestActivityAlias);
1990
1991        String targetActivity = sa.getNonConfigurationString(
1992                com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity, 0);
1993        if (targetActivity == null) {
1994            outError[0] = "<activity-alias> does not specify android:targetActivity";
1995            sa.recycle();
1996            return null;
1997        }
1998
1999        targetActivity = buildClassName(owner.applicationInfo.packageName,
2000                targetActivity, outError);
2001        if (targetActivity == null) {
2002            sa.recycle();
2003            return null;
2004        }
2005
2006        if (mParseActivityAliasArgs == null) {
2007            mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
2008                    com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
2009                    com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
2010                    com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
2011                    com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
2012                    mSeparateProcesses,
2013                    0,
2014                    com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
2015                    com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
2016            mParseActivityAliasArgs.tag = "<activity-alias>";
2017        }
2018
2019        mParseActivityAliasArgs.sa = sa;
2020        mParseActivityAliasArgs.flags = flags;
2021
2022        Activity target = null;
2023
2024        final int NA = owner.activities.size();
2025        for (int i=0; i<NA; i++) {
2026            Activity t = owner.activities.get(i);
2027            if (targetActivity.equals(t.info.name)) {
2028                target = t;
2029                break;
2030            }
2031        }
2032
2033        if (target == null) {
2034            outError[0] = "<activity-alias> target activity " + targetActivity
2035                    + " not found in manifest";
2036            sa.recycle();
2037            return null;
2038        }
2039
2040        ActivityInfo info = new ActivityInfo();
2041        info.targetActivity = targetActivity;
2042        info.configChanges = target.info.configChanges;
2043        info.flags = target.info.flags;
2044        info.icon = target.info.icon;
2045        info.logo = target.info.logo;
2046        info.labelRes = target.info.labelRes;
2047        info.nonLocalizedLabel = target.info.nonLocalizedLabel;
2048        info.launchMode = target.info.launchMode;
2049        info.processName = target.info.processName;
2050        if (info.descriptionRes == 0) {
2051            info.descriptionRes = target.info.descriptionRes;
2052        }
2053        info.screenOrientation = target.info.screenOrientation;
2054        info.taskAffinity = target.info.taskAffinity;
2055        info.theme = target.info.theme;
2056
2057        Activity a = new Activity(mParseActivityAliasArgs, info);
2058        if (outError[0] != null) {
2059            sa.recycle();
2060            return null;
2061        }
2062
2063        final boolean setExported = sa.hasValue(
2064                com.android.internal.R.styleable.AndroidManifestActivityAlias_exported);
2065        if (setExported) {
2066            a.info.exported = sa.getBoolean(
2067                    com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false);
2068        }
2069
2070        String str;
2071        str = sa.getNonConfigurationString(
2072                com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0);
2073        if (str != null) {
2074            a.info.permission = str.length() > 0 ? str.toString().intern() : null;
2075        }
2076
2077        sa.recycle();
2078
2079        if (outError[0] != null) {
2080            return null;
2081        }
2082
2083        int outerDepth = parser.getDepth();
2084        int type;
2085        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2086               && (type != XmlPullParser.END_TAG
2087                       || parser.getDepth() > outerDepth)) {
2088            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2089                continue;
2090            }
2091
2092            if (parser.getName().equals("intent-filter")) {
2093                ActivityIntentInfo intent = new ActivityIntentInfo(a);
2094                if (!parseIntent(res, parser, attrs, flags, intent, outError, true)) {
2095                    return null;
2096                }
2097                if (intent.countActions() == 0) {
2098                    Log.w(TAG, "No actions in intent filter at "
2099                            + mArchiveSourcePath + " "
2100                            + parser.getPositionDescription());
2101                } else {
2102                    a.intents.add(intent);
2103                }
2104            } else if (parser.getName().equals("meta-data")) {
2105                if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
2106                        outError)) == null) {
2107                    return null;
2108                }
2109            } else {
2110                if (!RIGID_PARSER) {
2111                    Log.w(TAG, "Unknown element under <activity-alias>: " + parser.getName()
2112                            + " at " + mArchiveSourcePath + " "
2113                            + parser.getPositionDescription());
2114                    XmlUtils.skipCurrentTag(parser);
2115                    continue;
2116                }
2117                outError[0] = "Bad element under <activity-alias>: " + parser.getName();
2118                return null;
2119            }
2120        }
2121
2122        if (!setExported) {
2123            a.info.exported = a.intents.size() > 0;
2124        }
2125
2126        return a;
2127    }
2128
2129    private Provider parseProvider(Package owner, Resources res,
2130            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
2131            throws XmlPullParserException, IOException {
2132        TypedArray sa = res.obtainAttributes(attrs,
2133                com.android.internal.R.styleable.AndroidManifestProvider);
2134
2135        if (mParseProviderArgs == null) {
2136            mParseProviderArgs = new ParseComponentArgs(owner, outError,
2137                    com.android.internal.R.styleable.AndroidManifestProvider_name,
2138                    com.android.internal.R.styleable.AndroidManifestProvider_label,
2139                    com.android.internal.R.styleable.AndroidManifestProvider_icon,
2140                    com.android.internal.R.styleable.AndroidManifestProvider_logo,
2141                    mSeparateProcesses,
2142                    com.android.internal.R.styleable.AndroidManifestProvider_process,
2143                    com.android.internal.R.styleable.AndroidManifestProvider_description,
2144                    com.android.internal.R.styleable.AndroidManifestProvider_enabled);
2145            mParseProviderArgs.tag = "<provider>";
2146        }
2147
2148        mParseProviderArgs.sa = sa;
2149        mParseProviderArgs.flags = flags;
2150
2151        Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
2152        if (outError[0] != null) {
2153            sa.recycle();
2154            return null;
2155        }
2156
2157        p.info.exported = sa.getBoolean(
2158                com.android.internal.R.styleable.AndroidManifestProvider_exported, true);
2159
2160        String cpname = sa.getNonConfigurationString(
2161                com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0);
2162
2163        p.info.isSyncable = sa.getBoolean(
2164                com.android.internal.R.styleable.AndroidManifestProvider_syncable,
2165                false);
2166
2167        String permission = sa.getNonConfigurationString(
2168                com.android.internal.R.styleable.AndroidManifestProvider_permission, 0);
2169        String str = sa.getNonConfigurationString(
2170                com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0);
2171        if (str == null) {
2172            str = permission;
2173        }
2174        if (str == null) {
2175            p.info.readPermission = owner.applicationInfo.permission;
2176        } else {
2177            p.info.readPermission =
2178                str.length() > 0 ? str.toString().intern() : null;
2179        }
2180        str = sa.getNonConfigurationString(
2181                com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0);
2182        if (str == null) {
2183            str = permission;
2184        }
2185        if (str == null) {
2186            p.info.writePermission = owner.applicationInfo.permission;
2187        } else {
2188            p.info.writePermission =
2189                str.length() > 0 ? str.toString().intern() : null;
2190        }
2191
2192        p.info.grantUriPermissions = sa.getBoolean(
2193                com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
2194                false);
2195
2196        p.info.multiprocess = sa.getBoolean(
2197                com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
2198                false);
2199
2200        p.info.initOrder = sa.getInt(
2201                com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
2202                0);
2203
2204        sa.recycle();
2205
2206        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
2207            // A heavy-weight application can not have providers in its main process
2208            // We can do direct compare because we intern all strings.
2209            if (p.info.processName == owner.packageName) {
2210                outError[0] = "Heavy-weight applications can not have providers in main process";
2211                return null;
2212            }
2213        }
2214
2215        if (cpname == null) {
2216            outError[0] = "<provider> does not incude authorities attribute";
2217            return null;
2218        }
2219        p.info.authority = cpname.intern();
2220
2221        if (!parseProviderTags(res, parser, attrs, p, outError)) {
2222            return null;
2223        }
2224
2225        return p;
2226    }
2227
2228    private boolean parseProviderTags(Resources res,
2229            XmlPullParser parser, AttributeSet attrs,
2230            Provider outInfo, String[] outError)
2231            throws XmlPullParserException, IOException {
2232        int outerDepth = parser.getDepth();
2233        int type;
2234        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2235               && (type != XmlPullParser.END_TAG
2236                       || parser.getDepth() > outerDepth)) {
2237            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2238                continue;
2239            }
2240
2241            if (parser.getName().equals("meta-data")) {
2242                if ((outInfo.metaData=parseMetaData(res, parser, attrs,
2243                        outInfo.metaData, outError)) == null) {
2244                    return false;
2245                }
2246
2247            } else if (parser.getName().equals("grant-uri-permission")) {
2248                TypedArray sa = res.obtainAttributes(attrs,
2249                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
2250
2251                PatternMatcher pa = null;
2252
2253                String str = sa.getNonConfigurationString(
2254                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0);
2255                if (str != null) {
2256                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
2257                }
2258
2259                str = sa.getNonConfigurationString(
2260                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
2261                if (str != null) {
2262                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
2263                }
2264
2265                str = sa.getNonConfigurationString(
2266                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
2267                if (str != null) {
2268                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
2269                }
2270
2271                sa.recycle();
2272
2273                if (pa != null) {
2274                    if (outInfo.info.uriPermissionPatterns == null) {
2275                        outInfo.info.uriPermissionPatterns = new PatternMatcher[1];
2276                        outInfo.info.uriPermissionPatterns[0] = pa;
2277                    } else {
2278                        final int N = outInfo.info.uriPermissionPatterns.length;
2279                        PatternMatcher[] newp = new PatternMatcher[N+1];
2280                        System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N);
2281                        newp[N] = pa;
2282                        outInfo.info.uriPermissionPatterns = newp;
2283                    }
2284                    outInfo.info.grantUriPermissions = true;
2285                } else {
2286                    if (!RIGID_PARSER) {
2287                        Log.w(TAG, "Unknown element under <path-permission>: "
2288                                + parser.getName() + " at " + mArchiveSourcePath + " "
2289                                + parser.getPositionDescription());
2290                        XmlUtils.skipCurrentTag(parser);
2291                        continue;
2292                    }
2293                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
2294                    return false;
2295                }
2296                XmlUtils.skipCurrentTag(parser);
2297
2298            } else if (parser.getName().equals("path-permission")) {
2299                TypedArray sa = res.obtainAttributes(attrs,
2300                        com.android.internal.R.styleable.AndroidManifestPathPermission);
2301
2302                PathPermission pa = null;
2303
2304                String permission = sa.getNonConfigurationString(
2305                        com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0);
2306                String readPermission = sa.getNonConfigurationString(
2307                        com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0);
2308                if (readPermission == null) {
2309                    readPermission = permission;
2310                }
2311                String writePermission = sa.getNonConfigurationString(
2312                        com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0);
2313                if (writePermission == null) {
2314                    writePermission = permission;
2315                }
2316
2317                boolean havePerm = false;
2318                if (readPermission != null) {
2319                    readPermission = readPermission.intern();
2320                    havePerm = true;
2321                }
2322                if (writePermission != null) {
2323                    writePermission = writePermission.intern();
2324                    havePerm = true;
2325                }
2326
2327                if (!havePerm) {
2328                    if (!RIGID_PARSER) {
2329                        Log.w(TAG, "No readPermission or writePermssion for <path-permission>: "
2330                                + parser.getName() + " at " + mArchiveSourcePath + " "
2331                                + parser.getPositionDescription());
2332                        XmlUtils.skipCurrentTag(parser);
2333                        continue;
2334                    }
2335                    outError[0] = "No readPermission or writePermssion for <path-permission>";
2336                    return false;
2337                }
2338
2339                String path = sa.getNonConfigurationString(
2340                        com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0);
2341                if (path != null) {
2342                    pa = new PathPermission(path,
2343                            PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
2344                }
2345
2346                path = sa.getNonConfigurationString(
2347                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
2348                if (path != null) {
2349                    pa = new PathPermission(path,
2350                            PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
2351                }
2352
2353                path = sa.getNonConfigurationString(
2354                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0);
2355                if (path != null) {
2356                    pa = new PathPermission(path,
2357                            PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
2358                }
2359
2360                sa.recycle();
2361
2362                if (pa != null) {
2363                    if (outInfo.info.pathPermissions == null) {
2364                        outInfo.info.pathPermissions = new PathPermission[1];
2365                        outInfo.info.pathPermissions[0] = pa;
2366                    } else {
2367                        final int N = outInfo.info.pathPermissions.length;
2368                        PathPermission[] newp = new PathPermission[N+1];
2369                        System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
2370                        newp[N] = pa;
2371                        outInfo.info.pathPermissions = newp;
2372                    }
2373                } else {
2374                    if (!RIGID_PARSER) {
2375                        Log.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
2376                                + parser.getName() + " at " + mArchiveSourcePath + " "
2377                                + parser.getPositionDescription());
2378                        XmlUtils.skipCurrentTag(parser);
2379                        continue;
2380                    }
2381                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
2382                    return false;
2383                }
2384                XmlUtils.skipCurrentTag(parser);
2385
2386            } else {
2387                if (!RIGID_PARSER) {
2388                    Log.w(TAG, "Unknown element under <provider>: "
2389                            + parser.getName() + " at " + mArchiveSourcePath + " "
2390                            + parser.getPositionDescription());
2391                    XmlUtils.skipCurrentTag(parser);
2392                    continue;
2393                }
2394                outError[0] = "Bad element under <provider>: "
2395                    + parser.getName();
2396                return false;
2397            }
2398        }
2399        return true;
2400    }
2401
2402    private Service parseService(Package owner, Resources res,
2403            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
2404            throws XmlPullParserException, IOException {
2405        TypedArray sa = res.obtainAttributes(attrs,
2406                com.android.internal.R.styleable.AndroidManifestService);
2407
2408        if (mParseServiceArgs == null) {
2409            mParseServiceArgs = new ParseComponentArgs(owner, outError,
2410                    com.android.internal.R.styleable.AndroidManifestService_name,
2411                    com.android.internal.R.styleable.AndroidManifestService_label,
2412                    com.android.internal.R.styleable.AndroidManifestService_icon,
2413                    com.android.internal.R.styleable.AndroidManifestService_logo,
2414                    mSeparateProcesses,
2415                    com.android.internal.R.styleable.AndroidManifestService_process,
2416                    com.android.internal.R.styleable.AndroidManifestService_description,
2417                    com.android.internal.R.styleable.AndroidManifestService_enabled);
2418            mParseServiceArgs.tag = "<service>";
2419        }
2420
2421        mParseServiceArgs.sa = sa;
2422        mParseServiceArgs.flags = flags;
2423
2424        Service s = new Service(mParseServiceArgs, new ServiceInfo());
2425        if (outError[0] != null) {
2426            sa.recycle();
2427            return null;
2428        }
2429
2430        final boolean setExported = sa.hasValue(
2431                com.android.internal.R.styleable.AndroidManifestService_exported);
2432        if (setExported) {
2433            s.info.exported = sa.getBoolean(
2434                    com.android.internal.R.styleable.AndroidManifestService_exported, false);
2435        }
2436
2437        String str = sa.getNonConfigurationString(
2438                com.android.internal.R.styleable.AndroidManifestService_permission, 0);
2439        if (str == null) {
2440            s.info.permission = owner.applicationInfo.permission;
2441        } else {
2442            s.info.permission = str.length() > 0 ? str.toString().intern() : null;
2443        }
2444
2445        sa.recycle();
2446
2447        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_HEAVY_WEIGHT) != 0) {
2448            // A heavy-weight application can not have services in its main process
2449            // We can do direct compare because we intern all strings.
2450            if (s.info.processName == owner.packageName) {
2451                outError[0] = "Heavy-weight applications can not have services in main process";
2452                return null;
2453            }
2454        }
2455
2456        int outerDepth = parser.getDepth();
2457        int type;
2458        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2459               && (type != XmlPullParser.END_TAG
2460                       || parser.getDepth() > outerDepth)) {
2461            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2462                continue;
2463            }
2464
2465            if (parser.getName().equals("intent-filter")) {
2466                ServiceIntentInfo intent = new ServiceIntentInfo(s);
2467                if (!parseIntent(res, parser, attrs, flags, intent, outError, false)) {
2468                    return null;
2469                }
2470
2471                s.intents.add(intent);
2472            } else if (parser.getName().equals("meta-data")) {
2473                if ((s.metaData=parseMetaData(res, parser, attrs, s.metaData,
2474                        outError)) == null) {
2475                    return null;
2476                }
2477            } else {
2478                if (!RIGID_PARSER) {
2479                    Log.w(TAG, "Unknown element under <service>: "
2480                            + parser.getName() + " at " + mArchiveSourcePath + " "
2481                            + parser.getPositionDescription());
2482                    XmlUtils.skipCurrentTag(parser);
2483                    continue;
2484                }
2485                outError[0] = "Bad element under <service>: "
2486                    + parser.getName();
2487                return null;
2488            }
2489        }
2490
2491        if (!setExported) {
2492            s.info.exported = s.intents.size() > 0;
2493        }
2494
2495        return s;
2496    }
2497
2498    private boolean parseAllMetaData(Resources res,
2499            XmlPullParser parser, AttributeSet attrs, String tag,
2500            Component outInfo, String[] outError)
2501            throws XmlPullParserException, IOException {
2502        int outerDepth = parser.getDepth();
2503        int type;
2504        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2505               && (type != XmlPullParser.END_TAG
2506                       || parser.getDepth() > outerDepth)) {
2507            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2508                continue;
2509            }
2510
2511            if (parser.getName().equals("meta-data")) {
2512                if ((outInfo.metaData=parseMetaData(res, parser, attrs,
2513                        outInfo.metaData, outError)) == null) {
2514                    return false;
2515                }
2516            } else {
2517                if (!RIGID_PARSER) {
2518                    Log.w(TAG, "Unknown element under " + tag + ": "
2519                            + parser.getName() + " at " + mArchiveSourcePath + " "
2520                            + parser.getPositionDescription());
2521                    XmlUtils.skipCurrentTag(parser);
2522                    continue;
2523                }
2524                outError[0] = "Bad element under " + tag + ": "
2525                    + parser.getName();
2526                return false;
2527            }
2528        }
2529        return true;
2530    }
2531
2532    private Bundle parseMetaData(Resources res,
2533            XmlPullParser parser, AttributeSet attrs,
2534            Bundle data, String[] outError)
2535            throws XmlPullParserException, IOException {
2536
2537        TypedArray sa = res.obtainAttributes(attrs,
2538                com.android.internal.R.styleable.AndroidManifestMetaData);
2539
2540        if (data == null) {
2541            data = new Bundle();
2542        }
2543
2544        String name = sa.getNonConfigurationString(
2545                com.android.internal.R.styleable.AndroidManifestMetaData_name, 0);
2546        if (name == null) {
2547            outError[0] = "<meta-data> requires an android:name attribute";
2548            sa.recycle();
2549            return null;
2550        }
2551
2552        name = name.intern();
2553
2554        TypedValue v = sa.peekValue(
2555                com.android.internal.R.styleable.AndroidManifestMetaData_resource);
2556        if (v != null && v.resourceId != 0) {
2557            //Log.i(TAG, "Meta data ref " + name + ": " + v);
2558            data.putInt(name, v.resourceId);
2559        } else {
2560            v = sa.peekValue(
2561                    com.android.internal.R.styleable.AndroidManifestMetaData_value);
2562            //Log.i(TAG, "Meta data " + name + ": " + v);
2563            if (v != null) {
2564                if (v.type == TypedValue.TYPE_STRING) {
2565                    CharSequence cs = v.coerceToString();
2566                    data.putString(name, cs != null ? cs.toString().intern() : null);
2567                } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
2568                    data.putBoolean(name, v.data != 0);
2569                } else if (v.type >= TypedValue.TYPE_FIRST_INT
2570                        && v.type <= TypedValue.TYPE_LAST_INT) {
2571                    data.putInt(name, v.data);
2572                } else if (v.type == TypedValue.TYPE_FLOAT) {
2573                    data.putFloat(name, v.getFloat());
2574                } else {
2575                    if (!RIGID_PARSER) {
2576                        Log.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: "
2577                                + parser.getName() + " at " + mArchiveSourcePath + " "
2578                                + parser.getPositionDescription());
2579                    } else {
2580                        outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types";
2581                        data = null;
2582                    }
2583                }
2584            } else {
2585                outError[0] = "<meta-data> requires an android:value or android:resource attribute";
2586                data = null;
2587            }
2588        }
2589
2590        sa.recycle();
2591
2592        XmlUtils.skipCurrentTag(parser);
2593
2594        return data;
2595    }
2596
2597    private static final String ANDROID_RESOURCES
2598            = "http://schemas.android.com/apk/res/android";
2599
2600    private boolean parseIntent(Resources res,
2601            XmlPullParser parser, AttributeSet attrs, int flags,
2602            IntentInfo outInfo, String[] outError, boolean isActivity)
2603            throws XmlPullParserException, IOException {
2604
2605        TypedArray sa = res.obtainAttributes(attrs,
2606                com.android.internal.R.styleable.AndroidManifestIntentFilter);
2607
2608        int priority = sa.getInt(
2609                com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
2610        if (priority > 0 && isActivity && (flags&PARSE_IS_SYSTEM) == 0) {
2611            Log.w(TAG, "Activity with priority > 0, forcing to 0 at "
2612                    + mArchiveSourcePath + " "
2613                    + parser.getPositionDescription());
2614            priority = 0;
2615        }
2616        outInfo.setPriority(priority);
2617
2618        TypedValue v = sa.peekValue(
2619                com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
2620        if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
2621            outInfo.nonLocalizedLabel = v.coerceToString();
2622        }
2623
2624        outInfo.icon = sa.getResourceId(
2625                com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
2626
2627        outInfo.logo = sa.getResourceId(
2628                com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
2629
2630        sa.recycle();
2631
2632        int outerDepth = parser.getDepth();
2633        int type;
2634        while ((type=parser.next()) != parser.END_DOCUMENT
2635               && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {
2636            if (type == parser.END_TAG || type == parser.TEXT) {
2637                continue;
2638            }
2639
2640            String nodeName = parser.getName();
2641            if (nodeName.equals("action")) {
2642                String value = attrs.getAttributeValue(
2643                        ANDROID_RESOURCES, "name");
2644                if (value == null || value == "") {
2645                    outError[0] = "No value supplied for <android:name>";
2646                    return false;
2647                }
2648                XmlUtils.skipCurrentTag(parser);
2649
2650                outInfo.addAction(value);
2651            } else if (nodeName.equals("category")) {
2652                String value = attrs.getAttributeValue(
2653                        ANDROID_RESOURCES, "name");
2654                if (value == null || value == "") {
2655                    outError[0] = "No value supplied for <android:name>";
2656                    return false;
2657                }
2658                XmlUtils.skipCurrentTag(parser);
2659
2660                outInfo.addCategory(value);
2661
2662            } else if (nodeName.equals("data")) {
2663                sa = res.obtainAttributes(attrs,
2664                        com.android.internal.R.styleable.AndroidManifestData);
2665
2666                String str = sa.getNonConfigurationString(
2667                        com.android.internal.R.styleable.AndroidManifestData_mimeType, 0);
2668                if (str != null) {
2669                    try {
2670                        outInfo.addDataType(str);
2671                    } catch (IntentFilter.MalformedMimeTypeException e) {
2672                        outError[0] = e.toString();
2673                        sa.recycle();
2674                        return false;
2675                    }
2676                }
2677
2678                str = sa.getNonConfigurationString(
2679                        com.android.internal.R.styleable.AndroidManifestData_scheme, 0);
2680                if (str != null) {
2681                    outInfo.addDataScheme(str);
2682                }
2683
2684                String host = sa.getNonConfigurationString(
2685                        com.android.internal.R.styleable.AndroidManifestData_host, 0);
2686                String port = sa.getNonConfigurationString(
2687                        com.android.internal.R.styleable.AndroidManifestData_port, 0);
2688                if (host != null) {
2689                    outInfo.addDataAuthority(host, port);
2690                }
2691
2692                str = sa.getNonConfigurationString(
2693                        com.android.internal.R.styleable.AndroidManifestData_path, 0);
2694                if (str != null) {
2695                    outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
2696                }
2697
2698                str = sa.getNonConfigurationString(
2699                        com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0);
2700                if (str != null) {
2701                    outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
2702                }
2703
2704                str = sa.getNonConfigurationString(
2705                        com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
2706                if (str != null) {
2707                    outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
2708                }
2709
2710                sa.recycle();
2711                XmlUtils.skipCurrentTag(parser);
2712            } else if (!RIGID_PARSER) {
2713                Log.w(TAG, "Unknown element under <intent-filter>: "
2714                        + parser.getName() + " at " + mArchiveSourcePath + " "
2715                        + parser.getPositionDescription());
2716                XmlUtils.skipCurrentTag(parser);
2717            } else {
2718                outError[0] = "Bad element under <intent-filter>: " + parser.getName();
2719                return false;
2720            }
2721        }
2722
2723        outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
2724        if (false) {
2725            String cats = "";
2726            Iterator<String> it = outInfo.categoriesIterator();
2727            while (it != null && it.hasNext()) {
2728                cats += " " + it.next();
2729            }
2730            System.out.println("Intent d=" +
2731                    outInfo.hasDefault + ", cat=" + cats);
2732        }
2733
2734        return true;
2735    }
2736
2737    public final static class Package {
2738        public String packageName;
2739
2740        // For now we only support one application per package.
2741        public final ApplicationInfo applicationInfo = new ApplicationInfo();
2742
2743        public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
2744        public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
2745        public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
2746        public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
2747        public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
2748        public final ArrayList<Service> services = new ArrayList<Service>(0);
2749        public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
2750
2751        public final ArrayList<String> requestedPermissions = new ArrayList<String>();
2752
2753        public ArrayList<String> protectedBroadcasts;
2754
2755        public ArrayList<String> usesLibraries = null;
2756        public ArrayList<String> usesOptionalLibraries = null;
2757        public String[] usesLibraryFiles = null;
2758
2759        public ArrayList<String> mOriginalPackages = null;
2760        public String mRealPackage = null;
2761        public ArrayList<String> mAdoptPermissions = null;
2762
2763        // We store the application meta-data independently to avoid multiple unwanted references
2764        public Bundle mAppMetaData = null;
2765
2766        // If this is a 3rd party app, this is the path of the zip file.
2767        public String mPath;
2768
2769        // The version code declared for this package.
2770        public int mVersionCode;
2771
2772        // The version name declared for this package.
2773        public String mVersionName;
2774
2775        // The shared user id that this package wants to use.
2776        public String mSharedUserId;
2777
2778        // The shared user label that this package wants to use.
2779        public int mSharedUserLabel;
2780
2781        // Signatures that were read from the package.
2782        public Signature mSignatures[];
2783
2784        // For use by package manager service for quick lookup of
2785        // preferred up order.
2786        public int mPreferredOrder = 0;
2787
2788        // For use by the package manager to keep track of the path to the
2789        // file an app came from.
2790        public String mScanPath;
2791
2792        // For use by package manager to keep track of where it has done dexopt.
2793        public boolean mDidDexOpt;
2794
2795        // Additional data supplied by callers.
2796        public Object mExtras;
2797
2798        /*
2799         *  Applications hardware preferences
2800         */
2801        public final ArrayList<ConfigurationInfo> configPreferences =
2802                new ArrayList<ConfigurationInfo>();
2803
2804        /*
2805         *  Applications requested features
2806         */
2807        public ArrayList<FeatureInfo> reqFeatures = null;
2808
2809        public int installLocation;
2810
2811        public Package(String _name) {
2812            packageName = _name;
2813            applicationInfo.packageName = _name;
2814            applicationInfo.uid = -1;
2815        }
2816
2817        public void setPackageName(String newName) {
2818            packageName = newName;
2819            applicationInfo.packageName = newName;
2820            for (int i=permissions.size()-1; i>=0; i--) {
2821                permissions.get(i).setPackageName(newName);
2822            }
2823            for (int i=permissionGroups.size()-1; i>=0; i--) {
2824                permissionGroups.get(i).setPackageName(newName);
2825            }
2826            for (int i=activities.size()-1; i>=0; i--) {
2827                activities.get(i).setPackageName(newName);
2828            }
2829            for (int i=receivers.size()-1; i>=0; i--) {
2830                receivers.get(i).setPackageName(newName);
2831            }
2832            for (int i=providers.size()-1; i>=0; i--) {
2833                providers.get(i).setPackageName(newName);
2834            }
2835            for (int i=services.size()-1; i>=0; i--) {
2836                services.get(i).setPackageName(newName);
2837            }
2838            for (int i=instrumentation.size()-1; i>=0; i--) {
2839                instrumentation.get(i).setPackageName(newName);
2840            }
2841        }
2842
2843        public String toString() {
2844            return "Package{"
2845                + Integer.toHexString(System.identityHashCode(this))
2846                + " " + packageName + "}";
2847        }
2848    }
2849
2850    public static class Component<II extends IntentInfo> {
2851        public final Package owner;
2852        public final ArrayList<II> intents;
2853        public final String className;
2854        public Bundle metaData;
2855
2856        ComponentName componentName;
2857        String componentShortName;
2858
2859        public Component(Package _owner) {
2860            owner = _owner;
2861            intents = null;
2862            className = null;
2863        }
2864
2865        public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
2866            owner = args.owner;
2867            intents = new ArrayList<II>(0);
2868            String name = args.sa.getNonConfigurationString(args.nameRes, 0);
2869            if (name == null) {
2870                className = null;
2871                args.outError[0] = args.tag + " does not specify android:name";
2872                return;
2873            }
2874
2875            outInfo.name
2876                = buildClassName(owner.applicationInfo.packageName, name, args.outError);
2877            if (outInfo.name == null) {
2878                className = null;
2879                args.outError[0] = args.tag + " does not have valid android:name";
2880                return;
2881            }
2882
2883            className = outInfo.name;
2884
2885            int iconVal = args.sa.getResourceId(args.iconRes, 0);
2886            if (iconVal != 0) {
2887                outInfo.icon = iconVal;
2888                outInfo.nonLocalizedLabel = null;
2889            }
2890
2891            int logoVal = args.sa.getResourceId(args.logoRes, 0);
2892            if (logoVal != 0) {
2893                outInfo.logo = logoVal;
2894            }
2895
2896            TypedValue v = args.sa.peekValue(args.labelRes);
2897            if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
2898                outInfo.nonLocalizedLabel = v.coerceToString();
2899            }
2900
2901            outInfo.packageName = owner.packageName;
2902        }
2903
2904        public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
2905            this(args, (PackageItemInfo)outInfo);
2906            if (args.outError[0] != null) {
2907                return;
2908            }
2909
2910            if (args.processRes != 0) {
2911                CharSequence pname;
2912                if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
2913                    pname = args.sa.getNonConfigurationString(args.processRes, 0);
2914                } else {
2915                    // Some older apps have been seen to use a resource reference
2916                    // here that on older builds was ignored (with a warning).  We
2917                    // need to continue to do this for them so they don't break.
2918                    pname = args.sa.getNonResourceString(args.processRes);
2919                }
2920                outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
2921                        owner.applicationInfo.processName, pname,
2922                        args.flags, args.sepProcesses, args.outError);
2923            }
2924
2925            if (args.descriptionRes != 0) {
2926                outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
2927            }
2928
2929            outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
2930        }
2931
2932        public Component(Component<II> clone) {
2933            owner = clone.owner;
2934            intents = clone.intents;
2935            className = clone.className;
2936            componentName = clone.componentName;
2937            componentShortName = clone.componentShortName;
2938        }
2939
2940        public ComponentName getComponentName() {
2941            if (componentName != null) {
2942                return componentName;
2943            }
2944            if (className != null) {
2945                componentName = new ComponentName(owner.applicationInfo.packageName,
2946                        className);
2947            }
2948            return componentName;
2949        }
2950
2951        public String getComponentShortName() {
2952            if (componentShortName != null) {
2953                return componentShortName;
2954            }
2955            ComponentName component = getComponentName();
2956            if (component != null) {
2957                componentShortName = component.flattenToShortString();
2958            }
2959            return componentShortName;
2960        }
2961
2962        public void setPackageName(String packageName) {
2963            componentName = null;
2964            componentShortName = null;
2965        }
2966    }
2967
2968    public final static class Permission extends Component<IntentInfo> {
2969        public final PermissionInfo info;
2970        public boolean tree;
2971        public PermissionGroup group;
2972
2973        public Permission(Package _owner) {
2974            super(_owner);
2975            info = new PermissionInfo();
2976        }
2977
2978        public Permission(Package _owner, PermissionInfo _info) {
2979            super(_owner);
2980            info = _info;
2981        }
2982
2983        public void setPackageName(String packageName) {
2984            super.setPackageName(packageName);
2985            info.packageName = packageName;
2986        }
2987
2988        public String toString() {
2989            return "Permission{"
2990                + Integer.toHexString(System.identityHashCode(this))
2991                + " " + info.name + "}";
2992        }
2993    }
2994
2995    public final static class PermissionGroup extends Component<IntentInfo> {
2996        public final PermissionGroupInfo info;
2997
2998        public PermissionGroup(Package _owner) {
2999            super(_owner);
3000            info = new PermissionGroupInfo();
3001        }
3002
3003        public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
3004            super(_owner);
3005            info = _info;
3006        }
3007
3008        public void setPackageName(String packageName) {
3009            super.setPackageName(packageName);
3010            info.packageName = packageName;
3011        }
3012
3013        public String toString() {
3014            return "PermissionGroup{"
3015                + Integer.toHexString(System.identityHashCode(this))
3016                + " " + info.name + "}";
3017        }
3018    }
3019
3020    private static boolean copyNeeded(int flags, Package p, Bundle metaData) {
3021        if ((flags & PackageManager.GET_META_DATA) != 0
3022                && (metaData != null || p.mAppMetaData != null)) {
3023            return true;
3024        }
3025        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
3026                && p.usesLibraryFiles != null) {
3027            return true;
3028        }
3029        return false;
3030    }
3031
3032    public static ApplicationInfo generateApplicationInfo(Package p, int flags) {
3033        if (p == null) return null;
3034        if (!copyNeeded(flags, p, null)) {
3035            // CompatibilityMode is global state. It's safe to modify the instance
3036            // of the package.
3037            if (!sCompatibilityModeEnabled) {
3038                p.applicationInfo.disableCompatibilityMode();
3039            }
3040            return p.applicationInfo;
3041        }
3042
3043        // Make shallow copy so we can store the metadata/libraries safely
3044        ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
3045        if ((flags & PackageManager.GET_META_DATA) != 0) {
3046            ai.metaData = p.mAppMetaData;
3047        }
3048        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
3049            ai.sharedLibraryFiles = p.usesLibraryFiles;
3050        }
3051        if (!sCompatibilityModeEnabled) {
3052            ai.disableCompatibilityMode();
3053        }
3054        return ai;
3055    }
3056
3057    public static final PermissionInfo generatePermissionInfo(
3058            Permission p, int flags) {
3059        if (p == null) return null;
3060        if ((flags&PackageManager.GET_META_DATA) == 0) {
3061            return p.info;
3062        }
3063        PermissionInfo pi = new PermissionInfo(p.info);
3064        pi.metaData = p.metaData;
3065        return pi;
3066    }
3067
3068    public static final PermissionGroupInfo generatePermissionGroupInfo(
3069            PermissionGroup pg, int flags) {
3070        if (pg == null) return null;
3071        if ((flags&PackageManager.GET_META_DATA) == 0) {
3072            return pg.info;
3073        }
3074        PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);
3075        pgi.metaData = pg.metaData;
3076        return pgi;
3077    }
3078
3079    public final static class Activity extends Component<ActivityIntentInfo> {
3080        public final ActivityInfo info;
3081
3082        public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
3083            super(args, _info);
3084            info = _info;
3085            info.applicationInfo = args.owner.applicationInfo;
3086        }
3087
3088        public void setPackageName(String packageName) {
3089            super.setPackageName(packageName);
3090            info.packageName = packageName;
3091        }
3092
3093        public String toString() {
3094            return "Activity{"
3095                + Integer.toHexString(System.identityHashCode(this))
3096                + " " + getComponentShortName() + "}";
3097        }
3098    }
3099
3100    public static final ActivityInfo generateActivityInfo(Activity a,
3101            int flags) {
3102        if (a == null) return null;
3103        if (!copyNeeded(flags, a.owner, a.metaData)) {
3104            return a.info;
3105        }
3106        // Make shallow copies so we can store the metadata safely
3107        ActivityInfo ai = new ActivityInfo(a.info);
3108        ai.metaData = a.metaData;
3109        ai.applicationInfo = generateApplicationInfo(a.owner, flags);
3110        return ai;
3111    }
3112
3113    public final static class Service extends Component<ServiceIntentInfo> {
3114        public final ServiceInfo info;
3115
3116        public Service(final ParseComponentArgs args, final ServiceInfo _info) {
3117            super(args, _info);
3118            info = _info;
3119            info.applicationInfo = args.owner.applicationInfo;
3120        }
3121
3122        public void setPackageName(String packageName) {
3123            super.setPackageName(packageName);
3124            info.packageName = packageName;
3125        }
3126
3127        public String toString() {
3128            return "Service{"
3129                + Integer.toHexString(System.identityHashCode(this))
3130                + " " + getComponentShortName() + "}";
3131        }
3132    }
3133
3134    public static final ServiceInfo generateServiceInfo(Service s, int flags) {
3135        if (s == null) return null;
3136        if (!copyNeeded(flags, s.owner, s.metaData)) {
3137            return s.info;
3138        }
3139        // Make shallow copies so we can store the metadata safely
3140        ServiceInfo si = new ServiceInfo(s.info);
3141        si.metaData = s.metaData;
3142        si.applicationInfo = generateApplicationInfo(s.owner, flags);
3143        return si;
3144    }
3145
3146    public final static class Provider extends Component {
3147        public final ProviderInfo info;
3148        public boolean syncable;
3149
3150        public Provider(final ParseComponentArgs args, final ProviderInfo _info) {
3151            super(args, _info);
3152            info = _info;
3153            info.applicationInfo = args.owner.applicationInfo;
3154            syncable = false;
3155        }
3156
3157        public Provider(Provider existingProvider) {
3158            super(existingProvider);
3159            this.info = existingProvider.info;
3160            this.syncable = existingProvider.syncable;
3161        }
3162
3163        public void setPackageName(String packageName) {
3164            super.setPackageName(packageName);
3165            info.packageName = packageName;
3166        }
3167
3168        public String toString() {
3169            return "Provider{"
3170                + Integer.toHexString(System.identityHashCode(this))
3171                + " " + info.name + "}";
3172        }
3173    }
3174
3175    public static final ProviderInfo generateProviderInfo(Provider p,
3176            int flags) {
3177        if (p == null) return null;
3178        if (!copyNeeded(flags, p.owner, p.metaData)
3179                && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
3180                        || p.info.uriPermissionPatterns == null)) {
3181            return p.info;
3182        }
3183        // Make shallow copies so we can store the metadata safely
3184        ProviderInfo pi = new ProviderInfo(p.info);
3185        pi.metaData = p.metaData;
3186        if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
3187            pi.uriPermissionPatterns = null;
3188        }
3189        pi.applicationInfo = generateApplicationInfo(p.owner, flags);
3190        return pi;
3191    }
3192
3193    public final static class Instrumentation extends Component {
3194        public final InstrumentationInfo info;
3195
3196        public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
3197            super(args, _info);
3198            info = _info;
3199        }
3200
3201        public void setPackageName(String packageName) {
3202            super.setPackageName(packageName);
3203            info.packageName = packageName;
3204        }
3205
3206        public String toString() {
3207            return "Instrumentation{"
3208                + Integer.toHexString(System.identityHashCode(this))
3209                + " " + getComponentShortName() + "}";
3210        }
3211    }
3212
3213    public static final InstrumentationInfo generateInstrumentationInfo(
3214            Instrumentation i, int flags) {
3215        if (i == null) return null;
3216        if ((flags&PackageManager.GET_META_DATA) == 0) {
3217            return i.info;
3218        }
3219        InstrumentationInfo ii = new InstrumentationInfo(i.info);
3220        ii.metaData = i.metaData;
3221        return ii;
3222    }
3223
3224    public static class IntentInfo extends IntentFilter {
3225        public boolean hasDefault;
3226        public int labelRes;
3227        public CharSequence nonLocalizedLabel;
3228        public int icon;
3229        public int logo;
3230    }
3231
3232    public final static class ActivityIntentInfo extends IntentInfo {
3233        public final Activity activity;
3234
3235        public ActivityIntentInfo(Activity _activity) {
3236            activity = _activity;
3237        }
3238
3239        public String toString() {
3240            return "ActivityIntentInfo{"
3241                + Integer.toHexString(System.identityHashCode(this))
3242                + " " + activity.info.name + "}";
3243        }
3244    }
3245
3246    public final static class ServiceIntentInfo extends IntentInfo {
3247        public final Service service;
3248
3249        public ServiceIntentInfo(Service _service) {
3250            service = _service;
3251        }
3252
3253        public String toString() {
3254            return "ServiceIntentInfo{"
3255                + Integer.toHexString(System.identityHashCode(this))
3256                + " " + service.info.name + "}";
3257        }
3258    }
3259
3260    /**
3261     * @hide
3262     */
3263    public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
3264        sCompatibilityModeEnabled = compatibilityModeEnabled;
3265    }
3266}
3267