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