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