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