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