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