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