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