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