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