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