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