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