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