PackageParser.java revision 589a1bc0b00e570db079b4b157f60229ad8ef8f9
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        if (sa.getBoolean(
2309                com.android.internal.R.styleable.AndroidManifestApplication_multiArch,
2310                false)) {
2311            ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
2312        }
2313
2314        String str;
2315        str = sa.getNonConfigurationString(
2316                com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
2317        ai.permission = (str != null && str.length() > 0) ? str.intern() : null;
2318
2319        if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
2320            str = sa.getNonConfigurationString(
2321                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity,
2322                    Configuration.NATIVE_CONFIG_VERSION);
2323        } else {
2324            // Some older apps have been seen to use a resource reference
2325            // here that on older builds was ignored (with a warning).  We
2326            // need to continue to do this for them so they don't break.
2327            str = sa.getNonResourceString(
2328                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
2329        }
2330        ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
2331                str, outError);
2332
2333        if (outError[0] == null) {
2334            CharSequence pname;
2335            if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
2336                pname = sa.getNonConfigurationString(
2337                        com.android.internal.R.styleable.AndroidManifestApplication_process,
2338                        Configuration.NATIVE_CONFIG_VERSION);
2339            } else {
2340                // Some older apps have been seen to use a resource reference
2341                // here that on older builds was ignored (with a warning).  We
2342                // need to continue to do this for them so they don't break.
2343                pname = sa.getNonResourceString(
2344                        com.android.internal.R.styleable.AndroidManifestApplication_process);
2345            }
2346            ai.processName = buildProcessName(ai.packageName, null, pname,
2347                    flags, mSeparateProcesses, outError);
2348
2349            ai.enabled = sa.getBoolean(
2350                    com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
2351
2352            if (sa.getBoolean(
2353                    com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) {
2354                ai.flags |= ApplicationInfo.FLAG_IS_GAME;
2355            }
2356
2357            if (false) {
2358                if (sa.getBoolean(
2359                        com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
2360                        false)) {
2361                    ai.flags |= ApplicationInfo.FLAG_CANT_SAVE_STATE;
2362
2363                    // A heavy-weight application can not be in a custom process.
2364                    // We can do direct compare because we intern all strings.
2365                    if (ai.processName != null && ai.processName != ai.packageName) {
2366                        outError[0] = "cantSaveState applications can not use custom processes";
2367                    }
2368                }
2369            }
2370        }
2371
2372        ai.uiOptions = sa.getInt(
2373                com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);
2374
2375        sa.recycle();
2376
2377        if (outError[0] != null) {
2378            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2379            return false;
2380        }
2381
2382        final int innerDepth = parser.getDepth();
2383        int type;
2384        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2385                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
2386            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2387                continue;
2388            }
2389
2390            String tagName = parser.getName();
2391            if (tagName.equals("activity")) {
2392                Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
2393                        hardwareAccelerated);
2394                if (a == null) {
2395                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2396                    return false;
2397                }
2398
2399                owner.activities.add(a);
2400
2401            } else if (tagName.equals("receiver")) {
2402                Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);
2403                if (a == null) {
2404                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2405                    return false;
2406                }
2407
2408                owner.receivers.add(a);
2409
2410            } else if (tagName.equals("service")) {
2411                Service s = parseService(owner, res, parser, attrs, flags, outError);
2412                if (s == null) {
2413                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2414                    return false;
2415                }
2416
2417                owner.services.add(s);
2418
2419            } else if (tagName.equals("provider")) {
2420                Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
2421                if (p == null) {
2422                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2423                    return false;
2424                }
2425
2426                owner.providers.add(p);
2427
2428            } else if (tagName.equals("activity-alias")) {
2429                Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);
2430                if (a == null) {
2431                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2432                    return false;
2433                }
2434
2435                owner.activities.add(a);
2436
2437            } else if (parser.getName().equals("meta-data")) {
2438                // note: application meta-data is stored off to the side, so it can
2439                // remain null in the primary copy (we like to avoid extra copies because
2440                // it can be large)
2441                if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData,
2442                        outError)) == null) {
2443                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2444                    return false;
2445                }
2446
2447            } else if (tagName.equals("library")) {
2448                sa = res.obtainAttributes(attrs,
2449                        com.android.internal.R.styleable.AndroidManifestLibrary);
2450
2451                // Note: don't allow this value to be a reference to a resource
2452                // that may change.
2453                String lname = sa.getNonResourceString(
2454                        com.android.internal.R.styleable.AndroidManifestLibrary_name);
2455
2456                sa.recycle();
2457
2458                if (lname != null) {
2459                    if (owner.libraryNames == null) {
2460                        owner.libraryNames = new ArrayList<String>();
2461                    }
2462                    if (!owner.libraryNames.contains(lname)) {
2463                        owner.libraryNames.add(lname.intern());
2464                    }
2465                }
2466
2467                XmlUtils.skipCurrentTag(parser);
2468
2469            } else if (tagName.equals("uses-library")) {
2470                sa = res.obtainAttributes(attrs,
2471                        com.android.internal.R.styleable.AndroidManifestUsesLibrary);
2472
2473                // Note: don't allow this value to be a reference to a resource
2474                // that may change.
2475                String lname = sa.getNonResourceString(
2476                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
2477                boolean req = sa.getBoolean(
2478                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
2479                        true);
2480
2481                sa.recycle();
2482
2483                if (lname != null) {
2484                    if (req) {
2485                        if (owner.usesLibraries == null) {
2486                            owner.usesLibraries = new ArrayList<String>();
2487                        }
2488                        if (!owner.usesLibraries.contains(lname)) {
2489                            owner.usesLibraries.add(lname.intern());
2490                        }
2491                    } else {
2492                        if (owner.usesOptionalLibraries == null) {
2493                            owner.usesOptionalLibraries = new ArrayList<String>();
2494                        }
2495                        if (!owner.usesOptionalLibraries.contains(lname)) {
2496                            owner.usesOptionalLibraries.add(lname.intern());
2497                        }
2498                    }
2499                }
2500
2501                XmlUtils.skipCurrentTag(parser);
2502
2503            } else if (tagName.equals("uses-package")) {
2504                // Dependencies for app installers; we don't currently try to
2505                // enforce this.
2506                XmlUtils.skipCurrentTag(parser);
2507
2508            } else {
2509                if (!RIGID_PARSER) {
2510                    Slog.w(TAG, "Unknown element under <application>: " + tagName
2511                            + " at " + mArchiveSourcePath + " "
2512                            + parser.getPositionDescription());
2513                    XmlUtils.skipCurrentTag(parser);
2514                    continue;
2515                } else {
2516                    outError[0] = "Bad element under <application>: " + tagName;
2517                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2518                    return false;
2519                }
2520            }
2521        }
2522
2523        return true;
2524    }
2525
2526    private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
2527            String[] outError, String tag, TypedArray sa,
2528            int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) {
2529        String name = sa.getNonConfigurationString(nameRes, 0);
2530        if (name == null) {
2531            outError[0] = tag + " does not specify android:name";
2532            return false;
2533        }
2534
2535        outInfo.name
2536            = buildClassName(owner.applicationInfo.packageName, name, outError);
2537        if (outInfo.name == null) {
2538            return false;
2539        }
2540
2541        int iconVal = sa.getResourceId(iconRes, 0);
2542        if (iconVal != 0) {
2543            outInfo.icon = iconVal;
2544            outInfo.nonLocalizedLabel = null;
2545        }
2546
2547        int logoVal = sa.getResourceId(logoRes, 0);
2548        if (logoVal != 0) {
2549            outInfo.logo = logoVal;
2550        }
2551
2552        int bannerVal = sa.getResourceId(bannerRes, 0);
2553        if (bannerVal != 0) {
2554            outInfo.banner = bannerVal;
2555        }
2556
2557        TypedValue v = sa.peekValue(labelRes);
2558        if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
2559            outInfo.nonLocalizedLabel = v.coerceToString();
2560        }
2561
2562        outInfo.packageName = owner.packageName;
2563
2564        return true;
2565    }
2566
2567    private Activity parseActivity(Package owner, Resources res,
2568            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
2569            boolean receiver, boolean hardwareAccelerated)
2570            throws XmlPullParserException, IOException {
2571        TypedArray sa = res.obtainAttributes(attrs,
2572                com.android.internal.R.styleable.AndroidManifestActivity);
2573
2574        if (mParseActivityArgs == null) {
2575            mParseActivityArgs = new ParseComponentArgs(owner, outError,
2576                    com.android.internal.R.styleable.AndroidManifestActivity_name,
2577                    com.android.internal.R.styleable.AndroidManifestActivity_label,
2578                    com.android.internal.R.styleable.AndroidManifestActivity_icon,
2579                    com.android.internal.R.styleable.AndroidManifestActivity_logo,
2580                    com.android.internal.R.styleable.AndroidManifestActivity_banner,
2581                    mSeparateProcesses,
2582                    com.android.internal.R.styleable.AndroidManifestActivity_process,
2583                    com.android.internal.R.styleable.AndroidManifestActivity_description,
2584                    com.android.internal.R.styleable.AndroidManifestActivity_enabled);
2585        }
2586
2587        mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
2588        mParseActivityArgs.sa = sa;
2589        mParseActivityArgs.flags = flags;
2590
2591        Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
2592        if (outError[0] != null) {
2593            sa.recycle();
2594            return null;
2595        }
2596
2597        boolean setExported = sa.hasValue(
2598                com.android.internal.R.styleable.AndroidManifestActivity_exported);
2599        if (setExported) {
2600            a.info.exported = sa.getBoolean(
2601                    com.android.internal.R.styleable.AndroidManifestActivity_exported, false);
2602        }
2603
2604        a.info.theme = sa.getResourceId(
2605                com.android.internal.R.styleable.AndroidManifestActivity_theme, 0);
2606
2607        a.info.uiOptions = sa.getInt(
2608                com.android.internal.R.styleable.AndroidManifestActivity_uiOptions,
2609                a.info.applicationInfo.uiOptions);
2610
2611        String parentName = sa.getNonConfigurationString(
2612                com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName,
2613                Configuration.NATIVE_CONFIG_VERSION);
2614        if (parentName != null) {
2615            String parentClassName = buildClassName(a.info.packageName, parentName, outError);
2616            if (outError[0] == null) {
2617                a.info.parentActivityName = parentClassName;
2618            } else {
2619                Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " +
2620                        parentName);
2621                outError[0] = null;
2622            }
2623        }
2624
2625        String str;
2626        str = sa.getNonConfigurationString(
2627                com.android.internal.R.styleable.AndroidManifestActivity_permission, 0);
2628        if (str == null) {
2629            a.info.permission = owner.applicationInfo.permission;
2630        } else {
2631            a.info.permission = str.length() > 0 ? str.toString().intern() : null;
2632        }
2633
2634        str = sa.getNonConfigurationString(
2635                com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity,
2636                Configuration.NATIVE_CONFIG_VERSION);
2637        a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
2638                owner.applicationInfo.taskAffinity, str, outError);
2639
2640        a.info.flags = 0;
2641        if (sa.getBoolean(
2642                com.android.internal.R.styleable.AndroidManifestActivity_multiprocess,
2643                false)) {
2644            a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
2645        }
2646
2647        if (sa.getBoolean(
2648                com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch,
2649                false)) {
2650            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
2651        }
2652
2653        if (sa.getBoolean(
2654                com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch,
2655                false)) {
2656            a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
2657        }
2658
2659        if (sa.getBoolean(
2660                com.android.internal.R.styleable.AndroidManifestActivity_noHistory,
2661                false)) {
2662            a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
2663        }
2664
2665        if (sa.getBoolean(
2666                com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState,
2667                false)) {
2668            a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
2669        }
2670
2671        if (sa.getBoolean(
2672                com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded,
2673                false)) {
2674            a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
2675        }
2676
2677        if (sa.getBoolean(
2678                com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents,
2679                false)) {
2680            a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
2681        }
2682
2683        if (sa.getBoolean(
2684                com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting,
2685                (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
2686            a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
2687        }
2688
2689        if (sa.getBoolean(
2690                com.android.internal.R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
2691                false)) {
2692            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
2693        }
2694
2695        if (sa.getBoolean(
2696                com.android.internal.R.styleable.AndroidManifestActivity_showOnLockScreen,
2697                false)) {
2698            a.info.flags |= ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN;
2699        }
2700
2701        if (sa.getBoolean(
2702                com.android.internal.R.styleable.AndroidManifestActivity_immersive,
2703                false)) {
2704            a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
2705        }
2706
2707        if (!receiver) {
2708            if (sa.getBoolean(
2709                    com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
2710                    hardwareAccelerated)) {
2711                a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
2712            }
2713
2714            a.info.launchMode = sa.getInt(
2715                    com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
2716                    ActivityInfo.LAUNCH_MULTIPLE);
2717            a.info.documentLaunchMode = sa.getInt(
2718                    com.android.internal.R.styleable.AndroidManifestActivity_documentLaunchMode,
2719                    ActivityInfo.DOCUMENT_LAUNCH_NONE);
2720            a.info.maxRecents = sa.getInt(
2721                    com.android.internal.R.styleable.AndroidManifestActivity_maxRecents,
2722                    15);
2723            a.info.screenOrientation = sa.getInt(
2724                    com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
2725                    ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
2726            a.info.configChanges = sa.getInt(
2727                    com.android.internal.R.styleable.AndroidManifestActivity_configChanges,
2728                    0);
2729            a.info.softInputMode = sa.getInt(
2730                    com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
2731                    0);
2732
2733            a.info.persistableMode = sa.getInteger(
2734                    com.android.internal.R.styleable.AndroidManifestActivity_persistableMode,
2735                    ActivityInfo.PERSIST_ROOT_ONLY);
2736
2737            if (sa.getBoolean(
2738                    com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
2739                    false)) {
2740                a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
2741            }
2742
2743            if (sa.getBoolean(
2744                    com.android.internal.R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
2745                    false)) {
2746                a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
2747            }
2748
2749            if (sa.getBoolean(
2750                    com.android.internal.R.styleable.AndroidManifestActivity_relinquishTaskIdentity,
2751                    false)) {
2752                a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
2753            }
2754        } else {
2755            a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
2756            a.info.configChanges = 0;
2757        }
2758
2759        if (receiver) {
2760            if (sa.getBoolean(
2761                    com.android.internal.R.styleable.AndroidManifestActivity_singleUser,
2762                    false)) {
2763                a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
2764                if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
2765                    Slog.w(TAG, "Activity exported request ignored due to singleUser: "
2766                            + a.className + " at " + mArchiveSourcePath + " "
2767                            + parser.getPositionDescription());
2768                    a.info.exported = false;
2769                    setExported = true;
2770                }
2771            }
2772            if (sa.getBoolean(
2773                    com.android.internal.R.styleable.AndroidManifestActivity_primaryUserOnly,
2774                    false)) {
2775                a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY;
2776            }
2777        }
2778
2779        sa.recycle();
2780
2781        if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
2782            // A heavy-weight application can not have receives in its main process
2783            // We can do direct compare because we intern all strings.
2784            if (a.info.processName == owner.packageName) {
2785                outError[0] = "Heavy-weight applications can not have receivers in main process";
2786            }
2787        }
2788
2789        if (outError[0] != null) {
2790            return null;
2791        }
2792
2793        int outerDepth = parser.getDepth();
2794        int type;
2795        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2796               && (type != XmlPullParser.END_TAG
2797                       || parser.getDepth() > outerDepth)) {
2798            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2799                continue;
2800            }
2801
2802            if (parser.getName().equals("intent-filter")) {
2803                ActivityIntentInfo intent = new ActivityIntentInfo(a);
2804                if (!parseIntent(res, parser, attrs, true, intent, outError)) {
2805                    return null;
2806                }
2807                if (intent.countActions() == 0) {
2808                    Slog.w(TAG, "No actions in intent filter at "
2809                            + mArchiveSourcePath + " "
2810                            + parser.getPositionDescription());
2811                } else {
2812                    a.intents.add(intent);
2813                }
2814            } else if (!receiver && parser.getName().equals("preferred")) {
2815                ActivityIntentInfo intent = new ActivityIntentInfo(a);
2816                if (!parseIntent(res, parser, attrs, false, intent, outError)) {
2817                    return null;
2818                }
2819                if (intent.countActions() == 0) {
2820                    Slog.w(TAG, "No actions in preferred at "
2821                            + mArchiveSourcePath + " "
2822                            + parser.getPositionDescription());
2823                } else {
2824                    if (owner.preferredActivityFilters == null) {
2825                        owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
2826                    }
2827                    owner.preferredActivityFilters.add(intent);
2828                }
2829            } else if (parser.getName().equals("meta-data")) {
2830                if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
2831                        outError)) == null) {
2832                    return null;
2833                }
2834            } else {
2835                if (!RIGID_PARSER) {
2836                    Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
2837                    if (receiver) {
2838                        Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
2839                                + " at " + mArchiveSourcePath + " "
2840                                + parser.getPositionDescription());
2841                    } else {
2842                        Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
2843                                + " at " + mArchiveSourcePath + " "
2844                                + parser.getPositionDescription());
2845                    }
2846                    XmlUtils.skipCurrentTag(parser);
2847                    continue;
2848                } else {
2849                    if (receiver) {
2850                        outError[0] = "Bad element under <receiver>: " + parser.getName();
2851                    } else {
2852                        outError[0] = "Bad element under <activity>: " + parser.getName();
2853                    }
2854                    return null;
2855                }
2856            }
2857        }
2858
2859        if (!setExported) {
2860            a.info.exported = a.intents.size() > 0;
2861        }
2862
2863        return a;
2864    }
2865
2866    private Activity parseActivityAlias(Package owner, Resources res,
2867            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
2868            throws XmlPullParserException, IOException {
2869        TypedArray sa = res.obtainAttributes(attrs,
2870                com.android.internal.R.styleable.AndroidManifestActivityAlias);
2871
2872        String targetActivity = sa.getNonConfigurationString(
2873                com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity,
2874                Configuration.NATIVE_CONFIG_VERSION);
2875        if (targetActivity == null) {
2876            outError[0] = "<activity-alias> does not specify android:targetActivity";
2877            sa.recycle();
2878            return null;
2879        }
2880
2881        targetActivity = buildClassName(owner.applicationInfo.packageName,
2882                targetActivity, outError);
2883        if (targetActivity == null) {
2884            sa.recycle();
2885            return null;
2886        }
2887
2888        if (mParseActivityAliasArgs == null) {
2889            mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
2890                    com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
2891                    com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
2892                    com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
2893                    com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
2894                    com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
2895                    mSeparateProcesses,
2896                    0,
2897                    com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
2898                    com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
2899            mParseActivityAliasArgs.tag = "<activity-alias>";
2900        }
2901
2902        mParseActivityAliasArgs.sa = sa;
2903        mParseActivityAliasArgs.flags = flags;
2904
2905        Activity target = null;
2906
2907        final int NA = owner.activities.size();
2908        for (int i=0; i<NA; i++) {
2909            Activity t = owner.activities.get(i);
2910            if (targetActivity.equals(t.info.name)) {
2911                target = t;
2912                break;
2913            }
2914        }
2915
2916        if (target == null) {
2917            outError[0] = "<activity-alias> target activity " + targetActivity
2918                    + " not found in manifest";
2919            sa.recycle();
2920            return null;
2921        }
2922
2923        ActivityInfo info = new ActivityInfo();
2924        info.targetActivity = targetActivity;
2925        info.configChanges = target.info.configChanges;
2926        info.flags = target.info.flags;
2927        info.icon = target.info.icon;
2928        info.logo = target.info.logo;
2929        info.banner = target.info.banner;
2930        info.labelRes = target.info.labelRes;
2931        info.nonLocalizedLabel = target.info.nonLocalizedLabel;
2932        info.launchMode = target.info.launchMode;
2933        info.processName = target.info.processName;
2934        if (info.descriptionRes == 0) {
2935            info.descriptionRes = target.info.descriptionRes;
2936        }
2937        info.screenOrientation = target.info.screenOrientation;
2938        info.taskAffinity = target.info.taskAffinity;
2939        info.theme = target.info.theme;
2940        info.softInputMode = target.info.softInputMode;
2941        info.uiOptions = target.info.uiOptions;
2942        info.parentActivityName = target.info.parentActivityName;
2943
2944        Activity a = new Activity(mParseActivityAliasArgs, info);
2945        if (outError[0] != null) {
2946            sa.recycle();
2947            return null;
2948        }
2949
2950        final boolean setExported = sa.hasValue(
2951                com.android.internal.R.styleable.AndroidManifestActivityAlias_exported);
2952        if (setExported) {
2953            a.info.exported = sa.getBoolean(
2954                    com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false);
2955        }
2956
2957        String str;
2958        str = sa.getNonConfigurationString(
2959                com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0);
2960        if (str != null) {
2961            a.info.permission = str.length() > 0 ? str.toString().intern() : null;
2962        }
2963
2964        String parentName = sa.getNonConfigurationString(
2965                com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName,
2966                Configuration.NATIVE_CONFIG_VERSION);
2967        if (parentName != null) {
2968            String parentClassName = buildClassName(a.info.packageName, parentName, outError);
2969            if (outError[0] == null) {
2970                a.info.parentActivityName = parentClassName;
2971            } else {
2972                Log.e(TAG, "Activity alias " + a.info.name +
2973                        " specified invalid parentActivityName " + parentName);
2974                outError[0] = null;
2975            }
2976        }
2977
2978        sa.recycle();
2979
2980        if (outError[0] != null) {
2981            return null;
2982        }
2983
2984        int outerDepth = parser.getDepth();
2985        int type;
2986        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2987               && (type != XmlPullParser.END_TAG
2988                       || parser.getDepth() > outerDepth)) {
2989            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2990                continue;
2991            }
2992
2993            if (parser.getName().equals("intent-filter")) {
2994                ActivityIntentInfo intent = new ActivityIntentInfo(a);
2995                if (!parseIntent(res, parser, attrs, true, intent, outError)) {
2996                    return null;
2997                }
2998                if (intent.countActions() == 0) {
2999                    Slog.w(TAG, "No actions in intent filter at "
3000                            + mArchiveSourcePath + " "
3001                            + parser.getPositionDescription());
3002                } else {
3003                    a.intents.add(intent);
3004                }
3005            } else if (parser.getName().equals("meta-data")) {
3006                if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
3007                        outError)) == null) {
3008                    return null;
3009                }
3010            } else {
3011                if (!RIGID_PARSER) {
3012                    Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName()
3013                            + " at " + mArchiveSourcePath + " "
3014                            + parser.getPositionDescription());
3015                    XmlUtils.skipCurrentTag(parser);
3016                    continue;
3017                } else {
3018                    outError[0] = "Bad element under <activity-alias>: " + parser.getName();
3019                    return null;
3020                }
3021            }
3022        }
3023
3024        if (!setExported) {
3025            a.info.exported = a.intents.size() > 0;
3026        }
3027
3028        return a;
3029    }
3030
3031    private Provider parseProvider(Package owner, Resources res,
3032            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
3033            throws XmlPullParserException, IOException {
3034        TypedArray sa = res.obtainAttributes(attrs,
3035                com.android.internal.R.styleable.AndroidManifestProvider);
3036
3037        if (mParseProviderArgs == null) {
3038            mParseProviderArgs = new ParseComponentArgs(owner, outError,
3039                    com.android.internal.R.styleable.AndroidManifestProvider_name,
3040                    com.android.internal.R.styleable.AndroidManifestProvider_label,
3041                    com.android.internal.R.styleable.AndroidManifestProvider_icon,
3042                    com.android.internal.R.styleable.AndroidManifestProvider_logo,
3043                    com.android.internal.R.styleable.AndroidManifestProvider_banner,
3044                    mSeparateProcesses,
3045                    com.android.internal.R.styleable.AndroidManifestProvider_process,
3046                    com.android.internal.R.styleable.AndroidManifestProvider_description,
3047                    com.android.internal.R.styleable.AndroidManifestProvider_enabled);
3048            mParseProviderArgs.tag = "<provider>";
3049        }
3050
3051        mParseProviderArgs.sa = sa;
3052        mParseProviderArgs.flags = flags;
3053
3054        Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
3055        if (outError[0] != null) {
3056            sa.recycle();
3057            return null;
3058        }
3059
3060        boolean providerExportedDefault = false;
3061
3062        if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
3063            // For compatibility, applications targeting API level 16 or lower
3064            // should have their content providers exported by default, unless they
3065            // specify otherwise.
3066            providerExportedDefault = true;
3067        }
3068
3069        p.info.exported = sa.getBoolean(
3070                com.android.internal.R.styleable.AndroidManifestProvider_exported,
3071                providerExportedDefault);
3072
3073        String cpname = sa.getNonConfigurationString(
3074                com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0);
3075
3076        p.info.isSyncable = sa.getBoolean(
3077                com.android.internal.R.styleable.AndroidManifestProvider_syncable,
3078                false);
3079
3080        String permission = sa.getNonConfigurationString(
3081                com.android.internal.R.styleable.AndroidManifestProvider_permission, 0);
3082        String str = sa.getNonConfigurationString(
3083                com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0);
3084        if (str == null) {
3085            str = permission;
3086        }
3087        if (str == null) {
3088            p.info.readPermission = owner.applicationInfo.permission;
3089        } else {
3090            p.info.readPermission =
3091                str.length() > 0 ? str.toString().intern() : null;
3092        }
3093        str = sa.getNonConfigurationString(
3094                com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0);
3095        if (str == null) {
3096            str = permission;
3097        }
3098        if (str == null) {
3099            p.info.writePermission = owner.applicationInfo.permission;
3100        } else {
3101            p.info.writePermission =
3102                str.length() > 0 ? str.toString().intern() : null;
3103        }
3104
3105        p.info.grantUriPermissions = sa.getBoolean(
3106                com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
3107                false);
3108
3109        p.info.multiprocess = sa.getBoolean(
3110                com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
3111                false);
3112
3113        p.info.initOrder = sa.getInt(
3114                com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
3115                0);
3116
3117        p.info.flags = 0;
3118
3119        if (sa.getBoolean(
3120                com.android.internal.R.styleable.AndroidManifestProvider_singleUser,
3121                false)) {
3122            p.info.flags |= ProviderInfo.FLAG_SINGLE_USER;
3123            if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
3124                Slog.w(TAG, "Provider exported request ignored due to singleUser: "
3125                        + p.className + " at " + mArchiveSourcePath + " "
3126                        + parser.getPositionDescription());
3127                p.info.exported = false;
3128            }
3129        }
3130
3131        sa.recycle();
3132
3133        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
3134            // A heavy-weight application can not have providers in its main process
3135            // We can do direct compare because we intern all strings.
3136            if (p.info.processName == owner.packageName) {
3137                outError[0] = "Heavy-weight applications can not have providers in main process";
3138                return null;
3139            }
3140        }
3141
3142        if (cpname == null) {
3143            outError[0] = "<provider> does not include authorities attribute";
3144            return null;
3145        }
3146        p.info.authority = cpname.intern();
3147
3148        if (!parseProviderTags(res, parser, attrs, p, outError)) {
3149            return null;
3150        }
3151
3152        return p;
3153    }
3154
3155    private boolean parseProviderTags(Resources res,
3156            XmlPullParser parser, AttributeSet attrs,
3157            Provider outInfo, String[] outError)
3158            throws XmlPullParserException, IOException {
3159        int outerDepth = parser.getDepth();
3160        int type;
3161        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3162               && (type != XmlPullParser.END_TAG
3163                       || parser.getDepth() > outerDepth)) {
3164            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3165                continue;
3166            }
3167
3168            if (parser.getName().equals("intent-filter")) {
3169                ProviderIntentInfo intent = new ProviderIntentInfo(outInfo);
3170                if (!parseIntent(res, parser, attrs, true, intent, outError)) {
3171                    return false;
3172                }
3173                outInfo.intents.add(intent);
3174
3175            } else if (parser.getName().equals("meta-data")) {
3176                if ((outInfo.metaData=parseMetaData(res, parser, attrs,
3177                        outInfo.metaData, outError)) == null) {
3178                    return false;
3179                }
3180
3181            } else if (parser.getName().equals("grant-uri-permission")) {
3182                TypedArray sa = res.obtainAttributes(attrs,
3183                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
3184
3185                PatternMatcher pa = null;
3186
3187                String str = sa.getNonConfigurationString(
3188                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0);
3189                if (str != null) {
3190                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
3191                }
3192
3193                str = sa.getNonConfigurationString(
3194                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
3195                if (str != null) {
3196                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
3197                }
3198
3199                str = sa.getNonConfigurationString(
3200                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
3201                if (str != null) {
3202                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
3203                }
3204
3205                sa.recycle();
3206
3207                if (pa != null) {
3208                    if (outInfo.info.uriPermissionPatterns == null) {
3209                        outInfo.info.uriPermissionPatterns = new PatternMatcher[1];
3210                        outInfo.info.uriPermissionPatterns[0] = pa;
3211                    } else {
3212                        final int N = outInfo.info.uriPermissionPatterns.length;
3213                        PatternMatcher[] newp = new PatternMatcher[N+1];
3214                        System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N);
3215                        newp[N] = pa;
3216                        outInfo.info.uriPermissionPatterns = newp;
3217                    }
3218                    outInfo.info.grantUriPermissions = true;
3219                } else {
3220                    if (!RIGID_PARSER) {
3221                        Slog.w(TAG, "Unknown element under <path-permission>: "
3222                                + parser.getName() + " at " + mArchiveSourcePath + " "
3223                                + parser.getPositionDescription());
3224                        XmlUtils.skipCurrentTag(parser);
3225                        continue;
3226                    } else {
3227                        outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
3228                        return false;
3229                    }
3230                }
3231                XmlUtils.skipCurrentTag(parser);
3232
3233            } else if (parser.getName().equals("path-permission")) {
3234                TypedArray sa = res.obtainAttributes(attrs,
3235                        com.android.internal.R.styleable.AndroidManifestPathPermission);
3236
3237                PathPermission pa = null;
3238
3239                String permission = sa.getNonConfigurationString(
3240                        com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0);
3241                String readPermission = sa.getNonConfigurationString(
3242                        com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0);
3243                if (readPermission == null) {
3244                    readPermission = permission;
3245                }
3246                String writePermission = sa.getNonConfigurationString(
3247                        com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0);
3248                if (writePermission == null) {
3249                    writePermission = permission;
3250                }
3251
3252                boolean havePerm = false;
3253                if (readPermission != null) {
3254                    readPermission = readPermission.intern();
3255                    havePerm = true;
3256                }
3257                if (writePermission != null) {
3258                    writePermission = writePermission.intern();
3259                    havePerm = true;
3260                }
3261
3262                if (!havePerm) {
3263                    if (!RIGID_PARSER) {
3264                        Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
3265                                + parser.getName() + " at " + mArchiveSourcePath + " "
3266                                + parser.getPositionDescription());
3267                        XmlUtils.skipCurrentTag(parser);
3268                        continue;
3269                    } else {
3270                        outError[0] = "No readPermission or writePermssion for <path-permission>";
3271                        return false;
3272                    }
3273                }
3274
3275                String path = sa.getNonConfigurationString(
3276                        com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0);
3277                if (path != null) {
3278                    pa = new PathPermission(path,
3279                            PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
3280                }
3281
3282                path = sa.getNonConfigurationString(
3283                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
3284                if (path != null) {
3285                    pa = new PathPermission(path,
3286                            PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
3287                }
3288
3289                path = sa.getNonConfigurationString(
3290                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0);
3291                if (path != null) {
3292                    pa = new PathPermission(path,
3293                            PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
3294                }
3295
3296                sa.recycle();
3297
3298                if (pa != null) {
3299                    if (outInfo.info.pathPermissions == null) {
3300                        outInfo.info.pathPermissions = new PathPermission[1];
3301                        outInfo.info.pathPermissions[0] = pa;
3302                    } else {
3303                        final int N = outInfo.info.pathPermissions.length;
3304                        PathPermission[] newp = new PathPermission[N+1];
3305                        System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
3306                        newp[N] = pa;
3307                        outInfo.info.pathPermissions = newp;
3308                    }
3309                } else {
3310                    if (!RIGID_PARSER) {
3311                        Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
3312                                + parser.getName() + " at " + mArchiveSourcePath + " "
3313                                + parser.getPositionDescription());
3314                        XmlUtils.skipCurrentTag(parser);
3315                        continue;
3316                    }
3317                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
3318                    return false;
3319                }
3320                XmlUtils.skipCurrentTag(parser);
3321
3322            } else {
3323                if (!RIGID_PARSER) {
3324                    Slog.w(TAG, "Unknown element under <provider>: "
3325                            + parser.getName() + " at " + mArchiveSourcePath + " "
3326                            + parser.getPositionDescription());
3327                    XmlUtils.skipCurrentTag(parser);
3328                    continue;
3329                } else {
3330                    outError[0] = "Bad element under <provider>: " + parser.getName();
3331                    return false;
3332                }
3333            }
3334        }
3335        return true;
3336    }
3337
3338    private Service parseService(Package owner, Resources res,
3339            XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
3340            throws XmlPullParserException, IOException {
3341        TypedArray sa = res.obtainAttributes(attrs,
3342                com.android.internal.R.styleable.AndroidManifestService);
3343
3344        if (mParseServiceArgs == null) {
3345            mParseServiceArgs = new ParseComponentArgs(owner, outError,
3346                    com.android.internal.R.styleable.AndroidManifestService_name,
3347                    com.android.internal.R.styleable.AndroidManifestService_label,
3348                    com.android.internal.R.styleable.AndroidManifestService_icon,
3349                    com.android.internal.R.styleable.AndroidManifestService_logo,
3350                    com.android.internal.R.styleable.AndroidManifestService_banner,
3351                    mSeparateProcesses,
3352                    com.android.internal.R.styleable.AndroidManifestService_process,
3353                    com.android.internal.R.styleable.AndroidManifestService_description,
3354                    com.android.internal.R.styleable.AndroidManifestService_enabled);
3355            mParseServiceArgs.tag = "<service>";
3356        }
3357
3358        mParseServiceArgs.sa = sa;
3359        mParseServiceArgs.flags = flags;
3360
3361        Service s = new Service(mParseServiceArgs, new ServiceInfo());
3362        if (outError[0] != null) {
3363            sa.recycle();
3364            return null;
3365        }
3366
3367        boolean setExported = sa.hasValue(
3368                com.android.internal.R.styleable.AndroidManifestService_exported);
3369        if (setExported) {
3370            s.info.exported = sa.getBoolean(
3371                    com.android.internal.R.styleable.AndroidManifestService_exported, false);
3372        }
3373
3374        String str = sa.getNonConfigurationString(
3375                com.android.internal.R.styleable.AndroidManifestService_permission, 0);
3376        if (str == null) {
3377            s.info.permission = owner.applicationInfo.permission;
3378        } else {
3379            s.info.permission = str.length() > 0 ? str.toString().intern() : null;
3380        }
3381
3382        s.info.flags = 0;
3383        if (sa.getBoolean(
3384                com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
3385                false)) {
3386            s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
3387        }
3388        if (sa.getBoolean(
3389                com.android.internal.R.styleable.AndroidManifestService_isolatedProcess,
3390                false)) {
3391            s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
3392        }
3393        if (sa.getBoolean(
3394                com.android.internal.R.styleable.AndroidManifestService_singleUser,
3395                false)) {
3396            s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
3397            if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
3398                Slog.w(TAG, "Service exported request ignored due to singleUser: "
3399                        + s.className + " at " + mArchiveSourcePath + " "
3400                        + parser.getPositionDescription());
3401                s.info.exported = false;
3402                setExported = true;
3403            }
3404        }
3405
3406        sa.recycle();
3407
3408        if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
3409            // A heavy-weight application can not have services in its main process
3410            // We can do direct compare because we intern all strings.
3411            if (s.info.processName == owner.packageName) {
3412                outError[0] = "Heavy-weight applications can not have services in main process";
3413                return null;
3414            }
3415        }
3416
3417        int outerDepth = parser.getDepth();
3418        int type;
3419        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3420               && (type != XmlPullParser.END_TAG
3421                       || parser.getDepth() > outerDepth)) {
3422            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3423                continue;
3424            }
3425
3426            if (parser.getName().equals("intent-filter")) {
3427                ServiceIntentInfo intent = new ServiceIntentInfo(s);
3428                if (!parseIntent(res, parser, attrs, true, intent, outError)) {
3429                    return null;
3430                }
3431
3432                s.intents.add(intent);
3433            } else if (parser.getName().equals("meta-data")) {
3434                if ((s.metaData=parseMetaData(res, parser, attrs, s.metaData,
3435                        outError)) == null) {
3436                    return null;
3437                }
3438            } else {
3439                if (!RIGID_PARSER) {
3440                    Slog.w(TAG, "Unknown element under <service>: "
3441                            + parser.getName() + " at " + mArchiveSourcePath + " "
3442                            + parser.getPositionDescription());
3443                    XmlUtils.skipCurrentTag(parser);
3444                    continue;
3445                } else {
3446                    outError[0] = "Bad element under <service>: " + parser.getName();
3447                    return null;
3448                }
3449            }
3450        }
3451
3452        if (!setExported) {
3453            s.info.exported = s.intents.size() > 0;
3454        }
3455
3456        return s;
3457    }
3458
3459    private boolean parseAllMetaData(Resources res,
3460            XmlPullParser parser, AttributeSet attrs, String tag,
3461            Component outInfo, String[] outError)
3462            throws XmlPullParserException, IOException {
3463        int outerDepth = parser.getDepth();
3464        int type;
3465        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3466               && (type != XmlPullParser.END_TAG
3467                       || parser.getDepth() > outerDepth)) {
3468            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3469                continue;
3470            }
3471
3472            if (parser.getName().equals("meta-data")) {
3473                if ((outInfo.metaData=parseMetaData(res, parser, attrs,
3474                        outInfo.metaData, outError)) == null) {
3475                    return false;
3476                }
3477            } else {
3478                if (!RIGID_PARSER) {
3479                    Slog.w(TAG, "Unknown element under " + tag + ": "
3480                            + parser.getName() + " at " + mArchiveSourcePath + " "
3481                            + parser.getPositionDescription());
3482                    XmlUtils.skipCurrentTag(parser);
3483                    continue;
3484                } else {
3485                    outError[0] = "Bad element under " + tag + ": " + parser.getName();
3486                    return false;
3487                }
3488            }
3489        }
3490        return true;
3491    }
3492
3493    private Bundle parseMetaData(Resources res,
3494            XmlPullParser parser, AttributeSet attrs,
3495            Bundle data, String[] outError)
3496            throws XmlPullParserException, IOException {
3497
3498        TypedArray sa = res.obtainAttributes(attrs,
3499                com.android.internal.R.styleable.AndroidManifestMetaData);
3500
3501        if (data == null) {
3502            data = new Bundle();
3503        }
3504
3505        String name = sa.getNonConfigurationString(
3506                com.android.internal.R.styleable.AndroidManifestMetaData_name, 0);
3507        if (name == null) {
3508            outError[0] = "<meta-data> requires an android:name attribute";
3509            sa.recycle();
3510            return null;
3511        }
3512
3513        name = name.intern();
3514
3515        TypedValue v = sa.peekValue(
3516                com.android.internal.R.styleable.AndroidManifestMetaData_resource);
3517        if (v != null && v.resourceId != 0) {
3518            //Slog.i(TAG, "Meta data ref " + name + ": " + v);
3519            data.putInt(name, v.resourceId);
3520        } else {
3521            v = sa.peekValue(
3522                    com.android.internal.R.styleable.AndroidManifestMetaData_value);
3523            //Slog.i(TAG, "Meta data " + name + ": " + v);
3524            if (v != null) {
3525                if (v.type == TypedValue.TYPE_STRING) {
3526                    CharSequence cs = v.coerceToString();
3527                    data.putString(name, cs != null ? cs.toString().intern() : null);
3528                } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
3529                    data.putBoolean(name, v.data != 0);
3530                } else if (v.type >= TypedValue.TYPE_FIRST_INT
3531                        && v.type <= TypedValue.TYPE_LAST_INT) {
3532                    data.putInt(name, v.data);
3533                } else if (v.type == TypedValue.TYPE_FLOAT) {
3534                    data.putFloat(name, v.getFloat());
3535                } else {
3536                    if (!RIGID_PARSER) {
3537                        Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: "
3538                                + parser.getName() + " at " + mArchiveSourcePath + " "
3539                                + parser.getPositionDescription());
3540                    } else {
3541                        outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types";
3542                        data = null;
3543                    }
3544                }
3545            } else {
3546                outError[0] = "<meta-data> requires an android:value or android:resource attribute";
3547                data = null;
3548            }
3549        }
3550
3551        sa.recycle();
3552
3553        XmlUtils.skipCurrentTag(parser);
3554
3555        return data;
3556    }
3557
3558    private static VerifierInfo parseVerifier(Resources res, XmlPullParser parser,
3559            AttributeSet attrs, int flags) {
3560        final TypedArray sa = res.obtainAttributes(attrs,
3561                com.android.internal.R.styleable.AndroidManifestPackageVerifier);
3562
3563        final String packageName = sa.getNonResourceString(
3564                com.android.internal.R.styleable.AndroidManifestPackageVerifier_name);
3565
3566        final String encodedPublicKey = sa.getNonResourceString(
3567                com.android.internal.R.styleable.AndroidManifestPackageVerifier_publicKey);
3568
3569        sa.recycle();
3570
3571        if (packageName == null || packageName.length() == 0) {
3572            Slog.i(TAG, "verifier package name was null; skipping");
3573            return null;
3574        }
3575
3576        final PublicKey publicKey = parsePublicKey(encodedPublicKey);
3577        if (publicKey == null) {
3578            Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
3579            return null;
3580        }
3581
3582        return new VerifierInfo(packageName, publicKey);
3583    }
3584
3585    public static final PublicKey parsePublicKey(final String encodedPublicKey) {
3586        if (encodedPublicKey == null) {
3587            Slog.i(TAG, "Could not parse null public key");
3588            return null;
3589        }
3590
3591        EncodedKeySpec keySpec;
3592        try {
3593            final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT);
3594            keySpec = new X509EncodedKeySpec(encoded);
3595        } catch (IllegalArgumentException e) {
3596            Slog.i(TAG, "Could not parse verifier public key; invalid Base64");
3597            return null;
3598        }
3599
3600        /* First try the key as an RSA key. */
3601        try {
3602            final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
3603            return keyFactory.generatePublic(keySpec);
3604        } catch (NoSuchAlgorithmException e) {
3605            Log.wtf(TAG, "Could not parse public key because RSA isn't included in build");
3606            return null;
3607        } catch (InvalidKeySpecException e) {
3608            // Not a RSA public key.
3609        }
3610
3611        /* Now try it as a DSA key. */
3612        try {
3613            final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
3614            return keyFactory.generatePublic(keySpec);
3615        } catch (NoSuchAlgorithmException e) {
3616            Log.wtf(TAG, "Could not parse public key because DSA isn't included in build");
3617            return null;
3618        } catch (InvalidKeySpecException e) {
3619            // Not a DSA public key.
3620        }
3621
3622        return null;
3623    }
3624
3625    private static final String ANDROID_RESOURCES
3626            = "http://schemas.android.com/apk/res/android";
3627
3628    private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs,
3629            boolean allowGlobs, IntentInfo outInfo, String[] outError)
3630            throws XmlPullParserException, IOException {
3631
3632        TypedArray sa = res.obtainAttributes(attrs,
3633                com.android.internal.R.styleable.AndroidManifestIntentFilter);
3634
3635        int priority = sa.getInt(
3636                com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
3637        outInfo.setPriority(priority);
3638
3639        TypedValue v = sa.peekValue(
3640                com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
3641        if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
3642            outInfo.nonLocalizedLabel = v.coerceToString();
3643        }
3644
3645        outInfo.icon = sa.getResourceId(
3646                com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
3647
3648        outInfo.logo = sa.getResourceId(
3649                com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
3650
3651        outInfo.banner = sa.getResourceId(
3652                com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0);
3653
3654        sa.recycle();
3655
3656        int outerDepth = parser.getDepth();
3657        int type;
3658        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3659                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3660            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3661                continue;
3662            }
3663
3664            String nodeName = parser.getName();
3665            if (nodeName.equals("action")) {
3666                String value = attrs.getAttributeValue(
3667                        ANDROID_RESOURCES, "name");
3668                if (value == null || value == "") {
3669                    outError[0] = "No value supplied for <android:name>";
3670                    return false;
3671                }
3672                XmlUtils.skipCurrentTag(parser);
3673
3674                outInfo.addAction(value);
3675            } else if (nodeName.equals("category")) {
3676                String value = attrs.getAttributeValue(
3677                        ANDROID_RESOURCES, "name");
3678                if (value == null || value == "") {
3679                    outError[0] = "No value supplied for <android:name>";
3680                    return false;
3681                }
3682                XmlUtils.skipCurrentTag(parser);
3683
3684                outInfo.addCategory(value);
3685
3686            } else if (nodeName.equals("data")) {
3687                sa = res.obtainAttributes(attrs,
3688                        com.android.internal.R.styleable.AndroidManifestData);
3689
3690                String str = sa.getNonConfigurationString(
3691                        com.android.internal.R.styleable.AndroidManifestData_mimeType, 0);
3692                if (str != null) {
3693                    try {
3694                        outInfo.addDataType(str);
3695                    } catch (IntentFilter.MalformedMimeTypeException e) {
3696                        outError[0] = e.toString();
3697                        sa.recycle();
3698                        return false;
3699                    }
3700                }
3701
3702                str = sa.getNonConfigurationString(
3703                        com.android.internal.R.styleable.AndroidManifestData_scheme, 0);
3704                if (str != null) {
3705                    outInfo.addDataScheme(str);
3706                }
3707
3708                str = sa.getNonConfigurationString(
3709                        com.android.internal.R.styleable.AndroidManifestData_ssp, 0);
3710                if (str != null) {
3711                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
3712                }
3713
3714                str = sa.getNonConfigurationString(
3715                        com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0);
3716                if (str != null) {
3717                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
3718                }
3719
3720                str = sa.getNonConfigurationString(
3721                        com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0);
3722                if (str != null) {
3723                    if (!allowGlobs) {
3724                        outError[0] = "sspPattern not allowed here; ssp must be literal";
3725                        return false;
3726                    }
3727                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
3728                }
3729
3730                String host = sa.getNonConfigurationString(
3731                        com.android.internal.R.styleable.AndroidManifestData_host, 0);
3732                String port = sa.getNonConfigurationString(
3733                        com.android.internal.R.styleable.AndroidManifestData_port, 0);
3734                if (host != null) {
3735                    outInfo.addDataAuthority(host, port);
3736                }
3737
3738                str = sa.getNonConfigurationString(
3739                        com.android.internal.R.styleable.AndroidManifestData_path, 0);
3740                if (str != null) {
3741                    outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
3742                }
3743
3744                str = sa.getNonConfigurationString(
3745                        com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0);
3746                if (str != null) {
3747                    outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
3748                }
3749
3750                str = sa.getNonConfigurationString(
3751                        com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
3752                if (str != null) {
3753                    if (!allowGlobs) {
3754                        outError[0] = "pathPattern not allowed here; path must be literal";
3755                        return false;
3756                    }
3757                    outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
3758                }
3759
3760                sa.recycle();
3761                XmlUtils.skipCurrentTag(parser);
3762            } else if (!RIGID_PARSER) {
3763                Slog.w(TAG, "Unknown element under <intent-filter>: "
3764                        + parser.getName() + " at " + mArchiveSourcePath + " "
3765                        + parser.getPositionDescription());
3766                XmlUtils.skipCurrentTag(parser);
3767            } else {
3768                outError[0] = "Bad element under <intent-filter>: " + parser.getName();
3769                return false;
3770            }
3771        }
3772
3773        outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
3774
3775        if (DEBUG_PARSER) {
3776            final StringBuilder cats = new StringBuilder("Intent d=");
3777            cats.append(outInfo.hasDefault);
3778            cats.append(", cat=");
3779
3780            final Iterator<String> it = outInfo.categoriesIterator();
3781            if (it != null) {
3782                while (it.hasNext()) {
3783                    cats.append(' ');
3784                    cats.append(it.next());
3785                }
3786            }
3787            Slog.d(TAG, cats.toString());
3788        }
3789
3790        return true;
3791    }
3792
3793    /**
3794     * Representation of a full package parsed from APK files on disk. A package
3795     * consists of a single base APK, and zero or more split APKs.
3796     */
3797    public final static class Package {
3798
3799        public String packageName;
3800        /** Names of any split APKs, ordered by parsed splitName */
3801        public String[] splitNames;
3802
3803        // TODO: work towards making these paths invariant
3804
3805        /**
3806         * Path where this package was found on disk. For monolithic packages
3807         * this is path to single base APK file; for cluster packages this is
3808         * path to the cluster directory.
3809         */
3810        public String codePath;
3811
3812        /** Path of base APK */
3813        public String baseCodePath;
3814        /** Paths of any split APKs, ordered by parsed splitName */
3815        public String[] splitCodePaths;
3816
3817        // For now we only support one application per package.
3818        public final ApplicationInfo applicationInfo = new ApplicationInfo();
3819
3820        public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
3821        public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
3822        public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
3823        public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
3824        public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
3825        public final ArrayList<Service> services = new ArrayList<Service>(0);
3826        public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
3827
3828        public final ArrayList<String> requestedPermissions = new ArrayList<String>();
3829        public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>();
3830
3831        public ArrayList<String> protectedBroadcasts;
3832
3833        public ArrayList<String> libraryNames = null;
3834        public ArrayList<String> usesLibraries = null;
3835        public ArrayList<String> usesOptionalLibraries = null;
3836        public String[] usesLibraryFiles = null;
3837
3838        public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
3839
3840        public ArrayList<String> mOriginalPackages = null;
3841        public String mRealPackage = null;
3842        public ArrayList<String> mAdoptPermissions = null;
3843
3844        // We store the application meta-data independently to avoid multiple unwanted references
3845        public Bundle mAppMetaData = null;
3846
3847        // The version code declared for this package.
3848        public int mVersionCode;
3849
3850        // The version name declared for this package.
3851        public String mVersionName;
3852
3853        // The shared user id that this package wants to use.
3854        public String mSharedUserId;
3855
3856        // The shared user label that this package wants to use.
3857        public int mSharedUserLabel;
3858
3859        // Signatures that were read from the package.
3860        public Signature[] mSignatures;
3861        public Certificate[][] mCertificates;
3862
3863        // For use by package manager service for quick lookup of
3864        // preferred up order.
3865        public int mPreferredOrder = 0;
3866
3867        // For use by package manager to keep track of where it needs to do dexopt.
3868        public boolean mDexOptNeeded = true;
3869
3870        // For use by package manager to keep track of when a package was last used.
3871        public long mLastPackageUsageTimeInMills;
3872
3873        // // User set enabled state.
3874        // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
3875        //
3876        // // Whether the package has been stopped.
3877        // public boolean mSetStopped = false;
3878
3879        // Additional data supplied by callers.
3880        public Object mExtras;
3881
3882        // Whether an operation is currently pending on this package
3883        public boolean mOperationPending;
3884
3885        /*
3886         *  Applications hardware preferences
3887         */
3888        public final ArrayList<ConfigurationInfo> configPreferences =
3889                new ArrayList<ConfigurationInfo>();
3890
3891        /*
3892         *  Applications requested features
3893         */
3894        public ArrayList<FeatureInfo> reqFeatures = null;
3895
3896        public int installLocation;
3897
3898        /* An app that's required for all users and cannot be uninstalled for a user */
3899        public boolean mRequiredForAllUsers;
3900
3901        /* For which types of profile this app is required */
3902        public int mRequiredForProfile;
3903
3904        /* The restricted account authenticator type that is used by this application */
3905        public String mRestrictedAccountType;
3906
3907        /* The required account type without which this application will not function */
3908        public String mRequiredAccountType;
3909
3910        /**
3911         * Digest suitable for comparing whether this package's manifest is the
3912         * same as another.
3913         */
3914        public ManifestDigest manifestDigest;
3915
3916        public String mOverlayTarget;
3917        public int mOverlayPriority;
3918        public boolean mTrustedOverlay;
3919
3920        /**
3921         * Data used to feed the KeySetManager
3922         */
3923        public Set<PublicKey> mSigningKeys;
3924        public Set<String> mUpgradeKeySets;
3925        public Map<String, Set<PublicKey>> mKeySetMapping;
3926
3927        public Package(String packageName) {
3928            this.packageName = packageName;
3929            applicationInfo.packageName = packageName;
3930            applicationInfo.uid = -1;
3931        }
3932
3933        public List<String> getAllCodePaths() {
3934            ArrayList<String> paths = new ArrayList<>();
3935            paths.add(baseCodePath);
3936            if (!ArrayUtils.isEmpty(splitCodePaths)) {
3937                Collections.addAll(paths, splitCodePaths);
3938            }
3939            return paths;
3940        }
3941
3942        public void setPackageName(String newName) {
3943            packageName = newName;
3944            applicationInfo.packageName = newName;
3945            for (int i=permissions.size()-1; i>=0; i--) {
3946                permissions.get(i).setPackageName(newName);
3947            }
3948            for (int i=permissionGroups.size()-1; i>=0; i--) {
3949                permissionGroups.get(i).setPackageName(newName);
3950            }
3951            for (int i=activities.size()-1; i>=0; i--) {
3952                activities.get(i).setPackageName(newName);
3953            }
3954            for (int i=receivers.size()-1; i>=0; i--) {
3955                receivers.get(i).setPackageName(newName);
3956            }
3957            for (int i=providers.size()-1; i>=0; i--) {
3958                providers.get(i).setPackageName(newName);
3959            }
3960            for (int i=services.size()-1; i>=0; i--) {
3961                services.get(i).setPackageName(newName);
3962            }
3963            for (int i=instrumentation.size()-1; i>=0; i--) {
3964                instrumentation.get(i).setPackageName(newName);
3965            }
3966        }
3967
3968        public boolean hasComponentClassName(String name) {
3969            for (int i=activities.size()-1; i>=0; i--) {
3970                if (name.equals(activities.get(i).className)) {
3971                    return true;
3972                }
3973            }
3974            for (int i=receivers.size()-1; i>=0; i--) {
3975                if (name.equals(receivers.get(i).className)) {
3976                    return true;
3977                }
3978            }
3979            for (int i=providers.size()-1; i>=0; i--) {
3980                if (name.equals(providers.get(i).className)) {
3981                    return true;
3982                }
3983            }
3984            for (int i=services.size()-1; i>=0; i--) {
3985                if (name.equals(services.get(i).className)) {
3986                    return true;
3987                }
3988            }
3989            for (int i=instrumentation.size()-1; i>=0; i--) {
3990                if (name.equals(instrumentation.get(i).className)) {
3991                    return true;
3992                }
3993            }
3994            return false;
3995        }
3996
3997        public String toString() {
3998            return "Package{"
3999                + Integer.toHexString(System.identityHashCode(this))
4000                + " " + packageName + "}";
4001        }
4002    }
4003
4004    public static class Component<II extends IntentInfo> {
4005        public final Package owner;
4006        public final ArrayList<II> intents;
4007        public final String className;
4008        public Bundle metaData;
4009
4010        ComponentName componentName;
4011        String componentShortName;
4012
4013        public Component(Package _owner) {
4014            owner = _owner;
4015            intents = null;
4016            className = null;
4017        }
4018
4019        public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
4020            owner = args.owner;
4021            intents = new ArrayList<II>(0);
4022            String name = args.sa.getNonConfigurationString(args.nameRes, 0);
4023            if (name == null) {
4024                className = null;
4025                args.outError[0] = args.tag + " does not specify android:name";
4026                return;
4027            }
4028
4029            outInfo.name
4030                = buildClassName(owner.applicationInfo.packageName, name, args.outError);
4031            if (outInfo.name == null) {
4032                className = null;
4033                args.outError[0] = args.tag + " does not have valid android:name";
4034                return;
4035            }
4036
4037            className = outInfo.name;
4038
4039            int iconVal = args.sa.getResourceId(args.iconRes, 0);
4040            if (iconVal != 0) {
4041                outInfo.icon = iconVal;
4042                outInfo.nonLocalizedLabel = null;
4043            }
4044
4045            int logoVal = args.sa.getResourceId(args.logoRes, 0);
4046            if (logoVal != 0) {
4047                outInfo.logo = logoVal;
4048            }
4049
4050            int bannerVal = args.sa.getResourceId(args.bannerRes, 0);
4051            if (bannerVal != 0) {
4052                outInfo.banner = bannerVal;
4053            }
4054
4055            TypedValue v = args.sa.peekValue(args.labelRes);
4056            if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
4057                outInfo.nonLocalizedLabel = v.coerceToString();
4058            }
4059
4060            outInfo.packageName = owner.packageName;
4061        }
4062
4063        public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
4064            this(args, (PackageItemInfo)outInfo);
4065            if (args.outError[0] != null) {
4066                return;
4067            }
4068
4069            if (args.processRes != 0) {
4070                CharSequence pname;
4071                if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
4072                    pname = args.sa.getNonConfigurationString(args.processRes,
4073                            Configuration.NATIVE_CONFIG_VERSION);
4074                } else {
4075                    // Some older apps have been seen to use a resource reference
4076                    // here that on older builds was ignored (with a warning).  We
4077                    // need to continue to do this for them so they don't break.
4078                    pname = args.sa.getNonResourceString(args.processRes);
4079                }
4080                outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
4081                        owner.applicationInfo.processName, pname,
4082                        args.flags, args.sepProcesses, args.outError);
4083            }
4084
4085            if (args.descriptionRes != 0) {
4086                outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
4087            }
4088
4089            outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
4090        }
4091
4092        public Component(Component<II> clone) {
4093            owner = clone.owner;
4094            intents = clone.intents;
4095            className = clone.className;
4096            componentName = clone.componentName;
4097            componentShortName = clone.componentShortName;
4098        }
4099
4100        public ComponentName getComponentName() {
4101            if (componentName != null) {
4102                return componentName;
4103            }
4104            if (className != null) {
4105                componentName = new ComponentName(owner.applicationInfo.packageName,
4106                        className);
4107            }
4108            return componentName;
4109        }
4110
4111        public void appendComponentShortName(StringBuilder sb) {
4112            ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className);
4113        }
4114
4115        public void printComponentShortName(PrintWriter pw) {
4116            ComponentName.printShortString(pw, owner.applicationInfo.packageName, className);
4117        }
4118
4119        public void setPackageName(String packageName) {
4120            componentName = null;
4121            componentShortName = null;
4122        }
4123    }
4124
4125    public final static class Permission extends Component<IntentInfo> {
4126        public final PermissionInfo info;
4127        public boolean tree;
4128        public PermissionGroup group;
4129
4130        public Permission(Package _owner) {
4131            super(_owner);
4132            info = new PermissionInfo();
4133        }
4134
4135        public Permission(Package _owner, PermissionInfo _info) {
4136            super(_owner);
4137            info = _info;
4138        }
4139
4140        public void setPackageName(String packageName) {
4141            super.setPackageName(packageName);
4142            info.packageName = packageName;
4143        }
4144
4145        public String toString() {
4146            return "Permission{"
4147                + Integer.toHexString(System.identityHashCode(this))
4148                + " " + info.name + "}";
4149        }
4150    }
4151
4152    public final static class PermissionGroup extends Component<IntentInfo> {
4153        public final PermissionGroupInfo info;
4154
4155        public PermissionGroup(Package _owner) {
4156            super(_owner);
4157            info = new PermissionGroupInfo();
4158        }
4159
4160        public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
4161            super(_owner);
4162            info = _info;
4163        }
4164
4165        public void setPackageName(String packageName) {
4166            super.setPackageName(packageName);
4167            info.packageName = packageName;
4168        }
4169
4170        public String toString() {
4171            return "PermissionGroup{"
4172                + Integer.toHexString(System.identityHashCode(this))
4173                + " " + info.name + "}";
4174        }
4175    }
4176
4177    private static boolean copyNeeded(int flags, Package p,
4178            PackageUserState state, Bundle metaData, int userId) {
4179        if (userId != 0) {
4180            // We always need to copy for other users, since we need
4181            // to fix up the uid.
4182            return true;
4183        }
4184        if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
4185            boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
4186            if (p.applicationInfo.enabled != enabled) {
4187                return true;
4188            }
4189        }
4190        if (!state.installed || state.blocked) {
4191            return true;
4192        }
4193        if (state.stopped) {
4194            return true;
4195        }
4196        if ((flags & PackageManager.GET_META_DATA) != 0
4197                && (metaData != null || p.mAppMetaData != null)) {
4198            return true;
4199        }
4200        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
4201                && p.usesLibraryFiles != null) {
4202            return true;
4203        }
4204        return false;
4205    }
4206
4207    public static ApplicationInfo generateApplicationInfo(Package p, int flags,
4208            PackageUserState state) {
4209        return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
4210    }
4211
4212    private static void updateApplicationInfo(ApplicationInfo ai, int flags,
4213            PackageUserState state) {
4214        // CompatibilityMode is global state.
4215        if (!sCompatibilityModeEnabled) {
4216            ai.disableCompatibilityMode();
4217        }
4218        if (state.installed) {
4219            ai.flags |= ApplicationInfo.FLAG_INSTALLED;
4220        } else {
4221            ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
4222        }
4223        if (state.blocked) {
4224            ai.flags |= ApplicationInfo.FLAG_BLOCKED;
4225        } else {
4226            ai.flags &= ~ApplicationInfo.FLAG_BLOCKED;
4227        }
4228        if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
4229            ai.enabled = true;
4230        } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
4231            ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
4232        } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
4233                || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
4234            ai.enabled = false;
4235        }
4236        ai.enabledSetting = state.enabled;
4237    }
4238
4239    public static ApplicationInfo generateApplicationInfo(Package p, int flags,
4240            PackageUserState state, int userId) {
4241        if (p == null) return null;
4242        if (!checkUseInstalledOrBlocked(flags, state)) {
4243            return null;
4244        }
4245        if (!copyNeeded(flags, p, state, null, userId)
4246                && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0
4247                        || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
4248            // In this case it is safe to directly modify the internal ApplicationInfo state:
4249            // - CompatibilityMode is global state, so will be the same for every call.
4250            // - We only come in to here if the app should reported as installed; this is the
4251            // default state, and we will do a copy otherwise.
4252            // - The enable state will always be reported the same for the application across
4253            // calls; the only exception is for the UNTIL_USED mode, and in that case we will
4254            // be doing a copy.
4255            updateApplicationInfo(p.applicationInfo, flags, state);
4256            return p.applicationInfo;
4257        }
4258
4259        // Make shallow copy so we can store the metadata/libraries safely
4260        ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
4261        if (userId != 0) {
4262            ai.uid = UserHandle.getUid(userId, ai.uid);
4263            ai.dataDir = PackageManager.getDataDirForUser(userId, ai.packageName);
4264        }
4265        if ((flags & PackageManager.GET_META_DATA) != 0) {
4266            ai.metaData = p.mAppMetaData;
4267        }
4268        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
4269            ai.sharedLibraryFiles = p.usesLibraryFiles;
4270        }
4271        if (state.stopped) {
4272            ai.flags |= ApplicationInfo.FLAG_STOPPED;
4273        } else {
4274            ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
4275        }
4276        updateApplicationInfo(ai, flags, state);
4277        return ai;
4278    }
4279
4280    public static final PermissionInfo generatePermissionInfo(
4281            Permission p, int flags) {
4282        if (p == null) return null;
4283        if ((flags&PackageManager.GET_META_DATA) == 0) {
4284            return p.info;
4285        }
4286        PermissionInfo pi = new PermissionInfo(p.info);
4287        pi.metaData = p.metaData;
4288        return pi;
4289    }
4290
4291    public static final PermissionGroupInfo generatePermissionGroupInfo(
4292            PermissionGroup pg, int flags) {
4293        if (pg == null) return null;
4294        if ((flags&PackageManager.GET_META_DATA) == 0) {
4295            return pg.info;
4296        }
4297        PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);
4298        pgi.metaData = pg.metaData;
4299        return pgi;
4300    }
4301
4302    public final static class Activity extends Component<ActivityIntentInfo> {
4303        public final ActivityInfo info;
4304
4305        public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
4306            super(args, _info);
4307            info = _info;
4308            info.applicationInfo = args.owner.applicationInfo;
4309        }
4310
4311        public void setPackageName(String packageName) {
4312            super.setPackageName(packageName);
4313            info.packageName = packageName;
4314        }
4315
4316        public String toString() {
4317            StringBuilder sb = new StringBuilder(128);
4318            sb.append("Activity{");
4319            sb.append(Integer.toHexString(System.identityHashCode(this)));
4320            sb.append(' ');
4321            appendComponentShortName(sb);
4322            sb.append('}');
4323            return sb.toString();
4324        }
4325    }
4326
4327    public static final ActivityInfo generateActivityInfo(Activity a, int flags,
4328            PackageUserState state, int userId) {
4329        if (a == null) return null;
4330        if (!checkUseInstalledOrBlocked(flags, state)) {
4331            return null;
4332        }
4333        if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
4334            return a.info;
4335        }
4336        // Make shallow copies so we can store the metadata safely
4337        ActivityInfo ai = new ActivityInfo(a.info);
4338        ai.metaData = a.metaData;
4339        ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);
4340        return ai;
4341    }
4342
4343    public final static class Service extends Component<ServiceIntentInfo> {
4344        public final ServiceInfo info;
4345
4346        public Service(final ParseComponentArgs args, final ServiceInfo _info) {
4347            super(args, _info);
4348            info = _info;
4349            info.applicationInfo = args.owner.applicationInfo;
4350        }
4351
4352        public void setPackageName(String packageName) {
4353            super.setPackageName(packageName);
4354            info.packageName = packageName;
4355        }
4356
4357        public String toString() {
4358            StringBuilder sb = new StringBuilder(128);
4359            sb.append("Service{");
4360            sb.append(Integer.toHexString(System.identityHashCode(this)));
4361            sb.append(' ');
4362            appendComponentShortName(sb);
4363            sb.append('}');
4364            return sb.toString();
4365        }
4366    }
4367
4368    public static final ServiceInfo generateServiceInfo(Service s, int flags,
4369            PackageUserState state, int userId) {
4370        if (s == null) return null;
4371        if (!checkUseInstalledOrBlocked(flags, state)) {
4372            return null;
4373        }
4374        if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
4375            return s.info;
4376        }
4377        // Make shallow copies so we can store the metadata safely
4378        ServiceInfo si = new ServiceInfo(s.info);
4379        si.metaData = s.metaData;
4380        si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId);
4381        return si;
4382    }
4383
4384    public final static class Provider extends Component<ProviderIntentInfo> {
4385        public final ProviderInfo info;
4386        public boolean syncable;
4387
4388        public Provider(final ParseComponentArgs args, final ProviderInfo _info) {
4389            super(args, _info);
4390            info = _info;
4391            info.applicationInfo = args.owner.applicationInfo;
4392            syncable = false;
4393        }
4394
4395        public Provider(Provider existingProvider) {
4396            super(existingProvider);
4397            this.info = existingProvider.info;
4398            this.syncable = existingProvider.syncable;
4399        }
4400
4401        public void setPackageName(String packageName) {
4402            super.setPackageName(packageName);
4403            info.packageName = packageName;
4404        }
4405
4406        public String toString() {
4407            StringBuilder sb = new StringBuilder(128);
4408            sb.append("Provider{");
4409            sb.append(Integer.toHexString(System.identityHashCode(this)));
4410            sb.append(' ');
4411            appendComponentShortName(sb);
4412            sb.append('}');
4413            return sb.toString();
4414        }
4415    }
4416
4417    public static final ProviderInfo generateProviderInfo(Provider p, int flags,
4418            PackageUserState state, int userId) {
4419        if (p == null) return null;
4420        if (!checkUseInstalledOrBlocked(flags, state)) {
4421            return null;
4422        }
4423        if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
4424                && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
4425                        || p.info.uriPermissionPatterns == null)) {
4426            return p.info;
4427        }
4428        // Make shallow copies so we can store the metadata safely
4429        ProviderInfo pi = new ProviderInfo(p.info);
4430        pi.metaData = p.metaData;
4431        if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
4432            pi.uriPermissionPatterns = null;
4433        }
4434        pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId);
4435        return pi;
4436    }
4437
4438    public final static class Instrumentation extends Component {
4439        public final InstrumentationInfo info;
4440
4441        public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
4442            super(args, _info);
4443            info = _info;
4444        }
4445
4446        public void setPackageName(String packageName) {
4447            super.setPackageName(packageName);
4448            info.packageName = packageName;
4449        }
4450
4451        public String toString() {
4452            StringBuilder sb = new StringBuilder(128);
4453            sb.append("Instrumentation{");
4454            sb.append(Integer.toHexString(System.identityHashCode(this)));
4455            sb.append(' ');
4456            appendComponentShortName(sb);
4457            sb.append('}');
4458            return sb.toString();
4459        }
4460    }
4461
4462    public static final InstrumentationInfo generateInstrumentationInfo(
4463            Instrumentation i, int flags) {
4464        if (i == null) return null;
4465        if ((flags&PackageManager.GET_META_DATA) == 0) {
4466            return i.info;
4467        }
4468        InstrumentationInfo ii = new InstrumentationInfo(i.info);
4469        ii.metaData = i.metaData;
4470        return ii;
4471    }
4472
4473    public static class IntentInfo extends IntentFilter {
4474        public boolean hasDefault;
4475        public int labelRes;
4476        public CharSequence nonLocalizedLabel;
4477        public int icon;
4478        public int logo;
4479        public int banner;
4480        public int preferred;
4481    }
4482
4483    public final static class ActivityIntentInfo extends IntentInfo {
4484        public final Activity activity;
4485
4486        public ActivityIntentInfo(Activity _activity) {
4487            activity = _activity;
4488        }
4489
4490        public String toString() {
4491            StringBuilder sb = new StringBuilder(128);
4492            sb.append("ActivityIntentInfo{");
4493            sb.append(Integer.toHexString(System.identityHashCode(this)));
4494            sb.append(' ');
4495            activity.appendComponentShortName(sb);
4496            sb.append('}');
4497            return sb.toString();
4498        }
4499    }
4500
4501    public final static class ServiceIntentInfo extends IntentInfo {
4502        public final Service service;
4503
4504        public ServiceIntentInfo(Service _service) {
4505            service = _service;
4506        }
4507
4508        public String toString() {
4509            StringBuilder sb = new StringBuilder(128);
4510            sb.append("ServiceIntentInfo{");
4511            sb.append(Integer.toHexString(System.identityHashCode(this)));
4512            sb.append(' ');
4513            service.appendComponentShortName(sb);
4514            sb.append('}');
4515            return sb.toString();
4516        }
4517    }
4518
4519    public static final class ProviderIntentInfo extends IntentInfo {
4520        public final Provider provider;
4521
4522        public ProviderIntentInfo(Provider provider) {
4523            this.provider = provider;
4524        }
4525
4526        public String toString() {
4527            StringBuilder sb = new StringBuilder(128);
4528            sb.append("ProviderIntentInfo{");
4529            sb.append(Integer.toHexString(System.identityHashCode(this)));
4530            sb.append(' ');
4531            provider.appendComponentShortName(sb);
4532            sb.append('}');
4533            return sb.toString();
4534        }
4535    }
4536
4537    /**
4538     * @hide
4539     */
4540    public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
4541        sCompatibilityModeEnabled = compatibilityModeEnabled;
4542    }
4543
4544    private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>();
4545
4546    public static long readFullyIgnoringContents(InputStream in) throws IOException {
4547        byte[] buffer = sBuffer.getAndSet(null);
4548        if (buffer == null) {
4549            buffer = new byte[4096];
4550        }
4551
4552        int n = 0;
4553        int count = 0;
4554        while ((n = in.read(buffer, 0, buffer.length)) != -1) {
4555            count += n;
4556        }
4557
4558        sBuffer.set(buffer);
4559        return count;
4560    }
4561
4562    public static void closeQuietly(StrictJarFile jarFile) {
4563        if (jarFile != null) {
4564            try {
4565                jarFile.close();
4566            } catch (Exception ignored) {
4567            }
4568        }
4569    }
4570
4571    public static class PackageParserException extends Exception {
4572        public final int error;
4573
4574        public PackageParserException(int error, String detailMessage) {
4575            super(detailMessage);
4576            this.error = error;
4577        }
4578
4579        public PackageParserException(int error, String detailMessage, Throwable throwable) {
4580            super(detailMessage, throwable);
4581            this.error = error;
4582        }
4583    }
4584}
4585