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