PackageParser.java revision 354cd3ce2213a1032d9138ea6fa1420f055ab08c
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 com.android.internal.R;
20import com.android.internal.util.ArrayUtils;
21import com.android.internal.util.XmlUtils;
22
23import org.xmlpull.v1.XmlPullParser;
24import org.xmlpull.v1.XmlPullParserException;
25
26import android.app.ActivityManager;
27import android.content.ComponentName;
28import android.content.Intent;
29import android.content.IntentFilter;
30import android.content.res.AssetManager;
31import android.content.res.Configuration;
32import android.content.res.Resources;
33import android.content.res.TypedArray;
34import android.content.res.XmlResourceParser;
35import android.os.Build;
36import android.os.Bundle;
37import android.os.FileUtils;
38import android.os.PatternMatcher;
39import android.os.Trace;
40import android.os.UserHandle;
41import android.text.TextUtils;
42import android.util.ArrayMap;
43import android.util.ArraySet;
44import android.util.AttributeSet;
45import android.util.Base64;
46import android.util.DisplayMetrics;
47import android.util.Log;
48import android.util.Pair;
49import android.util.Slog;
50import android.util.TypedValue;
51import android.util.apk.ApkSignatureSchemeV2Verifier;
52import android.util.jar.StrictJarFile;
53import android.view.Gravity;
54
55import java.io.File;
56import java.io.IOException;
57import java.io.InputStream;
58import java.io.PrintWriter;
59import java.security.GeneralSecurityException;
60import java.security.KeyFactory;
61import java.security.NoSuchAlgorithmException;
62import java.security.PublicKey;
63import java.security.cert.Certificate;
64import java.security.cert.CertificateEncodingException;
65import java.security.spec.EncodedKeySpec;
66import java.security.spec.InvalidKeySpecException;
67import java.security.spec.X509EncodedKeySpec;
68import java.util.ArrayList;
69import java.util.Arrays;
70import java.util.Collections;
71import java.util.Comparator;
72import java.util.Iterator;
73import java.util.List;
74import java.util.Set;
75import java.util.concurrent.atomic.AtomicReference;
76import java.util.zip.ZipEntry;
77
78import libcore.io.IoUtils;
79
80import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
81import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
82import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
83import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
84import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
85import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
86import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
87import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES;
88import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
89import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
90import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
91import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
92import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
93import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
94import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
95import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
96import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
97
98/**
99 * Parser for package files (APKs) on disk. This supports apps packaged either
100 * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple
101 * APKs in a single directory.
102 * <p>
103 * Apps packaged as multiple APKs always consist of a single "base" APK (with a
104 * {@code null} split name) and zero or more "split" APKs (with unique split
105 * names). Any subset of those split APKs are a valid install, as long as the
106 * following constraints are met:
107 * <ul>
108 * <li>All APKs must have the exact same package name, version code, and signing
109 * certificates.
110 * <li>All APKs must have unique split names.
111 * <li>All installations must contain a single base APK.
112 * </ul>
113 *
114 * @hide
115 */
116public class PackageParser {
117    private static final boolean DEBUG_JAR = false;
118    private static final boolean DEBUG_PARSER = false;
119    private static final boolean DEBUG_BACKUP = false;
120
121    private static final int MAX_PACKAGES_PER_APK = 5;
122
123    // TODO: switch outError users to PackageParserException
124    // TODO: refactor "codePath" to "apkPath"
125
126    /** File name in an APK for the Android manifest. */
127    private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
128
129    /**
130     * File name in an APK for bytecode.  There may be additional bytecode files
131     * but this one is always required for an APK that has code.
132     */
133    private static final String BYTECODE_FILENAME = "classes.dex";
134
135    /** Path prefix for apps on expanded storage */
136    private static final String MNT_EXPAND = "/mnt/expand/";
137
138    private static final String TAG_MANIFEST = "manifest";
139    private static final String TAG_APPLICATION = "application";
140    private static final String TAG_OVERLAY = "overlay";
141    private static final String TAG_KEY_SETS = "key-sets";
142    private static final String TAG_PERMISSION_GROUP = "permission-group";
143    private static final String TAG_PERMISSION = "permission";
144    private static final String TAG_PERMISSION_TREE = "permission-tree";
145    private static final String TAG_USES_PERMISSION = "uses-permission";
146    private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
147    private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";
148    private static final String TAG_USES_CONFIGURATION = "uses-configuration";
149    private static final String TAG_USES_FEATURE = "uses-feature";
150    private static final String TAG_FEATURE_GROUP = "feature-group";
151    private static final String TAG_USES_SDK = "uses-sdk";
152    private static final String TAG_SUPPORT_SCREENS = "supports-screens";
153    private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";
154    private static final String TAG_INSTRUMENTATION = "instrumentation";
155    private static final String TAG_ORIGINAL_PACKAGE = "original-package";
156    private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
157    private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
158    private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";
159    private static final String TAG_SUPPORTS_INPUT = "supports-input";
160    private static final String TAG_EAT_COMMENT = "eat-comment";
161    private static final String TAG_PACKAGE = "package";
162
163    // These are the tags supported by child packages
164    private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
165    static {
166        CHILD_PACKAGE_TAGS.add(TAG_APPLICATION);
167        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION);
168        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M);
169        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23);
170        CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION);
171        CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE);
172        CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP);
173        CHILD_PACKAGE_TAGS.add(TAG_USES_SDK);
174        CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS);
175        CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION);
176        CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE);
177        CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS);
178        CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT);
179        CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
180    }
181
182    /** @hide */
183    public static class NewPermissionInfo {
184        public final String name;
185        public final int sdkVersion;
186        public final int fileVersion;
187
188        public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {
189            this.name = name;
190            this.sdkVersion = sdkVersion;
191            this.fileVersion = fileVersion;
192        }
193    }
194
195    /** @hide */
196    public static class SplitPermissionInfo {
197        public final String rootPerm;
198        public final String[] newPerms;
199        public final int targetSdk;
200
201        public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
202            this.rootPerm = rootPerm;
203            this.newPerms = newPerms;
204            this.targetSdk = targetSdk;
205        }
206    }
207
208    /**
209     * List of new permissions that have been added since 1.0.
210     * NOTE: These must be declared in SDK version order, with permissions
211     * added to older SDKs appearing before those added to newer SDKs.
212     * If sdkVersion is 0, then this is not a permission that we want to
213     * automatically add to older apps, but we do want to allow it to be
214     * granted during a platform update.
215     * @hide
216     */
217    public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] =
218        new PackageParser.NewPermissionInfo[] {
219            new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
220                    android.os.Build.VERSION_CODES.DONUT, 0),
221            new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE,
222                    android.os.Build.VERSION_CODES.DONUT, 0)
223    };
224
225    /**
226     * List of permissions that have been split into more granular or dependent
227     * permissions.
228     * @hide
229     */
230    public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] =
231        new PackageParser.SplitPermissionInfo[] {
232            // READ_EXTERNAL_STORAGE is always required when an app requests
233            // WRITE_EXTERNAL_STORAGE, because we can't have an app that has
234            // write access without read access.  The hack here with the target
235            // target SDK version ensures that this grant is always done.
236            new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
237                    new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE },
238                    android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1),
239            new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
240                    new String[] { android.Manifest.permission.READ_CALL_LOG },
241                    android.os.Build.VERSION_CODES.JELLY_BEAN),
242            new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
243                    new String[] { android.Manifest.permission.WRITE_CALL_LOG },
244                    android.os.Build.VERSION_CODES.JELLY_BEAN)
245    };
246
247    /**
248     * @deprecated callers should move to explicitly passing around source path.
249     */
250    @Deprecated
251    private String mArchiveSourcePath;
252
253    private String[] mSeparateProcesses;
254    private boolean mOnlyCoreApps;
255    private DisplayMetrics mMetrics;
256
257    private static final int SDK_VERSION = Build.VERSION.SDK_INT;
258    private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
259
260    private int mParseError = PackageManager.INSTALL_SUCCEEDED;
261
262    private static boolean sCompatibilityModeEnabled = true;
263    private static final int PARSE_DEFAULT_INSTALL_LOCATION =
264            PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
265
266    static class ParsePackageItemArgs {
267        final Package owner;
268        final String[] outError;
269        final int nameRes;
270        final int labelRes;
271        final int iconRes;
272        final int logoRes;
273        final int bannerRes;
274
275        String tag;
276        TypedArray sa;
277
278        ParsePackageItemArgs(Package _owner, String[] _outError,
279                int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes) {
280            owner = _owner;
281            outError = _outError;
282            nameRes = _nameRes;
283            labelRes = _labelRes;
284            iconRes = _iconRes;
285            logoRes = _logoRes;
286            bannerRes = _bannerRes;
287        }
288    }
289
290    static class ParseComponentArgs extends ParsePackageItemArgs {
291        final String[] sepProcesses;
292        final int processRes;
293        final int descriptionRes;
294        final int enabledRes;
295        int flags;
296
297        ParseComponentArgs(Package _owner, String[] _outError,
298                int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes,
299                String[] _sepProcesses, int _processRes,
300                int _descriptionRes, int _enabledRes) {
301            super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes, _bannerRes);
302            sepProcesses = _sepProcesses;
303            processRes = _processRes;
304            descriptionRes = _descriptionRes;
305            enabledRes = _enabledRes;
306        }
307    }
308
309    /**
310     * Lightweight parsed details about a single package.
311     */
312    public static class PackageLite {
313        public final String packageName;
314        public final int versionCode;
315        public final int installLocation;
316        public final VerifierInfo[] verifiers;
317
318        /** Names of any split APKs, ordered by parsed splitName */
319        public final String[] splitNames;
320
321        /**
322         * Path where this package was found on disk. For monolithic packages
323         * this is path to single base APK file; for cluster packages this is
324         * path to the cluster directory.
325         */
326        public final String codePath;
327
328        /** Path of base APK */
329        public final String baseCodePath;
330        /** Paths of any split APKs, ordered by parsed splitName */
331        public final String[] splitCodePaths;
332
333        /** Revision code of base APK */
334        public final int baseRevisionCode;
335        /** Revision codes of any split APKs, ordered by parsed splitName */
336        public final int[] splitRevisionCodes;
337
338        public final boolean coreApp;
339        public final boolean multiArch;
340        public final String abiOverride;
341        public final boolean extractNativeLibs;
342
343        public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
344                String[] splitCodePaths, int[] splitRevisionCodes) {
345            this.packageName = baseApk.packageName;
346            this.versionCode = baseApk.versionCode;
347            this.installLocation = baseApk.installLocation;
348            this.verifiers = baseApk.verifiers;
349            this.splitNames = splitNames;
350            this.codePath = codePath;
351            this.baseCodePath = baseApk.codePath;
352            this.splitCodePaths = splitCodePaths;
353            this.baseRevisionCode = baseApk.revisionCode;
354            this.splitRevisionCodes = splitRevisionCodes;
355            this.coreApp = baseApk.coreApp;
356            this.multiArch = baseApk.multiArch;
357            this.abiOverride = baseApk.abiOverride;
358            this.extractNativeLibs = baseApk.extractNativeLibs;
359        }
360
361        public List<String> getAllCodePaths() {
362            ArrayList<String> paths = new ArrayList<>();
363            paths.add(baseCodePath);
364            if (!ArrayUtils.isEmpty(splitCodePaths)) {
365                Collections.addAll(paths, splitCodePaths);
366            }
367            return paths;
368        }
369    }
370
371    /**
372     * Lightweight parsed details about a single APK file.
373     */
374    public static class ApkLite {
375        public final String codePath;
376        public final String packageName;
377        public final String splitName;
378        public final int versionCode;
379        public final int revisionCode;
380        public final int installLocation;
381        public final VerifierInfo[] verifiers;
382        public final Signature[] signatures;
383        public final boolean coreApp;
384        public final boolean multiArch;
385        public final String abiOverride;
386        public final boolean extractNativeLibs;
387
388        public ApkLite(String codePath, String packageName, String splitName, int versionCode,
389                int revisionCode, int installLocation, List<VerifierInfo> verifiers,
390                Signature[] signatures, boolean coreApp, boolean multiArch, String abiOverride,
391                boolean extractNativeLibs) {
392            this.codePath = codePath;
393            this.packageName = packageName;
394            this.splitName = splitName;
395            this.versionCode = versionCode;
396            this.revisionCode = revisionCode;
397            this.installLocation = installLocation;
398            this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
399            this.signatures = signatures;
400            this.coreApp = coreApp;
401            this.multiArch = multiArch;
402            this.abiOverride = abiOverride;
403            this.extractNativeLibs = extractNativeLibs;
404        }
405    }
406
407    private ParsePackageItemArgs mParseInstrumentationArgs;
408    private ParseComponentArgs mParseActivityArgs;
409    private ParseComponentArgs mParseActivityAliasArgs;
410    private ParseComponentArgs mParseServiceArgs;
411    private ParseComponentArgs mParseProviderArgs;
412
413    /** If set to true, we will only allow package files that exactly match
414     *  the DTD.  Otherwise, we try to get as much from the package as we
415     *  can without failing.  This should normally be set to false, to
416     *  support extensions to the DTD in future versions. */
417    private static final boolean RIGID_PARSER = false;
418
419    private static final String TAG = "PackageParser";
420
421    public PackageParser() {
422        mMetrics = new DisplayMetrics();
423        mMetrics.setToDefaults();
424    }
425
426    public void setSeparateProcesses(String[] procs) {
427        mSeparateProcesses = procs;
428    }
429
430    /**
431     * Flag indicating this parser should only consider apps with
432     * {@code coreApp} manifest attribute to be valid apps. This is useful when
433     * creating a minimalist boot environment.
434     */
435    public void setOnlyCoreApps(boolean onlyCoreApps) {
436        mOnlyCoreApps = onlyCoreApps;
437    }
438
439    public void setDisplayMetrics(DisplayMetrics metrics) {
440        mMetrics = metrics;
441    }
442
443    public static final boolean isApkFile(File file) {
444        return isApkPath(file.getName());
445    }
446
447    private static boolean isApkPath(String path) {
448        return path.endsWith(".apk");
449    }
450
451    /**
452     * Generate and return the {@link PackageInfo} for a parsed package.
453     *
454     * @param p the parsed package.
455     * @param flags indicating which optional information is included.
456     */
457    public static PackageInfo generatePackageInfo(PackageParser.Package p,
458            int gids[], int flags, long firstInstallTime, long lastUpdateTime,
459            Set<String> grantedPermissions, PackageUserState state) {
460
461        return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
462                grantedPermissions, state, UserHandle.getCallingUserId());
463    }
464
465    /**
466     * Returns true if the package is installed and not hidden, or if the caller
467     * explicitly wanted all uninstalled and hidden packages as well.
468     */
469    private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state) {
470        return (state.installed && !state.hidden)
471                || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
472    }
473
474    public static boolean isAvailable(PackageUserState state) {
475        return checkUseInstalledOrHidden(0, state);
476    }
477
478    public static PackageInfo generatePackageInfo(PackageParser.Package p,
479            int gids[], int flags, long firstInstallTime, long lastUpdateTime,
480            Set<String> grantedPermissions, PackageUserState state, int userId) {
481        if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) {
482            return null;
483        }
484        PackageInfo pi = new PackageInfo();
485        pi.packageName = p.packageName;
486        pi.splitNames = p.splitNames;
487        pi.versionCode = p.mVersionCode;
488        pi.baseRevisionCode = p.baseRevisionCode;
489        pi.splitRevisionCodes = p.splitRevisionCodes;
490        pi.versionName = p.mVersionName;
491        pi.sharedUserId = p.mSharedUserId;
492        pi.sharedUserLabel = p.mSharedUserLabel;
493        pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
494        pi.installLocation = p.installLocation;
495        pi.coreApp = p.coreApp;
496        if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0
497                || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
498            pi.requiredForAllUsers = p.mRequiredForAllUsers;
499        }
500        pi.restrictedAccountType = p.mRestrictedAccountType;
501        pi.requiredAccountType = p.mRequiredAccountType;
502        pi.overlayTarget = p.mOverlayTarget;
503        pi.firstInstallTime = firstInstallTime;
504        pi.lastUpdateTime = lastUpdateTime;
505        if ((flags&PackageManager.GET_GIDS) != 0) {
506            pi.gids = gids;
507        }
508        if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) {
509            int N = p.configPreferences != null ? p.configPreferences.size() : 0;
510            if (N > 0) {
511                pi.configPreferences = new ConfigurationInfo[N];
512                p.configPreferences.toArray(pi.configPreferences);
513            }
514            N = p.reqFeatures != null ? p.reqFeatures.size() : 0;
515            if (N > 0) {
516                pi.reqFeatures = new FeatureInfo[N];
517                p.reqFeatures.toArray(pi.reqFeatures);
518            }
519            N = p.featureGroups != null ? p.featureGroups.size() : 0;
520            if (N > 0) {
521                pi.featureGroups = new FeatureGroupInfo[N];
522                p.featureGroups.toArray(pi.featureGroups);
523            }
524        }
525        if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
526            final int N = p.activities.size();
527            if (N > 0) {
528                int num = 0;
529                final ActivityInfo[] res = new ActivityInfo[N];
530                for (int i = 0; i < N; i++) {
531                    final Activity a = p.activities.get(i);
532                    if (state.isMatch(a.info, flags)) {
533                        res[num++] = generateActivityInfo(a, flags, state, userId);
534                    }
535                }
536                pi.activities = ArrayUtils.trimToSize(res, num);
537            }
538        }
539        if ((flags & PackageManager.GET_RECEIVERS) != 0) {
540            final int N = p.receivers.size();
541            if (N > 0) {
542                int num = 0;
543                final ActivityInfo[] res = new ActivityInfo[N];
544                for (int i = 0; i < N; i++) {
545                    final Activity a = p.receivers.get(i);
546                    if (state.isMatch(a.info, flags)) {
547                        res[num++] = generateActivityInfo(a, flags, state, userId);
548                    }
549                }
550                pi.receivers = ArrayUtils.trimToSize(res, num);
551            }
552        }
553        if ((flags & PackageManager.GET_SERVICES) != 0) {
554            final int N = p.services.size();
555            if (N > 0) {
556                int num = 0;
557                final ServiceInfo[] res = new ServiceInfo[N];
558                for (int i = 0; i < N; i++) {
559                    final Service s = p.services.get(i);
560                    if (state.isMatch(s.info, flags)) {
561                        res[num++] = generateServiceInfo(s, flags, state, userId);
562                    }
563                }
564                pi.services = ArrayUtils.trimToSize(res, num);
565            }
566        }
567        if ((flags & PackageManager.GET_PROVIDERS) != 0) {
568            final int N = p.providers.size();
569            if (N > 0) {
570                int num = 0;
571                final ProviderInfo[] res = new ProviderInfo[N];
572                for (int i = 0; i < N; i++) {
573                    final Provider pr = p.providers.get(i);
574                    if (state.isMatch(pr.info, flags)) {
575                        res[num++] = generateProviderInfo(pr, flags, state, userId);
576                    }
577                }
578                pi.providers = ArrayUtils.trimToSize(res, num);
579            }
580        }
581        if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) {
582            int N = p.instrumentation.size();
583            if (N > 0) {
584                pi.instrumentation = new InstrumentationInfo[N];
585                for (int i=0; i<N; i++) {
586                    pi.instrumentation[i] = generateInstrumentationInfo(
587                            p.instrumentation.get(i), flags);
588                }
589            }
590        }
591        if ((flags&PackageManager.GET_PERMISSIONS) != 0) {
592            int N = p.permissions.size();
593            if (N > 0) {
594                pi.permissions = new PermissionInfo[N];
595                for (int i=0; i<N; i++) {
596                    pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags);
597                }
598            }
599            N = p.requestedPermissions.size();
600            if (N > 0) {
601                pi.requestedPermissions = new String[N];
602                pi.requestedPermissionsFlags = new int[N];
603                for (int i=0; i<N; i++) {
604                    final String perm = p.requestedPermissions.get(i);
605                    pi.requestedPermissions[i] = perm;
606                    // The notion of required permissions is deprecated but for compatibility.
607                    pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
608                    if (grantedPermissions != null && grantedPermissions.contains(perm)) {
609                        pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
610                    }
611                }
612            }
613        }
614        if ((flags&PackageManager.GET_SIGNATURES) != 0) {
615           int N = (p.mSignatures != null) ? p.mSignatures.length : 0;
616           if (N > 0) {
617                pi.signatures = new Signature[N];
618                System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);
619            }
620        }
621        return pi;
622    }
623
624    private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry)
625            throws PackageParserException {
626        InputStream is = null;
627        try {
628            // We must read the stream for the JarEntry to retrieve
629            // its certificates.
630            is = jarFile.getInputStream(entry);
631            readFullyIgnoringContents(is);
632            return jarFile.getCertificateChains(entry);
633        } catch (IOException | RuntimeException e) {
634            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
635                    "Failed reading " + entry.getName() + " in " + jarFile, e);
636        } finally {
637            IoUtils.closeQuietly(is);
638        }
639    }
640
641    public final static int PARSE_IS_SYSTEM = 1<<0;
642    public final static int PARSE_CHATTY = 1<<1;
643    public final static int PARSE_MUST_BE_APK = 1<<2;
644    public final static int PARSE_IGNORE_PROCESSES = 1<<3;
645    public final static int PARSE_FORWARD_LOCK = 1<<4;
646    public final static int PARSE_EXTERNAL_STORAGE = 1<<5;
647    public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
648    public final static int PARSE_IS_PRIVILEGED = 1<<7;
649    public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
650    public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
651    public final static int PARSE_ENFORCE_CODE = 1<<10;
652    public final static int PARSE_IS_EPHEMERAL = 1<<11;
653
654    private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
655
656    /**
657     * Used to sort a set of APKs based on their split names, always placing the
658     * base APK (with {@code null} split name) first.
659     */
660    private static class SplitNameComparator implements Comparator<String> {
661        @Override
662        public int compare(String lhs, String rhs) {
663            if (lhs == null) {
664                return -1;
665            } else if (rhs == null) {
666                return 1;
667            } else {
668                return lhs.compareTo(rhs);
669            }
670        }
671    }
672
673    /**
674     * Parse only lightweight details about the package at the given location.
675     * Automatically detects if the package is a monolithic style (single APK
676     * file) or cluster style (directory of APKs).
677     * <p>
678     * This performs sanity checking on cluster style packages, such as
679     * requiring identical package name and version codes, a single base APK,
680     * and unique split names.
681     *
682     * @see PackageParser#parsePackage(File, int)
683     */
684    public static PackageLite parsePackageLite(File packageFile, int flags)
685            throws PackageParserException {
686        if (packageFile.isDirectory()) {
687            return parseClusterPackageLite(packageFile, flags);
688        } else {
689            return parseMonolithicPackageLite(packageFile, flags);
690        }
691    }
692
693    private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)
694            throws PackageParserException {
695        final ApkLite baseApk = parseApkLite(packageFile, flags);
696        final String packagePath = packageFile.getAbsolutePath();
697        return new PackageLite(packagePath, baseApk, null, null, null);
698    }
699
700    private static PackageLite parseClusterPackageLite(File packageDir, int flags)
701            throws PackageParserException {
702        final File[] files = packageDir.listFiles();
703        if (ArrayUtils.isEmpty(files)) {
704            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
705                    "No packages found in split");
706        }
707
708        String packageName = null;
709        int versionCode = 0;
710
711        final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
712        for (File file : files) {
713            if (isApkFile(file)) {
714                final ApkLite lite = parseApkLite(file, flags);
715
716                // Assert that all package names and version codes are
717                // consistent with the first one we encounter.
718                if (packageName == null) {
719                    packageName = lite.packageName;
720                    versionCode = lite.versionCode;
721                } else {
722                    if (!packageName.equals(lite.packageName)) {
723                        throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
724                                "Inconsistent package " + lite.packageName + " in " + file
725                                + "; expected " + packageName);
726                    }
727                    if (versionCode != lite.versionCode) {
728                        throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
729                                "Inconsistent version " + lite.versionCode + " in " + file
730                                + "; expected " + versionCode);
731                    }
732                }
733
734                // Assert that each split is defined only once
735                if (apks.put(lite.splitName, lite) != null) {
736                    throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
737                            "Split name " + lite.splitName
738                            + " defined more than once; most recent was " + file);
739                }
740            }
741        }
742
743        final ApkLite baseApk = apks.remove(null);
744        if (baseApk == null) {
745            throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
746                    "Missing base APK in " + packageDir);
747        }
748
749        // Always apply deterministic ordering based on splitName
750        final int size = apks.size();
751
752        String[] splitNames = null;
753        String[] splitCodePaths = null;
754        int[] splitRevisionCodes = null;
755        if (size > 0) {
756            splitNames = new String[size];
757            splitCodePaths = new String[size];
758            splitRevisionCodes = new int[size];
759
760            splitNames = apks.keySet().toArray(splitNames);
761            Arrays.sort(splitNames, sSplitNameComparator);
762
763            for (int i = 0; i < size; i++) {
764                splitCodePaths[i] = apks.get(splitNames[i]).codePath;
765                splitRevisionCodes[i] = apks.get(splitNames[i]).revisionCode;
766            }
767        }
768
769        final String codePath = packageDir.getAbsolutePath();
770        return new PackageLite(codePath, baseApk, splitNames, splitCodePaths,
771                splitRevisionCodes);
772    }
773
774    /**
775     * Parse the package at the given location. Automatically detects if the
776     * package is a monolithic style (single APK file) or cluster style
777     * (directory of APKs).
778     * <p>
779     * This performs sanity checking on cluster style packages, such as
780     * requiring identical package name and version codes, a single base APK,
781     * and unique split names.
782     * <p>
783     * Note that this <em>does not</em> perform signature verification; that
784     * must be done separately in {@link #collectCertificates(Package, int)}.
785     *
786     * @see #parsePackageLite(File, int)
787     */
788    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
789        if (packageFile.isDirectory()) {
790            return parseClusterPackage(packageFile, flags);
791        } else {
792            return parseMonolithicPackage(packageFile, flags);
793        }
794    }
795
796    /**
797     * Parse all APKs contained in the given directory, treating them as a
798     * single package. This also performs sanity checking, such as requiring
799     * identical package name and version codes, a single base APK, and unique
800     * split names.
801     * <p>
802     * Note that this <em>does not</em> perform signature verification; that
803     * must be done separately in {@link #collectCertificates(Package, int)}.
804     */
805    private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
806        final PackageLite lite = parseClusterPackageLite(packageDir, 0);
807
808        if (mOnlyCoreApps && !lite.coreApp) {
809            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
810                    "Not a coreApp: " + packageDir);
811        }
812
813        final AssetManager assets = new AssetManager();
814        try {
815            // Load the base and all splits into the AssetManager
816            // so that resources can be overriden when parsing the manifests.
817            loadApkIntoAssetManager(assets, lite.baseCodePath, flags);
818
819            if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
820                for (String path : lite.splitCodePaths) {
821                    loadApkIntoAssetManager(assets, path, flags);
822                }
823            }
824
825            final File baseApk = new File(lite.baseCodePath);
826            final Package pkg = parseBaseApk(baseApk, assets, flags);
827            if (pkg == null) {
828                throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
829                        "Failed to parse base APK: " + baseApk);
830            }
831
832            if (!ArrayUtils.isEmpty(lite.splitNames)) {
833                final int num = lite.splitNames.length;
834                pkg.splitNames = lite.splitNames;
835                pkg.splitCodePaths = lite.splitCodePaths;
836                pkg.splitRevisionCodes = lite.splitRevisionCodes;
837                pkg.splitFlags = new int[num];
838                pkg.splitPrivateFlags = new int[num];
839
840                for (int i = 0; i < num; i++) {
841                    parseSplitApk(pkg, i, assets, flags);
842                }
843            }
844
845            pkg.setCodePath(packageDir.getAbsolutePath());
846            pkg.setCpuAbiOverride(lite.abiOverride);
847
848            return pkg;
849        } finally {
850            IoUtils.closeQuietly(assets);
851        }
852    }
853
854    /**
855     * Parse the given APK file, treating it as as a single monolithic package.
856     * <p>
857     * Note that this <em>does not</em> perform signature verification; that
858     * must be done separately in {@link #collectCertificates(Package, int)}.
859     *
860     * @deprecated external callers should move to
861     *             {@link #parsePackage(File, int)}. Eventually this method will
862     *             be marked private.
863     */
864    @Deprecated
865    public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
866        final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
867        if (mOnlyCoreApps) {
868            if (!lite.coreApp) {
869                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
870                        "Not a coreApp: " + apkFile);
871            }
872        }
873
874        final AssetManager assets = new AssetManager();
875        try {
876            final Package pkg = parseBaseApk(apkFile, assets, flags);
877            pkg.setCodePath(apkFile.getAbsolutePath());
878            pkg.setCpuAbiOverride(lite.abiOverride);
879            return pkg;
880        } finally {
881            IoUtils.closeQuietly(assets);
882        }
883    }
884
885    private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
886            throws PackageParserException {
887        if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
888            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
889                    "Invalid package file: " + apkPath);
890        }
891
892        // The AssetManager guarantees uniqueness for asset paths, so if this asset path
893        // already exists in the AssetManager, addAssetPath will only return the cookie
894        // assigned to it.
895        int cookie = assets.addAssetPath(apkPath);
896        if (cookie == 0) {
897            throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
898                    "Failed adding asset path: " + apkPath);
899        }
900        return cookie;
901    }
902
903    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
904            throws PackageParserException {
905        final String apkPath = apkFile.getAbsolutePath();
906
907        String volumeUuid = null;
908        if (apkPath.startsWith(MNT_EXPAND)) {
909            final int end = apkPath.indexOf('/', MNT_EXPAND.length());
910            volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
911        }
912
913        mParseError = PackageManager.INSTALL_SUCCEEDED;
914        mArchiveSourcePath = apkFile.getAbsolutePath();
915
916        if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
917
918        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
919
920        Resources res = null;
921        XmlResourceParser parser = null;
922        try {
923            res = new Resources(assets, mMetrics, null);
924            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
925                    Build.VERSION.RESOURCES_SDK_INT);
926            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
927
928            final String[] outError = new String[1];
929            final Package pkg = parseBaseApk(res, parser, flags, outError);
930            if (pkg == null) {
931                throw new PackageParserException(mParseError,
932                        apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
933            }
934
935            pkg.setVolumeUuid(volumeUuid);
936            pkg.setApplicationVolumeUuid(volumeUuid);
937            pkg.setBaseCodePath(apkPath);
938            pkg.setSignatures(null);
939
940            return pkg;
941
942        } catch (PackageParserException e) {
943            throw e;
944        } catch (Exception e) {
945            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
946                    "Failed to read manifest from " + apkPath, e);
947        } finally {
948            IoUtils.closeQuietly(parser);
949        }
950    }
951
952    private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags)
953            throws PackageParserException {
954        final String apkPath = pkg.splitCodePaths[splitIndex];
955
956        mParseError = PackageManager.INSTALL_SUCCEEDED;
957        mArchiveSourcePath = apkPath;
958
959        if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
960
961        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
962
963        Resources res = null;
964        XmlResourceParser parser = null;
965        try {
966            res = new Resources(assets, mMetrics, null);
967            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
968                    Build.VERSION.RESOURCES_SDK_INT);
969            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
970
971            final String[] outError = new String[1];
972            pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
973            if (pkg == null) {
974                throw new PackageParserException(mParseError,
975                        apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
976            }
977
978        } catch (PackageParserException e) {
979            throw e;
980        } catch (Exception e) {
981            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
982                    "Failed to read manifest from " + apkPath, e);
983        } finally {
984            IoUtils.closeQuietly(parser);
985        }
986    }
987
988    /**
989     * Parse the manifest of a <em>split APK</em>.
990     * <p>
991     * Note that split APKs have many more restrictions on what they're capable
992     * of doing, so many valid features of a base APK have been carefully
993     * omitted here.
994     */
995    private Package parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags,
996            int splitIndex, String[] outError) throws XmlPullParserException, IOException,
997            PackageParserException {
998        AttributeSet attrs = parser;
999
1000        // We parsed manifest tag earlier; just skip past it
1001        parsePackageSplitNames(parser, attrs);
1002
1003        mParseInstrumentationArgs = null;
1004        mParseActivityArgs = null;
1005        mParseServiceArgs = null;
1006        mParseProviderArgs = null;
1007
1008        int type;
1009
1010        boolean foundApp = false;
1011
1012        int outerDepth = parser.getDepth();
1013        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1014                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1015            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1016                continue;
1017            }
1018
1019            String tagName = parser.getName();
1020            if (tagName.equals("application")) {
1021                if (foundApp) {
1022                    if (RIGID_PARSER) {
1023                        outError[0] = "<manifest> has more than one <application>";
1024                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1025                        return null;
1026                    } else {
1027                        Slog.w(TAG, "<manifest> has more than one <application>");
1028                        XmlUtils.skipCurrentTag(parser);
1029                        continue;
1030                    }
1031                }
1032
1033                foundApp = true;
1034                if (!parseSplitApplication(pkg, res, parser, flags, splitIndex, outError)) {
1035                    return null;
1036                }
1037
1038            } else if (RIGID_PARSER) {
1039                outError[0] = "Bad element under <manifest>: "
1040                    + parser.getName();
1041                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1042                return null;
1043
1044            } else {
1045                Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
1046                        + " at " + mArchiveSourcePath + " "
1047                        + parser.getPositionDescription());
1048                XmlUtils.skipCurrentTag(parser);
1049                continue;
1050            }
1051        }
1052
1053        if (!foundApp) {
1054            outError[0] = "<manifest> does not contain an <application>";
1055            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
1056        }
1057
1058        return pkg;
1059    }
1060
1061    /**
1062     * Collect certificates from all the APKs described in the given package,
1063     * populating {@link Package#mSignatures}. Also asserts that all APK
1064     * contents are signed correctly and consistently.
1065     */
1066    public static void collectCertificates(Package pkg, int parseFlags) throws PackageParserException {
1067        collectCertificatesInternal(pkg, parseFlags);
1068        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
1069        for (int i = 0; i < childCount; i++) {
1070            Package childPkg = pkg.childPackages.get(i);
1071            childPkg.mCertificates = pkg.mCertificates;
1072            childPkg.mSignatures = pkg.mSignatures;
1073            childPkg.mSigningKeys = pkg.mSigningKeys;
1074        }
1075    }
1076
1077    private static void collectCertificatesInternal(Package pkg, int parseFlags) throws PackageParserException {
1078        pkg.mCertificates = null;
1079        pkg.mSignatures = null;
1080        pkg.mSigningKeys = null;
1081
1082        collectCertificates(pkg, new File(pkg.baseCodePath), pkg.applicationInfo.flags, parseFlags);
1083
1084        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
1085            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
1086                collectCertificates(pkg, new File(pkg.splitCodePaths[i]), pkg.splitFlags[i],
1087                        parseFlags);
1088            }
1089        }
1090    }
1091
1092    private static void collectCertificates(Package pkg, File apkFile, int apkFlags, int parseFlags)
1093            throws PackageParserException {
1094        final boolean hasCode = (apkFlags & ApplicationInfo.FLAG_HAS_CODE) != 0;
1095        final boolean requireCode = ((parseFlags & PARSE_ENFORCE_CODE) != 0) && hasCode;
1096        final String apkPath = apkFile.getAbsolutePath();
1097
1098        // Try to verify the APK using APK Signature Scheme v2.
1099        boolean verified = false;
1100        {
1101            Certificate[][] allSignersCerts = null;
1102            Signature[] signatures = null;
1103            try {
1104                allSignersCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
1105                signatures = convertToSignatures(allSignersCerts);
1106                // APK verified using APK Signature Scheme v2.
1107                verified = true;
1108            } catch (ApkSignatureSchemeV2Verifier.SignatureNotFoundException e) {
1109                // No APK Signature Scheme v2 signature found
1110            } catch (Exception e) {
1111                // APK Signature Scheme v2 signature was found but did not verify
1112                throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1113                        "Failed to collect certificates from " + apkPath
1114                                + " using APK Signature Scheme v2",
1115                        e);
1116            }
1117
1118            if (verified) {
1119                if (pkg.mCertificates == null) {
1120                    pkg.mCertificates = allSignersCerts;
1121                    pkg.mSignatures = signatures;
1122                    pkg.mSigningKeys = new ArraySet<>(allSignersCerts.length);
1123                    for (int i = 0; i < allSignersCerts.length; i++) {
1124                        Certificate[] signerCerts = allSignersCerts[i];
1125                        Certificate signerCert = signerCerts[0];
1126                        pkg.mSigningKeys.add(signerCert.getPublicKey());
1127                    }
1128                } else {
1129                    if (!Signature.areExactMatch(pkg.mSignatures, signatures)) {
1130                        throw new PackageParserException(
1131                                INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
1132                                apkPath + " has mismatched certificates");
1133                    }
1134                }
1135                // Not yet done, because we need to confirm that AndroidManifest.xml exists and,
1136                // if requested, that classes.dex exists.
1137            }
1138        }
1139
1140        boolean codeFound = false;
1141        StrictJarFile jarFile = null;
1142        try {
1143            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
1144            jarFile = new StrictJarFile(
1145                    apkPath,
1146                    !verified // whether to verify JAR signature
1147                    );
1148            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1149
1150            // Always verify manifest, regardless of source
1151            final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
1152            if (manifestEntry == null) {
1153                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
1154                        "Package " + apkPath + " has no manifest");
1155            }
1156
1157            // Optimization: early termination when APK already verified
1158            if (verified) {
1159                if ((requireCode) && (jarFile.findEntry(BYTECODE_FILENAME) == null)) {
1160                    throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1161                            "Package " + apkPath + " code is missing");
1162                }
1163                return;
1164            }
1165
1166            // APK's integrity needs to be verified using JAR signature scheme.
1167            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "buildVerifyList");
1168            final List<ZipEntry> toVerify = new ArrayList<>();
1169            toVerify.add(manifestEntry);
1170
1171            // If we're parsing an untrusted package, verify all contents
1172            if ((parseFlags & PARSE_IS_SYSTEM) == 0) {
1173                final Iterator<ZipEntry> i = jarFile.iterator();
1174                while (i.hasNext()) {
1175                    final ZipEntry entry = i.next();
1176
1177                    if (entry.isDirectory()) continue;
1178
1179                    final String entryName = entry.getName();
1180                    if (entryName.startsWith("META-INF/")) continue;
1181                    if (entryName.equals(ANDROID_MANIFEST_FILENAME)) continue;
1182                    if (entryName.equals(BYTECODE_FILENAME)) {
1183                        codeFound = true;
1184                    }
1185
1186                    toVerify.add(entry);
1187                }
1188            }
1189            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1190
1191            if (!codeFound && requireCode) {
1192                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1193                        "Package " + apkPath + " code is missing");
1194            }
1195
1196            // Verify that entries are signed consistently with the first entry
1197            // we encountered. Note that for splits, certificates may have
1198            // already been populated during an earlier parse of a base APK.
1199            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyEntries");
1200            for (ZipEntry entry : toVerify) {
1201                final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
1202                if (ArrayUtils.isEmpty(entryCerts)) {
1203                    throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1204                            "Package " + apkPath + " has no certificates at entry "
1205                            + entry.getName());
1206                }
1207                final Signature[] entrySignatures = convertToSignatures(entryCerts);
1208
1209                if (pkg.mCertificates == null) {
1210                    pkg.mCertificates = entryCerts;
1211                    pkg.mSignatures = entrySignatures;
1212                    pkg.mSigningKeys = new ArraySet<PublicKey>();
1213                    for (int i=0; i < entryCerts.length; i++) {
1214                        pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
1215                    }
1216                } else {
1217                    if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {
1218                        throw new PackageParserException(
1219                                INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath
1220                                        + " has mismatched certificates at entry "
1221                                        + entry.getName());
1222                    }
1223                }
1224            }
1225            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1226        } catch (GeneralSecurityException e) {
1227            throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
1228                    "Failed to collect certificates from " + apkPath, e);
1229        } catch (IOException | RuntimeException e) {
1230            throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1231                    "Failed to collect certificates from " + apkPath, e);
1232        } finally {
1233            closeQuietly(jarFile);
1234        }
1235    }
1236
1237    private static Signature[] convertToSignatures(Certificate[][] certs)
1238            throws CertificateEncodingException {
1239        final Signature[] res = new Signature[certs.length];
1240        for (int i = 0; i < certs.length; i++) {
1241            res[i] = new Signature(certs[i]);
1242        }
1243        return res;
1244    }
1245
1246    /**
1247     * Utility method that retrieves lightweight details about a single APK
1248     * file, including package name, split name, and install location.
1249     *
1250     * @param apkFile path to a single APK
1251     * @param flags optional parse flags, such as
1252     *            {@link #PARSE_COLLECT_CERTIFICATES}
1253     */
1254    public static ApkLite parseApkLite(File apkFile, int flags)
1255            throws PackageParserException {
1256        final String apkPath = apkFile.getAbsolutePath();
1257
1258        AssetManager assets = null;
1259        XmlResourceParser parser = null;
1260        try {
1261            assets = new AssetManager();
1262            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1263                    Build.VERSION.RESOURCES_SDK_INT);
1264
1265            int cookie = assets.addAssetPath(apkPath);
1266            if (cookie == 0) {
1267                throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
1268                        "Failed to parse " + apkPath);
1269            }
1270
1271            final DisplayMetrics metrics = new DisplayMetrics();
1272            metrics.setToDefaults();
1273
1274            final Resources res = new Resources(assets, metrics, null);
1275            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
1276
1277            final Signature[] signatures;
1278            if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
1279                // TODO: factor signature related items out of Package object
1280                final Package tempPkg = new Package(null);
1281                collectCertificates(tempPkg, apkFile, 0 /*apkFlags*/, 0 /*flags*/);
1282                signatures = tempPkg.mSignatures;
1283            } else {
1284                signatures = null;
1285            }
1286
1287            final AttributeSet attrs = parser;
1288            return parseApkLite(apkPath, res, parser, attrs, flags, signatures);
1289
1290        } catch (XmlPullParserException | IOException | RuntimeException e) {
1291            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
1292                    "Failed to parse " + apkPath, e);
1293        } finally {
1294            IoUtils.closeQuietly(parser);
1295            IoUtils.closeQuietly(assets);
1296        }
1297    }
1298
1299    private static String validateName(String name, boolean requireSeparator,
1300            boolean requireFilename) {
1301        final int N = name.length();
1302        boolean hasSep = false;
1303        boolean front = true;
1304        for (int i=0; i<N; i++) {
1305            final char c = name.charAt(i);
1306            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
1307                front = false;
1308                continue;
1309            }
1310            if (!front) {
1311                if ((c >= '0' && c <= '9') || c == '_') {
1312                    continue;
1313                }
1314            }
1315            if (c == '.') {
1316                hasSep = true;
1317                front = true;
1318                continue;
1319            }
1320            return "bad character '" + c + "'";
1321        }
1322        if (requireFilename && !FileUtils.isValidExtFilename(name)) {
1323            return "Invalid filename";
1324        }
1325        return hasSep || !requireSeparator
1326                ? null : "must have at least one '.' separator";
1327    }
1328
1329    private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
1330            AttributeSet attrs) throws IOException, XmlPullParserException,
1331            PackageParserException {
1332
1333        int type;
1334        while ((type = parser.next()) != XmlPullParser.START_TAG
1335                && type != XmlPullParser.END_DOCUMENT) {
1336        }
1337
1338        if (type != XmlPullParser.START_TAG) {
1339            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1340                    "No start tag found");
1341        }
1342        if (!parser.getName().equals(TAG_MANIFEST)) {
1343            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1344                    "No <manifest> tag");
1345        }
1346
1347        final String packageName = attrs.getAttributeValue(null, "package");
1348        if (!"android".equals(packageName)) {
1349            final String error = validateName(packageName, true, true);
1350            if (error != null) {
1351                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
1352                        "Invalid manifest package: " + error);
1353            }
1354        }
1355
1356        String splitName = attrs.getAttributeValue(null, "split");
1357        if (splitName != null) {
1358            if (splitName.length() == 0) {
1359                splitName = null;
1360            } else {
1361                final String error = validateName(splitName, false, false);
1362                if (error != null) {
1363                    throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
1364                            "Invalid manifest split: " + error);
1365                }
1366            }
1367        }
1368
1369        return Pair.create(packageName.intern(),
1370                (splitName != null) ? splitName.intern() : splitName);
1371    }
1372
1373    private static ApkLite parseApkLite(String codePath, Resources res, XmlPullParser parser,
1374            AttributeSet attrs, int flags, Signature[] signatures) throws IOException,
1375            XmlPullParserException, PackageParserException {
1376        final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
1377
1378        int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
1379        int versionCode = 0;
1380        int revisionCode = 0;
1381        boolean coreApp = false;
1382        boolean multiArch = false;
1383        String abiOverride = null;
1384        boolean extractNativeLibs = true;
1385
1386        for (int i = 0; i < attrs.getAttributeCount(); i++) {
1387            final String attr = attrs.getAttributeName(i);
1388            if (attr.equals("installLocation")) {
1389                installLocation = attrs.getAttributeIntValue(i,
1390                        PARSE_DEFAULT_INSTALL_LOCATION);
1391            } else if (attr.equals("versionCode")) {
1392                versionCode = attrs.getAttributeIntValue(i, 0);
1393            } else if (attr.equals("revisionCode")) {
1394                revisionCode = attrs.getAttributeIntValue(i, 0);
1395            } else if (attr.equals("coreApp")) {
1396                coreApp = attrs.getAttributeBooleanValue(i, false);
1397            }
1398        }
1399
1400        // Only search the tree when the tag is directly below <manifest>
1401        int type;
1402        final int searchDepth = parser.getDepth() + 1;
1403
1404        final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
1405        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1406                && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {
1407            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1408                continue;
1409            }
1410
1411            if (parser.getDepth() == searchDepth && "package-verifier".equals(parser.getName())) {
1412                final VerifierInfo verifier = parseVerifier(res, parser, attrs, flags);
1413                if (verifier != null) {
1414                    verifiers.add(verifier);
1415                }
1416            }
1417
1418            if (parser.getDepth() == searchDepth && "application".equals(parser.getName())) {
1419                for (int i = 0; i < attrs.getAttributeCount(); ++i) {
1420                    final String attr = attrs.getAttributeName(i);
1421                    if ("multiArch".equals(attr)) {
1422                        multiArch = attrs.getAttributeBooleanValue(i, false);
1423                    }
1424                    if ("abiOverride".equals(attr)) {
1425                        abiOverride = attrs.getAttributeValue(i);
1426                    }
1427                    if ("extractNativeLibs".equals(attr)) {
1428                        extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
1429                    }
1430                }
1431            }
1432        }
1433
1434        return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
1435                revisionCode, installLocation, verifiers, signatures, coreApp, multiArch,
1436                abiOverride, extractNativeLibs);
1437    }
1438
1439    /**
1440     * Temporary.
1441     */
1442    static public Signature stringToSignature(String str) {
1443        final int N = str.length();
1444        byte[] sig = new byte[N];
1445        for (int i=0; i<N; i++) {
1446            sig[i] = (byte)str.charAt(i);
1447        }
1448        return new Signature(sig);
1449    }
1450
1451    /**
1452     * Parses a child package and adds it to the parent if successful. If you add
1453     * new tags that need to be supported by child packages make sure to add them
1454     * to {@link #CHILD_PACKAGE_TAGS}.
1455     *
1456     * @param parentPkg The parent that contains the child
1457     * @param res Resources against which to resolve values
1458     * @param parser Parser of the manifest
1459     * @param flags Flags about how to parse
1460     * @param outError Human readable error if parsing fails
1461     * @return True of parsing succeeded.
1462     *
1463     * @throws XmlPullParserException
1464     * @throws IOException
1465     */
1466    private boolean parseBaseApkChild(Package parentPkg, Resources res, XmlResourceParser parser,
1467            int flags, String[] outError) throws XmlPullParserException, IOException {
1468        // Let ppl not abuse this mechanism by limiting the packages per APK
1469        if (parentPkg.childPackages != null && parentPkg.childPackages.size() + 2
1470                > MAX_PACKAGES_PER_APK) {
1471            outError[0] = "Maximum number of packages per APK is: " + MAX_PACKAGES_PER_APK;
1472            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1473            return false;
1474        }
1475
1476        // Make sure we have a valid child package name
1477        String childPackageName = parser.getAttributeValue(null, "package");
1478        if (validateName(childPackageName, true, false) != null) {
1479            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1480            return false;
1481        }
1482
1483        // Child packages must be unique
1484        if (childPackageName.equals(parentPkg.packageName)) {
1485            String message = "Child package name cannot be equal to parent package name: "
1486                    + parentPkg.packageName;
1487            Slog.w(TAG, message);
1488            outError[0] = message;
1489            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1490            return false;
1491        }
1492
1493        // Child packages must be unique
1494        if (parentPkg.hasChildPackage(childPackageName)) {
1495            String message = "Duplicate child package:" + childPackageName;
1496            Slog.w(TAG, message);
1497            outError[0] = message;
1498            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1499            return false;
1500        }
1501
1502        // Go ahead and parse the child
1503        Package childPkg = new Package(childPackageName);
1504
1505        // Child package inherits parent version code/name/target SDK
1506        childPkg.mVersionCode = parentPkg.mVersionCode;
1507        childPkg.baseRevisionCode = parentPkg.baseRevisionCode;
1508        childPkg.mVersionName = parentPkg.mVersionName;
1509        childPkg.applicationInfo.targetSdkVersion = parentPkg.applicationInfo.targetSdkVersion;
1510
1511        childPkg = parseBaseApkCommon(childPkg, CHILD_PACKAGE_TAGS, res, parser, flags, outError);
1512        if (childPkg == null) {
1513            // If we got null then error was set during child parsing
1514            return false;
1515        }
1516
1517        // Set the parent-child relation
1518        if (parentPkg.childPackages == null) {
1519            parentPkg.childPackages = new ArrayList<>();
1520        }
1521        parentPkg.childPackages.add(childPkg);
1522        childPkg.parentPackage = parentPkg;
1523
1524        return true;
1525    }
1526
1527    /**
1528     * Parse the manifest of a <em>base APK</em>. When adding new features you
1529     * need to consider whether they should be supported by split APKs and child
1530     * packages.
1531     *
1532     * @param res The resources from which to resolve values
1533     * @param parser The manifest parser
1534     * @param flags Flags how to parse
1535     * @param outError Human readable error message
1536     * @return Parsed package or null on error.
1537     *
1538     * @throws XmlPullParserException
1539     * @throws IOException
1540     */
1541    private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
1542            String[] outError) throws XmlPullParserException, IOException {
1543        final String splitName;
1544        final String pkgName;
1545
1546        try {
1547            Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser);
1548            pkgName = packageSplit.first;
1549            splitName = packageSplit.second;
1550
1551            if (!TextUtils.isEmpty(splitName)) {
1552                outError[0] = "Expected base APK, but found split " + splitName;
1553                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1554                return null;
1555            }
1556        } catch (PackageParserException e) {
1557            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1558            return null;
1559        }
1560
1561        final Package pkg = new Package(pkgName);
1562
1563        TypedArray sa = res.obtainAttributes(parser,
1564                com.android.internal.R.styleable.AndroidManifest);
1565
1566        pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
1567                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
1568        pkg.baseRevisionCode = sa.getInteger(
1569                com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
1570        pkg.mVersionName = sa.getNonConfigurationString(
1571                com.android.internal.R.styleable.AndroidManifest_versionName, 0);
1572        if (pkg.mVersionName != null) {
1573            pkg.mVersionName = pkg.mVersionName.intern();
1574        }
1575
1576        pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
1577
1578        sa.recycle();
1579
1580        return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
1581    }
1582
1583    /**
1584     * This is the common parsing routing for handling parent and child
1585     * packages in a base APK. The difference between parent and child
1586     * parsing is that some targs are not supported by child packages as
1587     * well as some manifest attributes are ignored. The implementation
1588     * assumes the calling code already handled the manifest tag if needed
1589     * (this applies to the parent only).
1590     *
1591     * @param pkg The package which to populate
1592     * @param acceptedTags Which tags to handle, null to handle all
1593     * @param res Resources against which to resolve values
1594     * @param parser Parser of the manifest
1595     * @param flags Flags about how to parse
1596     * @param outError Human readable error if parsing fails
1597     * @return The package if parsing succeeded or null.
1598     *
1599     * @throws XmlPullParserException
1600     * @throws IOException
1601     */
1602    private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
1603            XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
1604            IOException {
1605        final boolean trustedOverlay = (flags & PARSE_TRUSTED_OVERLAY) != 0;
1606        mParseInstrumentationArgs = null;
1607        mParseActivityArgs = null;
1608        mParseServiceArgs = null;
1609        mParseProviderArgs = null;
1610
1611        int type;
1612        boolean foundApp = false;
1613
1614        TypedArray sa = res.obtainAttributes(parser,
1615                com.android.internal.R.styleable.AndroidManifest);
1616
1617        String str = sa.getNonConfigurationString(
1618                com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
1619        if (str != null && str.length() > 0) {
1620            String nameError = validateName(str, true, false);
1621            if (nameError != null && !"android".equals(pkg.packageName)) {
1622                outError[0] = "<manifest> specifies bad sharedUserId name \""
1623                    + str + "\": " + nameError;
1624                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
1625                return null;
1626            }
1627            pkg.mSharedUserId = str.intern();
1628            pkg.mSharedUserLabel = sa.getResourceId(
1629                    com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
1630        }
1631
1632        pkg.installLocation = sa.getInteger(
1633                com.android.internal.R.styleable.AndroidManifest_installLocation,
1634                PARSE_DEFAULT_INSTALL_LOCATION);
1635        pkg.applicationInfo.installLocation = pkg.installLocation;
1636
1637
1638        /* Set the global "forward lock" flag */
1639        if ((flags & PARSE_FORWARD_LOCK) != 0) {
1640            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
1641        }
1642
1643        /* Set the global "on SD card" flag */
1644        if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
1645            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
1646        }
1647
1648        if ((flags & PARSE_IS_EPHEMERAL) != 0) {
1649            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_EPHEMERAL;
1650        }
1651
1652        // Resource boolean are -1, so 1 means we don't know the value.
1653        int supportsSmallScreens = 1;
1654        int supportsNormalScreens = 1;
1655        int supportsLargeScreens = 1;
1656        int supportsXLargeScreens = 1;
1657        int resizeable = 1;
1658        int anyDensity = 1;
1659
1660        int outerDepth = parser.getDepth();
1661        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1662                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1663            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1664                continue;
1665            }
1666
1667            String tagName = parser.getName();
1668
1669            if (acceptedTags != null && !acceptedTags.contains(tagName)) {
1670                Slog.w(TAG, "Skipping unsupported element under <manifest>: "
1671                        + tagName + " at " + mArchiveSourcePath + " "
1672                        + parser.getPositionDescription());
1673                XmlUtils.skipCurrentTag(parser);
1674                continue;
1675            }
1676
1677            if (tagName.equals(TAG_APPLICATION)) {
1678                if (foundApp) {
1679                    if (RIGID_PARSER) {
1680                        outError[0] = "<manifest> has more than one <application>";
1681                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1682                        return null;
1683                    } else {
1684                        Slog.w(TAG, "<manifest> has more than one <application>");
1685                        XmlUtils.skipCurrentTag(parser);
1686                        continue;
1687                    }
1688                }
1689
1690                foundApp = true;
1691                if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
1692                    return null;
1693                }
1694            } else if (tagName.equals(TAG_OVERLAY)) {
1695                pkg.mTrustedOverlay = trustedOverlay;
1696
1697                sa = res.obtainAttributes(parser,
1698                        com.android.internal.R.styleable.AndroidManifestResourceOverlay);
1699                pkg.mOverlayTarget = sa.getString(
1700                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
1701                pkg.mOverlayPriority = sa.getInt(
1702                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
1703                        -1);
1704                sa.recycle();
1705
1706                if (pkg.mOverlayTarget == null) {
1707                    outError[0] = "<overlay> does not specify a target package";
1708                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1709                    return null;
1710                }
1711                if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
1712                    outError[0] = "<overlay> priority must be between 0 and 9999";
1713                    mParseError =
1714                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1715                    return null;
1716                }
1717                XmlUtils.skipCurrentTag(parser);
1718
1719            } else if (tagName.equals(TAG_KEY_SETS)) {
1720                if (!parseKeySets(pkg, res, parser, outError)) {
1721                    return null;
1722                }
1723            } else if (tagName.equals(TAG_PERMISSION_GROUP)) {
1724                if (parsePermissionGroup(pkg, flags, res, parser, outError) == null) {
1725                    return null;
1726                }
1727            } else if (tagName.equals(TAG_PERMISSION)) {
1728                if (parsePermission(pkg, res, parser, outError) == null) {
1729                    return null;
1730                }
1731            } else if (tagName.equals(TAG_PERMISSION_TREE)) {
1732                if (parsePermissionTree(pkg, res, parser, outError) == null) {
1733                    return null;
1734                }
1735            } else if (tagName.equals(TAG_USES_PERMISSION)) {
1736                if (!parseUsesPermission(pkg, res, parser)) {
1737                    return null;
1738                }
1739            } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)
1740                    || tagName.equals(TAG_USES_PERMISSION_SDK_23)) {
1741                if (!parseUsesPermission(pkg, res, parser)) {
1742                    return null;
1743                }
1744            } else if (tagName.equals(TAG_USES_CONFIGURATION)) {
1745                ConfigurationInfo cPref = new ConfigurationInfo();
1746                sa = res.obtainAttributes(parser,
1747                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration);
1748                cPref.reqTouchScreen = sa.getInt(
1749                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
1750                        Configuration.TOUCHSCREEN_UNDEFINED);
1751                cPref.reqKeyboardType = sa.getInt(
1752                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
1753                        Configuration.KEYBOARD_UNDEFINED);
1754                if (sa.getBoolean(
1755                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
1756                        false)) {
1757                    cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
1758                }
1759                cPref.reqNavigation = sa.getInt(
1760                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
1761                        Configuration.NAVIGATION_UNDEFINED);
1762                if (sa.getBoolean(
1763                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
1764                        false)) {
1765                    cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
1766                }
1767                sa.recycle();
1768                pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
1769
1770                XmlUtils.skipCurrentTag(parser);
1771
1772            } else if (tagName.equals(TAG_USES_FEATURE)) {
1773                FeatureInfo fi = parseUsesFeature(res, parser);
1774                pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi);
1775
1776                if (fi.name == null) {
1777                    ConfigurationInfo cPref = new ConfigurationInfo();
1778                    cPref.reqGlEsVersion = fi.reqGlEsVersion;
1779                    pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
1780                }
1781
1782                XmlUtils.skipCurrentTag(parser);
1783
1784            } else if (tagName.equals(TAG_FEATURE_GROUP)) {
1785                FeatureGroupInfo group = new FeatureGroupInfo();
1786                ArrayList<FeatureInfo> features = null;
1787                final int innerDepth = parser.getDepth();
1788                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1789                        && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
1790                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1791                        continue;
1792                    }
1793
1794                    final String innerTagName = parser.getName();
1795                    if (innerTagName.equals("uses-feature")) {
1796                        FeatureInfo featureInfo = parseUsesFeature(res, parser);
1797                        // FeatureGroups are stricter and mandate that
1798                        // any <uses-feature> declared are mandatory.
1799                        featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
1800                        features = ArrayUtils.add(features, featureInfo);
1801                    } else {
1802                        Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName +
1803                                " at " + mArchiveSourcePath + " " +
1804                                parser.getPositionDescription());
1805                    }
1806                    XmlUtils.skipCurrentTag(parser);
1807                }
1808
1809                if (features != null) {
1810                    group.features = new FeatureInfo[features.size()];
1811                    group.features = features.toArray(group.features);
1812                }
1813                pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group);
1814
1815            } else if (tagName.equals(TAG_USES_SDK)) {
1816                if (SDK_VERSION > 0) {
1817                    sa = res.obtainAttributes(parser,
1818                            com.android.internal.R.styleable.AndroidManifestUsesSdk);
1819
1820                    int minVers = 0;
1821                    String minCode = null;
1822                    int targetVers = 0;
1823                    String targetCode = null;
1824
1825                    TypedValue val = sa.peekValue(
1826                            com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
1827                    if (val != null) {
1828                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
1829                            targetCode = minCode = val.string.toString();
1830                        } else {
1831                            // If it's not a string, it's an integer.
1832                            targetVers = minVers = val.data;
1833                        }
1834                    }
1835
1836                    val = sa.peekValue(
1837                            com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
1838                    if (val != null) {
1839                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
1840                            targetCode = minCode = val.string.toString();
1841                        } else {
1842                            // If it's not a string, it's an integer.
1843                            targetVers = val.data;
1844                        }
1845                    }
1846
1847                    sa.recycle();
1848
1849                    if (minCode != null) {
1850                        boolean allowedCodename = false;
1851                        for (String codename : SDK_CODENAMES) {
1852                            if (minCode.equals(codename)) {
1853                                allowedCodename = true;
1854                                break;
1855                            }
1856                        }
1857                        if (!allowedCodename) {
1858                            if (SDK_CODENAMES.length > 0) {
1859                                outError[0] = "Requires development platform " + minCode
1860                                        + " (current platform is any of "
1861                                        + Arrays.toString(SDK_CODENAMES) + ")";
1862                            } else {
1863                                outError[0] = "Requires development platform " + minCode
1864                                        + " but this is a release platform.";
1865                            }
1866                            mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
1867                            return null;
1868                        }
1869                    } else if (minVers > SDK_VERSION) {
1870                        outError[0] = "Requires newer sdk version #" + minVers
1871                                + " (current version is #" + SDK_VERSION + ")";
1872                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
1873                        return null;
1874                    }
1875
1876                    if (targetCode != null) {
1877                        boolean allowedCodename = false;
1878                        for (String codename : SDK_CODENAMES) {
1879                            if (targetCode.equals(codename)) {
1880                                allowedCodename = true;
1881                                break;
1882                            }
1883                        }
1884                        if (!allowedCodename) {
1885                            if (SDK_CODENAMES.length > 0) {
1886                                outError[0] = "Requires development platform " + targetCode
1887                                        + " (current platform is any of "
1888                                        + Arrays.toString(SDK_CODENAMES) + ")";
1889                            } else {
1890                                outError[0] = "Requires development platform " + targetCode
1891                                        + " but this is a release platform.";
1892                            }
1893                            mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
1894                            return null;
1895                        }
1896                        // If the code matches, it definitely targets this SDK.
1897                        pkg.applicationInfo.targetSdkVersion
1898                                = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
1899                    } else {
1900                        pkg.applicationInfo.targetSdkVersion = targetVers;
1901                    }
1902                }
1903
1904                XmlUtils.skipCurrentTag(parser);
1905
1906            } else if (tagName.equals(TAG_SUPPORT_SCREENS)) {
1907                sa = res.obtainAttributes(parser,
1908                        com.android.internal.R.styleable.AndroidManifestSupportsScreens);
1909
1910                pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger(
1911                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp,
1912                        0);
1913                pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger(
1914                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp,
1915                        0);
1916                pkg.applicationInfo.largestWidthLimitDp = sa.getInteger(
1917                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp,
1918                        0);
1919
1920                // This is a trick to get a boolean and still able to detect
1921                // if a value was actually set.
1922                supportsSmallScreens = sa.getInteger(
1923                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens,
1924                        supportsSmallScreens);
1925                supportsNormalScreens = sa.getInteger(
1926                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens,
1927                        supportsNormalScreens);
1928                supportsLargeScreens = sa.getInteger(
1929                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens,
1930                        supportsLargeScreens);
1931                supportsXLargeScreens = sa.getInteger(
1932                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens,
1933                        supportsXLargeScreens);
1934                resizeable = sa.getInteger(
1935                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable,
1936                        resizeable);
1937                anyDensity = sa.getInteger(
1938                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity,
1939                        anyDensity);
1940
1941                sa.recycle();
1942
1943                XmlUtils.skipCurrentTag(parser);
1944
1945            } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) {
1946                sa = res.obtainAttributes(parser,
1947                        com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
1948
1949                // Note: don't allow this value to be a reference to a resource
1950                // that may change.
1951                String name = sa.getNonResourceString(
1952                        com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name);
1953
1954                sa.recycle();
1955
1956                if (name != null && (flags&PARSE_IS_SYSTEM) != 0) {
1957                    if (pkg.protectedBroadcasts == null) {
1958                        pkg.protectedBroadcasts = new ArrayList<String>();
1959                    }
1960                    if (!pkg.protectedBroadcasts.contains(name)) {
1961                        pkg.protectedBroadcasts.add(name.intern());
1962                    }
1963                }
1964
1965                XmlUtils.skipCurrentTag(parser);
1966
1967            } else if (tagName.equals(TAG_INSTRUMENTATION)) {
1968                if (parseInstrumentation(pkg, res, parser, outError) == null) {
1969                    return null;
1970                }
1971            } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) {
1972                sa = res.obtainAttributes(parser,
1973                        com.android.internal.R.styleable.AndroidManifestOriginalPackage);
1974
1975                String orig =sa.getNonConfigurationString(
1976                        com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
1977                if (!pkg.packageName.equals(orig)) {
1978                    if (pkg.mOriginalPackages == null) {
1979                        pkg.mOriginalPackages = new ArrayList<String>();
1980                        pkg.mRealPackage = pkg.packageName;
1981                    }
1982                    pkg.mOriginalPackages.add(orig);
1983                }
1984
1985                sa.recycle();
1986
1987                XmlUtils.skipCurrentTag(parser);
1988
1989            } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) {
1990                sa = res.obtainAttributes(parser,
1991                        com.android.internal.R.styleable.AndroidManifestOriginalPackage);
1992
1993                String name = sa.getNonConfigurationString(
1994                        com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
1995
1996                sa.recycle();
1997
1998                if (name != null) {
1999                    if (pkg.mAdoptPermissions == null) {
2000                        pkg.mAdoptPermissions = new ArrayList<String>();
2001                    }
2002                    pkg.mAdoptPermissions.add(name);
2003                }
2004
2005                XmlUtils.skipCurrentTag(parser);
2006
2007            } else if (tagName.equals(TAG_USES_GL_TEXTURE)) {
2008                // Just skip this tag
2009                XmlUtils.skipCurrentTag(parser);
2010                continue;
2011
2012            } else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) {
2013                // Just skip this tag
2014                XmlUtils.skipCurrentTag(parser);
2015                continue;
2016            } else if (tagName.equals(TAG_SUPPORTS_INPUT)) {//
2017                XmlUtils.skipCurrentTag(parser);
2018                continue;
2019
2020            } else if (tagName.equals(TAG_EAT_COMMENT)) {
2021                // Just skip this tag
2022                XmlUtils.skipCurrentTag(parser);
2023                continue;
2024
2025            } else if (tagName.equals(TAG_PACKAGE)) {
2026                if (!parseBaseApkChild(pkg, res, parser, flags, outError)) {
2027                    // If parsing a child failed the error is already set
2028                    return null;
2029                }
2030            } else if (RIGID_PARSER) {
2031                outError[0] = "Bad element under <manifest>: "
2032                    + parser.getName();
2033                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2034                return null;
2035
2036            } else {
2037                Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
2038                        + " at " + mArchiveSourcePath + " "
2039                        + parser.getPositionDescription());
2040                XmlUtils.skipCurrentTag(parser);
2041                continue;
2042            }
2043        }
2044
2045        if (!foundApp && pkg.instrumentation.size() == 0) {
2046            outError[0] = "<manifest> does not contain an <application> or <instrumentation>";
2047            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
2048        }
2049
2050        final int NP = PackageParser.NEW_PERMISSIONS.length;
2051        StringBuilder implicitPerms = null;
2052        for (int ip=0; ip<NP; ip++) {
2053            final PackageParser.NewPermissionInfo npi
2054                    = PackageParser.NEW_PERMISSIONS[ip];
2055            if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
2056                break;
2057            }
2058            if (!pkg.requestedPermissions.contains(npi.name)) {
2059                if (implicitPerms == null) {
2060                    implicitPerms = new StringBuilder(128);
2061                    implicitPerms.append(pkg.packageName);
2062                    implicitPerms.append(": compat added ");
2063                } else {
2064                    implicitPerms.append(' ');
2065                }
2066                implicitPerms.append(npi.name);
2067                pkg.requestedPermissions.add(npi.name);
2068            }
2069        }
2070        if (implicitPerms != null) {
2071            Slog.i(TAG, implicitPerms.toString());
2072        }
2073
2074        final int NS = PackageParser.SPLIT_PERMISSIONS.length;
2075        for (int is=0; is<NS; is++) {
2076            final PackageParser.SplitPermissionInfo spi
2077                    = PackageParser.SPLIT_PERMISSIONS[is];
2078            if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
2079                    || !pkg.requestedPermissions.contains(spi.rootPerm)) {
2080                continue;
2081            }
2082            for (int in=0; in<spi.newPerms.length; in++) {
2083                final String perm = spi.newPerms[in];
2084                if (!pkg.requestedPermissions.contains(perm)) {
2085                    pkg.requestedPermissions.add(perm);
2086                }
2087            }
2088        }
2089
2090        if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
2091                && pkg.applicationInfo.targetSdkVersion
2092                        >= android.os.Build.VERSION_CODES.DONUT)) {
2093            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
2094        }
2095        if (supportsNormalScreens != 0) {
2096            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
2097        }
2098        if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
2099                && pkg.applicationInfo.targetSdkVersion
2100                        >= android.os.Build.VERSION_CODES.DONUT)) {
2101            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
2102        }
2103        if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
2104                && pkg.applicationInfo.targetSdkVersion
2105                        >= android.os.Build.VERSION_CODES.GINGERBREAD)) {
2106            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
2107        }
2108        if (resizeable < 0 || (resizeable > 0
2109                && pkg.applicationInfo.targetSdkVersion
2110                        >= android.os.Build.VERSION_CODES.DONUT)) {
2111            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
2112        }
2113        if (anyDensity < 0 || (anyDensity > 0
2114                && pkg.applicationInfo.targetSdkVersion
2115                        >= android.os.Build.VERSION_CODES.DONUT)) {
2116            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
2117        }
2118
2119        return pkg;
2120    }
2121
2122    private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs) {
2123        FeatureInfo fi = new FeatureInfo();
2124        TypedArray sa = res.obtainAttributes(attrs,
2125                com.android.internal.R.styleable.AndroidManifestUsesFeature);
2126        // Note: don't allow this value to be a reference to a resource
2127        // that may change.
2128        fi.name = sa.getNonResourceString(
2129                com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
2130        if (fi.name == null) {
2131            fi.reqGlEsVersion = sa.getInt(
2132                        com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
2133                        FeatureInfo.GL_ES_VERSION_UNDEFINED);
2134        }
2135        if (sa.getBoolean(
2136                com.android.internal.R.styleable.AndroidManifestUsesFeature_required, true)) {
2137            fi.flags |= FeatureInfo.FLAG_REQUIRED;
2138        }
2139        sa.recycle();
2140        return fi;
2141    }
2142
2143    private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser)
2144            throws XmlPullParserException, IOException {
2145        TypedArray sa = res.obtainAttributes(parser,
2146                com.android.internal.R.styleable.AndroidManifestUsesPermission);
2147
2148        // Note: don't allow this value to be a reference to a resource
2149        // that may change.
2150        String name = sa.getNonResourceString(
2151                com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
2152
2153        int maxSdkVersion = 0;
2154        TypedValue val = sa.peekValue(
2155                com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
2156        if (val != null) {
2157            if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
2158                maxSdkVersion = val.data;
2159            }
2160        }
2161
2162        sa.recycle();
2163
2164        if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
2165            if (name != null) {
2166                int index = pkg.requestedPermissions.indexOf(name);
2167                if (index == -1) {
2168                    pkg.requestedPermissions.add(name.intern());
2169                } else {
2170                    Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
2171                            + name + " in package: " + pkg.packageName + " at: "
2172                            + parser.getPositionDescription());
2173                }
2174            }
2175        }
2176
2177        XmlUtils.skipCurrentTag(parser);
2178        return true;
2179    }
2180
2181    private static String buildClassName(String pkg, CharSequence clsSeq,
2182            String[] outError) {
2183        if (clsSeq == null || clsSeq.length() <= 0) {
2184            outError[0] = "Empty class name in package " + pkg;
2185            return null;
2186        }
2187        String cls = clsSeq.toString();
2188        char c = cls.charAt(0);
2189        if (c == '.') {
2190            return (pkg + cls).intern();
2191        }
2192        if (cls.indexOf('.') < 0) {
2193            StringBuilder b = new StringBuilder(pkg);
2194            b.append('.');
2195            b.append(cls);
2196            return b.toString().intern();
2197        }
2198        if (c >= 'a' && c <= 'z') {
2199            return cls.intern();
2200        }
2201        outError[0] = "Bad class name " + cls + " in package " + pkg;
2202        return null;
2203    }
2204
2205    private static String buildCompoundName(String pkg,
2206            CharSequence procSeq, String type, String[] outError) {
2207        String proc = procSeq.toString();
2208        char c = proc.charAt(0);
2209        if (pkg != null && c == ':') {
2210            if (proc.length() < 2) {
2211                outError[0] = "Bad " + type + " name " + proc + " in package " + pkg
2212                        + ": must be at least two characters";
2213                return null;
2214            }
2215            String subName = proc.substring(1);
2216            String nameError = validateName(subName, false, false);
2217            if (nameError != null) {
2218                outError[0] = "Invalid " + type + " name " + proc + " in package "
2219                        + pkg + ": " + nameError;
2220                return null;
2221            }
2222            return (pkg + proc).intern();
2223        }
2224        String nameError = validateName(proc, true, false);
2225        if (nameError != null && !"system".equals(proc)) {
2226            outError[0] = "Invalid " + type + " name " + proc + " in package "
2227                    + pkg + ": " + nameError;
2228            return null;
2229        }
2230        return proc.intern();
2231    }
2232
2233    private static String buildProcessName(String pkg, String defProc,
2234            CharSequence procSeq, int flags, String[] separateProcesses,
2235            String[] outError) {
2236        if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
2237            return defProc != null ? defProc : pkg;
2238        }
2239        if (separateProcesses != null) {
2240            for (int i=separateProcesses.length-1; i>=0; i--) {
2241                String sp = separateProcesses[i];
2242                if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) {
2243                    return pkg;
2244                }
2245            }
2246        }
2247        if (procSeq == null || procSeq.length() <= 0) {
2248            return defProc;
2249        }
2250        return buildCompoundName(pkg, procSeq, "process", outError);
2251    }
2252
2253    private static String buildTaskAffinityName(String pkg, String defProc,
2254            CharSequence procSeq, String[] outError) {
2255        if (procSeq == null) {
2256            return defProc;
2257        }
2258        if (procSeq.length() <= 0) {
2259            return null;
2260        }
2261        return buildCompoundName(pkg, procSeq, "taskAffinity", outError);
2262    }
2263
2264    private boolean parseKeySets(Package owner, Resources res,
2265            XmlResourceParser parser, String[] outError)
2266            throws XmlPullParserException, IOException {
2267        // we've encountered the 'key-sets' tag
2268        // all the keys and keysets that we want must be defined here
2269        // so we're going to iterate over the parser and pull out the things we want
2270        int outerDepth = parser.getDepth();
2271        int currentKeySetDepth = -1;
2272        int type;
2273        String currentKeySet = null;
2274        ArrayMap<String, PublicKey> publicKeys = new ArrayMap<String, PublicKey>();
2275        ArraySet<String> upgradeKeySets = new ArraySet<String>();
2276        ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<String, ArraySet<String>>();
2277        ArraySet<String> improperKeySets = new ArraySet<String>();
2278        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2279                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2280            if (type == XmlPullParser.END_TAG) {
2281                if (parser.getDepth() == currentKeySetDepth) {
2282                    currentKeySet = null;
2283                    currentKeySetDepth = -1;
2284                }
2285                continue;
2286            }
2287            String tagName = parser.getName();
2288            if (tagName.equals("key-set")) {
2289                if (currentKeySet != null) {
2290                    outError[0] = "Improperly nested 'key-set' tag at "
2291                            + parser.getPositionDescription();
2292                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2293                    return false;
2294                }
2295                final TypedArray sa = res.obtainAttributes(parser,
2296                        com.android.internal.R.styleable.AndroidManifestKeySet);
2297                final String keysetName = sa.getNonResourceString(
2298                    com.android.internal.R.styleable.AndroidManifestKeySet_name);
2299                definedKeySets.put(keysetName, new ArraySet<String>());
2300                currentKeySet = keysetName;
2301                currentKeySetDepth = parser.getDepth();
2302                sa.recycle();
2303            } else if (tagName.equals("public-key")) {
2304                if (currentKeySet == null) {
2305                    outError[0] = "Improperly nested 'key-set' tag at "
2306                            + parser.getPositionDescription();
2307                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2308                    return false;
2309                }
2310                final TypedArray sa = res.obtainAttributes(parser,
2311                        com.android.internal.R.styleable.AndroidManifestPublicKey);
2312                final String publicKeyName = sa.getNonResourceString(
2313                        com.android.internal.R.styleable.AndroidManifestPublicKey_name);
2314                final String encodedKey = sa.getNonResourceString(
2315                            com.android.internal.R.styleable.AndroidManifestPublicKey_value);
2316                if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
2317                    outError[0] = "'public-key' " + publicKeyName + " must define a public-key value"
2318                            + " on first use at " + parser.getPositionDescription();
2319                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2320                    sa.recycle();
2321                    return false;
2322                } else if (encodedKey != null) {
2323                    PublicKey currentKey = parsePublicKey(encodedKey);
2324                    if (currentKey == null) {
2325                        Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
2326                                + parser.getPositionDescription() + " key-set " + currentKeySet
2327                                + " will not be added to the package's defined key-sets.");
2328                        sa.recycle();
2329                        improperKeySets.add(currentKeySet);
2330                        XmlUtils.skipCurrentTag(parser);
2331                        continue;
2332                    }
2333                    if (publicKeys.get(publicKeyName) == null
2334                            || publicKeys.get(publicKeyName).equals(currentKey)) {
2335
2336                        /* public-key first definition, or matches old definition */
2337                        publicKeys.put(publicKeyName, currentKey);
2338                    } else {
2339                        outError[0] = "Value of 'public-key' " + publicKeyName
2340                               + " conflicts with previously defined value at "
2341                               + parser.getPositionDescription();
2342                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2343                        sa.recycle();
2344                        return false;
2345                    }
2346                }
2347                definedKeySets.get(currentKeySet).add(publicKeyName);
2348                sa.recycle();
2349                XmlUtils.skipCurrentTag(parser);
2350            } else if (tagName.equals("upgrade-key-set")) {
2351                final TypedArray sa = res.obtainAttributes(parser,
2352                        com.android.internal.R.styleable.AndroidManifestUpgradeKeySet);
2353                String name = sa.getNonResourceString(
2354                        com.android.internal.R.styleable.AndroidManifestUpgradeKeySet_name);
2355                upgradeKeySets.add(name);
2356                sa.recycle();
2357                XmlUtils.skipCurrentTag(parser);
2358            } else if (RIGID_PARSER) {
2359                outError[0] = "Bad element under <key-sets>: " + parser.getName()
2360                        + " at " + mArchiveSourcePath + " "
2361                        + parser.getPositionDescription();
2362                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2363                return false;
2364            } else {
2365                Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName()
2366                        + " at " + mArchiveSourcePath + " "
2367                        + parser.getPositionDescription());
2368                XmlUtils.skipCurrentTag(parser);
2369                continue;
2370            }
2371        }
2372        Set<String> publicKeyNames = publicKeys.keySet();
2373        if (publicKeyNames.removeAll(definedKeySets.keySet())) {
2374            outError[0] = "Package" + owner.packageName + " AndroidManifext.xml "
2375                    + "'key-set' and 'public-key' names must be distinct.";
2376            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2377            return false;
2378        }
2379        owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>();
2380        for (ArrayMap.Entry<String, ArraySet<String>> e: definedKeySets.entrySet()) {
2381            final String keySetName = e.getKey();
2382            if (e.getValue().size() == 0) {
2383                Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
2384                        + "'key-set' " + keySetName + " has no valid associated 'public-key'."
2385                        + " Not including in package's defined key-sets.");
2386                continue;
2387            } else if (improperKeySets.contains(keySetName)) {
2388                Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
2389                        + "'key-set' " + keySetName + " contained improper 'public-key'"
2390                        + " tags. Not including in package's defined key-sets.");
2391                continue;
2392            }
2393            owner.mKeySetMapping.put(keySetName, new ArraySet<PublicKey>());
2394            for (String s : e.getValue()) {
2395                owner.mKeySetMapping.get(keySetName).add(publicKeys.get(s));
2396            }
2397        }
2398        if (owner.mKeySetMapping.keySet().containsAll(upgradeKeySets)) {
2399            owner.mUpgradeKeySets = upgradeKeySets;
2400        } else {
2401            outError[0] ="Package" + owner.packageName + " AndroidManifext.xml "
2402                   + "does not define all 'upgrade-key-set's .";
2403            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2404            return false;
2405        }
2406        return true;
2407    }
2408
2409    private PermissionGroup parsePermissionGroup(Package owner, int flags, Resources res,
2410            XmlResourceParser parser, String[] outError)
2411            throws XmlPullParserException, IOException {
2412        PermissionGroup perm = new PermissionGroup(owner);
2413
2414        TypedArray sa = res.obtainAttributes(parser,
2415                com.android.internal.R.styleable.AndroidManifestPermissionGroup);
2416
2417        if (!parsePackageItemInfo(owner, perm.info, outError,
2418                "<permission-group>", sa,
2419                com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
2420                com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
2421                com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
2422                com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
2423                com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
2424            sa.recycle();
2425            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2426            return null;
2427        }
2428
2429        perm.info.descriptionRes = sa.getResourceId(
2430                com.android.internal.R.styleable.AndroidManifestPermissionGroup_description,
2431                0);
2432        perm.info.flags = sa.getInt(
2433                com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0);
2434        perm.info.priority = sa.getInt(
2435                com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0);
2436        if (perm.info.priority > 0 && (flags&PARSE_IS_SYSTEM) == 0) {
2437            perm.info.priority = 0;
2438        }
2439
2440        sa.recycle();
2441
2442        if (!parseAllMetaData(res, parser, "<permission-group>", perm,
2443                outError)) {
2444            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2445            return null;
2446        }
2447
2448        owner.permissionGroups.add(perm);
2449
2450        return perm;
2451    }
2452
2453    private Permission parsePermission(Package owner, Resources res,
2454            XmlResourceParser parser, String[] outError)
2455        throws XmlPullParserException, IOException {
2456        Permission perm = new Permission(owner);
2457
2458        TypedArray sa = res.obtainAttributes(parser,
2459                com.android.internal.R.styleable.AndroidManifestPermission);
2460
2461        if (!parsePackageItemInfo(owner, perm.info, outError,
2462                "<permission>", sa,
2463                com.android.internal.R.styleable.AndroidManifestPermission_name,
2464                com.android.internal.R.styleable.AndroidManifestPermission_label,
2465                com.android.internal.R.styleable.AndroidManifestPermission_icon,
2466                com.android.internal.R.styleable.AndroidManifestPermission_logo,
2467                com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
2468            sa.recycle();
2469            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2470            return null;
2471        }
2472
2473        // Note: don't allow this value to be a reference to a resource
2474        // that may change.
2475        perm.info.group = sa.getNonResourceString(
2476                com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup);
2477        if (perm.info.group != null) {
2478            perm.info.group = perm.info.group.intern();
2479        }
2480
2481        perm.info.descriptionRes = sa.getResourceId(
2482                com.android.internal.R.styleable.AndroidManifestPermission_description,
2483                0);
2484
2485        perm.info.protectionLevel = sa.getInt(
2486                com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel,
2487                PermissionInfo.PROTECTION_NORMAL);
2488
2489        perm.info.flags = sa.getInt(
2490                com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0);
2491
2492        sa.recycle();
2493
2494        if (perm.info.protectionLevel == -1) {
2495            outError[0] = "<permission> does not specify protectionLevel";
2496            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2497            return null;
2498        }
2499
2500        perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
2501
2502        if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) {
2503            if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=
2504                    PermissionInfo.PROTECTION_SIGNATURE) {
2505                outError[0] = "<permission>  protectionLevel specifies a flag but is "
2506                        + "not based on signature type";
2507                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2508                return null;
2509            }
2510        }
2511
2512        if (!parseAllMetaData(res, parser, "<permission>", perm, outError)) {
2513            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2514            return null;
2515        }
2516
2517        owner.permissions.add(perm);
2518
2519        return perm;
2520    }
2521
2522    private Permission parsePermissionTree(Package owner, Resources res,
2523            XmlResourceParser parser, String[] outError)
2524        throws XmlPullParserException, IOException {
2525        Permission perm = new Permission(owner);
2526
2527        TypedArray sa = res.obtainAttributes(parser,
2528                com.android.internal.R.styleable.AndroidManifestPermissionTree);
2529
2530        if (!parsePackageItemInfo(owner, perm.info, outError,
2531                "<permission-tree>", sa,
2532                com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
2533                com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
2534                com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
2535                com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,
2536                com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
2537            sa.recycle();
2538            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2539            return null;
2540        }
2541
2542        sa.recycle();
2543
2544        int index = perm.info.name.indexOf('.');
2545        if (index > 0) {
2546            index = perm.info.name.indexOf('.', index+1);
2547        }
2548        if (index < 0) {
2549            outError[0] = "<permission-tree> name has less than three segments: "
2550                + perm.info.name;
2551            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2552            return null;
2553        }
2554
2555        perm.info.descriptionRes = 0;
2556        perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
2557        perm.tree = true;
2558
2559        if (!parseAllMetaData(res, parser, "<permission-tree>", perm,
2560                outError)) {
2561            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2562            return null;
2563        }
2564
2565        owner.permissions.add(perm);
2566
2567        return perm;
2568    }
2569
2570    private Instrumentation parseInstrumentation(Package owner, Resources res,
2571            XmlResourceParser parser, String[] outError)
2572            throws XmlPullParserException, IOException {
2573        TypedArray sa = res.obtainAttributes(parser,
2574                com.android.internal.R.styleable.AndroidManifestInstrumentation);
2575
2576        if (mParseInstrumentationArgs == null) {
2577            mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError,
2578                    com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
2579                    com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
2580                    com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
2581                    com.android.internal.R.styleable.AndroidManifestInstrumentation_logo,
2582                    com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
2583            mParseInstrumentationArgs.tag = "<instrumentation>";
2584        }
2585
2586        mParseInstrumentationArgs.sa = sa;
2587
2588        Instrumentation a = new Instrumentation(mParseInstrumentationArgs,
2589                new InstrumentationInfo());
2590        if (outError[0] != null) {
2591            sa.recycle();
2592            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2593            return null;
2594        }
2595
2596        String str;
2597        // Note: don't allow this value to be a reference to a resource
2598        // that may change.
2599        str = sa.getNonResourceString(
2600                com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage);
2601        a.info.targetPackage = str != null ? str.intern() : null;
2602
2603        a.info.handleProfiling = sa.getBoolean(
2604                com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling,
2605                false);
2606
2607        a.info.functionalTest = sa.getBoolean(
2608                com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest,
2609                false);
2610
2611        sa.recycle();
2612
2613        if (a.info.targetPackage == null) {
2614            outError[0] = "<instrumentation> does not specify targetPackage";
2615            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2616            return null;
2617        }
2618
2619        if (!parseAllMetaData(res, parser, "<instrumentation>", a,
2620                outError)) {
2621            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2622            return null;
2623        }
2624
2625        owner.instrumentation.add(a);
2626
2627        return a;
2628    }
2629
2630    /**
2631     * Parse the {@code application} XML tree at the current parse location in a
2632     * <em>base APK</em> manifest.
2633     * <p>
2634     * When adding new features, carefully consider if they should also be
2635     * supported by split APKs.
2636     */
2637    private boolean parseBaseApplication(Package owner, Resources res,
2638            XmlResourceParser parser, int flags, String[] outError)
2639        throws XmlPullParserException, IOException {
2640        final ApplicationInfo ai = owner.applicationInfo;
2641        final String pkgName = owner.applicationInfo.packageName;
2642
2643        TypedArray sa = res.obtainAttributes(parser,
2644                com.android.internal.R.styleable.AndroidManifestApplication);
2645
2646        String name = sa.getNonConfigurationString(
2647                com.android.internal.R.styleable.AndroidManifestApplication_name, 0);
2648        if (name != null) {
2649            ai.className = buildClassName(pkgName, name, outError);
2650            if (ai.className == null) {
2651                sa.recycle();
2652                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2653                return false;
2654            }
2655        }
2656
2657        String manageSpaceActivity = sa.getNonConfigurationString(
2658                com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
2659                Configuration.NATIVE_CONFIG_VERSION);
2660        if (manageSpaceActivity != null) {
2661            ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
2662                    outError);
2663        }
2664
2665        boolean allowBackup = sa.getBoolean(
2666                com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
2667        if (allowBackup) {
2668            ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
2669
2670            // backupAgent, killAfterRestore, fullBackupContent and restoreAnyVersion are only
2671            // relevant if backup is possible for the given application.
2672            String backupAgent = sa.getNonConfigurationString(
2673                    com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
2674                    Configuration.NATIVE_CONFIG_VERSION);
2675            if (backupAgent != null) {
2676                ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
2677                if (DEBUG_BACKUP) {
2678                    Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName
2679                            + " from " + pkgName + "+" + backupAgent);
2680                }
2681
2682                if (sa.getBoolean(
2683                        com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore,
2684                        true)) {
2685                    ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
2686                }
2687                if (sa.getBoolean(
2688                        com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion,
2689                        false)) {
2690                    ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
2691                }
2692                if (sa.getBoolean(
2693                        com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly,
2694                        false)) {
2695                    ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
2696                }
2697            }
2698
2699            TypedValue v = sa.peekValue(
2700                    com.android.internal.R.styleable.AndroidManifestApplication_fullBackupContent);
2701            if (v != null && (ai.fullBackupContent = v.resourceId) == 0) {
2702                if (DEBUG_BACKUP) {
2703                    Slog.v(TAG, "fullBackupContent specified as boolean=" +
2704                            (v.data == 0 ? "false" : "true"));
2705                }
2706                // "false" => -1, "true" => 0
2707                ai.fullBackupContent = (v.data == 0 ? -1 : 0);
2708            }
2709            if (DEBUG_BACKUP) {
2710                Slog.v(TAG, "fullBackupContent=" + ai.fullBackupContent + " for " + pkgName);
2711            }
2712        }
2713
2714        TypedValue v = sa.peekValue(
2715                com.android.internal.R.styleable.AndroidManifestApplication_label);
2716        if (v != null && (ai.labelRes=v.resourceId) == 0) {
2717            ai.nonLocalizedLabel = v.coerceToString();
2718        }
2719
2720        ai.icon = sa.getResourceId(
2721                com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
2722        ai.logo = sa.getResourceId(
2723                com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
2724        ai.banner = sa.getResourceId(
2725                com.android.internal.R.styleable.AndroidManifestApplication_banner, 0);
2726        ai.theme = sa.getResourceId(
2727                com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
2728        ai.descriptionRes = sa.getResourceId(
2729                com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
2730
2731        if ((flags&PARSE_IS_SYSTEM) != 0) {
2732            if (sa.getBoolean(
2733                    com.android.internal.R.styleable.AndroidManifestApplication_persistent,
2734                    false)) {
2735                ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
2736            }
2737        }
2738
2739        if (sa.getBoolean(
2740                com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers,
2741                false)) {
2742            owner.mRequiredForAllUsers = true;
2743        }
2744
2745        String restrictedAccountType = sa.getString(com.android.internal.R.styleable
2746                .AndroidManifestApplication_restrictedAccountType);
2747        if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
2748            owner.mRestrictedAccountType = restrictedAccountType;
2749        }
2750
2751        String requiredAccountType = sa.getString(com.android.internal.R.styleable
2752                .AndroidManifestApplication_requiredAccountType);
2753        if (requiredAccountType != null && requiredAccountType.length() > 0) {
2754            owner.mRequiredAccountType = requiredAccountType;
2755        }
2756
2757        if (sa.getBoolean(
2758                com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
2759                false)) {
2760            ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
2761        }
2762
2763        if (sa.getBoolean(
2764                com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode,
2765                false)) {
2766            ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE;
2767        }
2768
2769        owner.baseHardwareAccelerated = sa.getBoolean(
2770                com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
2771                owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
2772        if (owner.baseHardwareAccelerated) {
2773            ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
2774        }
2775
2776        if (sa.getBoolean(
2777                com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
2778                true)) {
2779            ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
2780        }
2781
2782        if (sa.getBoolean(
2783                com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
2784                false)) {
2785            ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
2786        }
2787
2788        if (sa.getBoolean(
2789                com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
2790                true)) {
2791            ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
2792        }
2793
2794        // The parent package controls installation, hence specify test only installs.
2795        if (owner.parentPackage == null) {
2796            if (sa.getBoolean(
2797                    com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
2798                    false)) {
2799                ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
2800            }
2801        }
2802
2803        if (sa.getBoolean(
2804                com.android.internal.R.styleable.AndroidManifestApplication_largeHeap,
2805                false)) {
2806            ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP;
2807        }
2808
2809        if (sa.getBoolean(
2810                com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic,
2811                true)) {
2812            ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
2813        }
2814
2815        if (sa.getBoolean(
2816                com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl,
2817                false /* default is no RTL support*/)) {
2818            ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
2819        }
2820
2821        if (sa.getBoolean(
2822                com.android.internal.R.styleable.AndroidManifestApplication_multiArch,
2823                false)) {
2824            ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
2825        }
2826
2827        if (sa.getBoolean(
2828                com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
2829                true)) {
2830            ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
2831        }
2832
2833        if (sa.getBoolean(R.styleable.AndroidManifestApplication_forceDeviceEncrypted, false)
2834                && (flags & PARSE_IS_SYSTEM) != 0) {
2835            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED;
2836        }
2837        if (sa.getBoolean(R.styleable.AndroidManifestApplication_encryptionAware, false)
2838                && (flags & PARSE_IS_SYSTEM) != 0) {
2839            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ENCRYPTION_AWARE;
2840        }
2841
2842        if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity,
2843                owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N)) {
2844            ai.privateFlags |= PRIVATE_FLAG_RESIZEABLE_ACTIVITIES;
2845        }
2846
2847        String str;
2848        str = sa.getNonConfigurationString(
2849                com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
2850        ai.permission = (str != null && str.length() > 0) ? str.intern() : null;
2851
2852        if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
2853            str = sa.getNonConfigurationString(
2854                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity,
2855                    Configuration.NATIVE_CONFIG_VERSION);
2856        } else {
2857            // Some older apps have been seen to use a resource reference
2858            // here that on older builds was ignored (with a warning).  We
2859            // need to continue to do this for them so they don't break.
2860            str = sa.getNonResourceString(
2861                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
2862        }
2863        ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
2864                str, outError);
2865
2866        if (outError[0] == null) {
2867            CharSequence pname;
2868            if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
2869                pname = sa.getNonConfigurationString(
2870                        com.android.internal.R.styleable.AndroidManifestApplication_process,
2871                        Configuration.NATIVE_CONFIG_VERSION);
2872            } else {
2873                // Some older apps have been seen to use a resource reference
2874                // here that on older builds was ignored (with a warning).  We
2875                // need to continue to do this for them so they don't break.
2876                pname = sa.getNonResourceString(
2877                        com.android.internal.R.styleable.AndroidManifestApplication_process);
2878            }
2879            ai.processName = buildProcessName(ai.packageName, null, pname,
2880                    flags, mSeparateProcesses, outError);
2881
2882            ai.enabled = sa.getBoolean(
2883                    com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
2884
2885            if (sa.getBoolean(
2886                    com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) {
2887                ai.flags |= ApplicationInfo.FLAG_IS_GAME;
2888            }
2889
2890            if (false) {
2891                if (sa.getBoolean(
2892                        com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
2893                        false)) {
2894                    ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
2895
2896                    // A heavy-weight application can not be in a custom process.
2897                    // We can do direct compare because we intern all strings.
2898                    if (ai.processName != null && ai.processName != ai.packageName) {
2899                        outError[0] = "cantSaveState applications can not use custom processes";
2900                    }
2901                }
2902            }
2903        }
2904
2905        ai.uiOptions = sa.getInt(
2906                com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);
2907
2908        sa.recycle();
2909
2910        if (outError[0] != null) {
2911            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2912            return false;
2913        }
2914
2915        final int innerDepth = parser.getDepth();
2916        int type;
2917        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2918                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
2919            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2920                continue;
2921            }
2922
2923            String tagName = parser.getName();
2924            if (tagName.equals("activity")) {
2925                Activity a = parseActivity(owner, res, parser, flags, outError, false,
2926                        owner.baseHardwareAccelerated);
2927                if (a == null) {
2928                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2929                    return false;
2930                }
2931
2932                owner.activities.add(a);
2933
2934            } else if (tagName.equals("receiver")) {
2935                Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
2936                if (a == null) {
2937                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2938                    return false;
2939                }
2940
2941                owner.receivers.add(a);
2942
2943            } else if (tagName.equals("service")) {
2944                Service s = parseService(owner, res, parser, flags, outError);
2945                if (s == null) {
2946                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2947                    return false;
2948                }
2949
2950                owner.services.add(s);
2951
2952            } else if (tagName.equals("provider")) {
2953                Provider p = parseProvider(owner, res, parser, flags, outError);
2954                if (p == null) {
2955                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2956                    return false;
2957                }
2958
2959                owner.providers.add(p);
2960
2961            } else if (tagName.equals("activity-alias")) {
2962                Activity a = parseActivityAlias(owner, res, parser, flags, outError);
2963                if (a == null) {
2964                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2965                    return false;
2966                }
2967
2968                owner.activities.add(a);
2969
2970            } else if (parser.getName().equals("meta-data")) {
2971                // note: application meta-data is stored off to the side, so it can
2972                // remain null in the primary copy (we like to avoid extra copies because
2973                // it can be large)
2974                if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
2975                        outError)) == null) {
2976                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2977                    return false;
2978                }
2979
2980            } else if (tagName.equals("library")) {
2981                sa = res.obtainAttributes(parser,
2982                        com.android.internal.R.styleable.AndroidManifestLibrary);
2983
2984                // Note: don't allow this value to be a reference to a resource
2985                // that may change.
2986                String lname = sa.getNonResourceString(
2987                        com.android.internal.R.styleable.AndroidManifestLibrary_name);
2988
2989                sa.recycle();
2990
2991                if (lname != null) {
2992                    lname = lname.intern();
2993                    if (!ArrayUtils.contains(owner.libraryNames, lname)) {
2994                        owner.libraryNames = ArrayUtils.add(owner.libraryNames, lname);
2995                    }
2996                }
2997
2998                XmlUtils.skipCurrentTag(parser);
2999
3000            } else if (tagName.equals("uses-library")) {
3001                sa = res.obtainAttributes(parser,
3002                        com.android.internal.R.styleable.AndroidManifestUsesLibrary);
3003
3004                // Note: don't allow this value to be a reference to a resource
3005                // that may change.
3006                String lname = sa.getNonResourceString(
3007                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
3008                boolean req = sa.getBoolean(
3009                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
3010                        true);
3011
3012                sa.recycle();
3013
3014                if (lname != null) {
3015                    lname = lname.intern();
3016                    if (req) {
3017                        owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
3018                    } else {
3019                        owner.usesOptionalLibraries = ArrayUtils.add(
3020                                owner.usesOptionalLibraries, lname);
3021                    }
3022                }
3023
3024                XmlUtils.skipCurrentTag(parser);
3025
3026            } else if (tagName.equals("uses-package")) {
3027                // Dependencies for app installers; we don't currently try to
3028                // enforce this.
3029                XmlUtils.skipCurrentTag(parser);
3030
3031            } else {
3032                if (!RIGID_PARSER) {
3033                    Slog.w(TAG, "Unknown element under <application>: " + tagName
3034                            + " at " + mArchiveSourcePath + " "
3035                            + parser.getPositionDescription());
3036                    XmlUtils.skipCurrentTag(parser);
3037                    continue;
3038                } else {
3039                    outError[0] = "Bad element under <application>: " + tagName;
3040                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3041                    return false;
3042                }
3043            }
3044        }
3045
3046        modifySharedLibrariesForBackwardCompatibility(owner);
3047
3048        if (hasDomainURLs(owner)) {
3049            owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
3050        } else {
3051            owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
3052        }
3053
3054        return true;
3055    }
3056
3057    private static void modifySharedLibrariesForBackwardCompatibility(Package owner) {
3058        // "org.apache.http.legacy" is now a part of the boot classpath so it doesn't need
3059        // to be an explicit dependency.
3060        //
3061        // A future change will remove this library from the boot classpath, at which point
3062        // all apps that target SDK 21 and earlier will have it automatically added to their
3063        // dependency lists.
3064        owner.usesLibraries = ArrayUtils.remove(owner.usesLibraries, "org.apache.http.legacy");
3065        owner.usesOptionalLibraries = ArrayUtils.remove(owner.usesOptionalLibraries,
3066                "org.apache.http.legacy");
3067    }
3068
3069    /**
3070     * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
3071     */
3072    private static boolean hasDomainURLs(Package pkg) {
3073        if (pkg == null || pkg.activities == null) return false;
3074        final ArrayList<Activity> activities = pkg.activities;
3075        final int countActivities = activities.size();
3076        for (int n=0; n<countActivities; n++) {
3077            Activity activity = activities.get(n);
3078            ArrayList<ActivityIntentInfo> filters = activity.intents;
3079            if (filters == null) continue;
3080            final int countFilters = filters.size();
3081            for (int m=0; m<countFilters; m++) {
3082                ActivityIntentInfo aii = filters.get(m);
3083                if (!aii.hasAction(Intent.ACTION_VIEW)) continue;
3084                if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue;
3085                if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
3086                        aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
3087                    return true;
3088                }
3089            }
3090        }
3091        return false;
3092    }
3093
3094    /**
3095     * Parse the {@code application} XML tree at the current parse location in a
3096     * <em>split APK</em> manifest.
3097     * <p>
3098     * Note that split APKs have many more restrictions on what they're capable
3099     * of doing, so many valid features of a base APK have been carefully
3100     * omitted here.
3101     */
3102    private boolean parseSplitApplication(Package owner, Resources res, XmlResourceParser parser,
3103            int flags, int splitIndex, String[] outError)
3104            throws XmlPullParserException, IOException {
3105        TypedArray sa = res.obtainAttributes(parser,
3106                com.android.internal.R.styleable.AndroidManifestApplication);
3107
3108        if (sa.getBoolean(
3109                com.android.internal.R.styleable.AndroidManifestApplication_hasCode, true)) {
3110            owner.splitFlags[splitIndex] |= ApplicationInfo.FLAG_HAS_CODE;
3111        }
3112
3113        final int innerDepth = parser.getDepth();
3114        int type;
3115        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3116                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
3117            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3118                continue;
3119            }
3120
3121            String tagName = parser.getName();
3122            if (tagName.equals("activity")) {
3123                Activity a = parseActivity(owner, res, parser, flags, outError, false,
3124                        owner.baseHardwareAccelerated);
3125                if (a == null) {
3126                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3127                    return false;
3128                }
3129
3130                owner.activities.add(a);
3131
3132            } else if (tagName.equals("receiver")) {
3133                Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
3134                if (a == null) {
3135                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3136                    return false;
3137                }
3138
3139                owner.receivers.add(a);
3140
3141            } else if (tagName.equals("service")) {
3142                Service s = parseService(owner, res, parser, flags, outError);
3143                if (s == null) {
3144                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3145                    return false;
3146                }
3147
3148                owner.services.add(s);
3149
3150            } else if (tagName.equals("provider")) {
3151                Provider p = parseProvider(owner, res, parser, flags, outError);
3152                if (p == null) {
3153                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3154                    return false;
3155                }
3156
3157                owner.providers.add(p);
3158
3159            } else if (tagName.equals("activity-alias")) {
3160                Activity a = parseActivityAlias(owner, res, parser, flags, outError);
3161                if (a == null) {
3162                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3163                    return false;
3164                }
3165
3166                owner.activities.add(a);
3167
3168            } else if (parser.getName().equals("meta-data")) {
3169                // note: application meta-data is stored off to the side, so it can
3170                // remain null in the primary copy (we like to avoid extra copies because
3171                // it can be large)
3172                if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
3173                        outError)) == null) {
3174                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3175                    return false;
3176                }
3177
3178            } else if (tagName.equals("uses-library")) {
3179                sa = res.obtainAttributes(parser,
3180                        com.android.internal.R.styleable.AndroidManifestUsesLibrary);
3181
3182                // Note: don't allow this value to be a reference to a resource
3183                // that may change.
3184                String lname = sa.getNonResourceString(
3185                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
3186                boolean req = sa.getBoolean(
3187                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
3188                        true);
3189
3190                sa.recycle();
3191
3192                if (lname != null) {
3193                    lname = lname.intern();
3194                    if (req) {
3195                        // Upgrade to treat as stronger constraint
3196                        owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
3197                        owner.usesOptionalLibraries = ArrayUtils.remove(
3198                                owner.usesOptionalLibraries, lname);
3199                    } else {
3200                        // Ignore if someone already defined as required
3201                        if (!ArrayUtils.contains(owner.usesLibraries, lname)) {
3202                            owner.usesOptionalLibraries = ArrayUtils.add(
3203                                    owner.usesOptionalLibraries, lname);
3204                        }
3205                    }
3206                }
3207
3208                XmlUtils.skipCurrentTag(parser);
3209
3210            } else if (tagName.equals("uses-package")) {
3211                // Dependencies for app installers; we don't currently try to
3212                // enforce this.
3213                XmlUtils.skipCurrentTag(parser);
3214
3215            } else {
3216                if (!RIGID_PARSER) {
3217                    Slog.w(TAG, "Unknown element under <application>: " + tagName
3218                            + " at " + mArchiveSourcePath + " "
3219                            + parser.getPositionDescription());
3220                    XmlUtils.skipCurrentTag(parser);
3221                    continue;
3222                } else {
3223                    outError[0] = "Bad element under <application>: " + tagName;
3224                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3225                    return false;
3226                }
3227            }
3228        }
3229
3230        return true;
3231    }
3232
3233    private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
3234            String[] outError, String tag, TypedArray sa,
3235            int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) {
3236        String name = sa.getNonConfigurationString(nameRes, 0);
3237        if (name == null) {
3238            outError[0] = tag + " does not specify android:name";
3239            return false;
3240        }
3241
3242        outInfo.name
3243            = buildClassName(owner.applicationInfo.packageName, name, outError);
3244        if (outInfo.name == null) {
3245            return false;
3246        }
3247
3248        int iconVal = sa.getResourceId(iconRes, 0);
3249        if (iconVal != 0) {
3250            outInfo.icon = iconVal;
3251            outInfo.nonLocalizedLabel = null;
3252        }
3253
3254        int logoVal = sa.getResourceId(logoRes, 0);
3255        if (logoVal != 0) {
3256            outInfo.logo = logoVal;
3257        }
3258
3259        int bannerVal = sa.getResourceId(bannerRes, 0);
3260        if (bannerVal != 0) {
3261            outInfo.banner = bannerVal;
3262        }
3263
3264        TypedValue v = sa.peekValue(labelRes);
3265        if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
3266            outInfo.nonLocalizedLabel = v.coerceToString();
3267        }
3268
3269        outInfo.packageName = owner.packageName;
3270
3271        return true;
3272    }
3273
3274    private Activity parseActivity(Package owner, Resources res,
3275            XmlResourceParser parser, int flags, String[] outError,
3276            boolean receiver, boolean hardwareAccelerated)
3277            throws XmlPullParserException, IOException {
3278        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
3279
3280        if (mParseActivityArgs == null) {
3281            mParseActivityArgs = new ParseComponentArgs(owner, outError,
3282                    R.styleable.AndroidManifestActivity_name,
3283                    R.styleable.AndroidManifestActivity_label,
3284                    R.styleable.AndroidManifestActivity_icon,
3285                    R.styleable.AndroidManifestActivity_logo,
3286                    R.styleable.AndroidManifestActivity_banner,
3287                    mSeparateProcesses,
3288                    R.styleable.AndroidManifestActivity_process,
3289                    R.styleable.AndroidManifestActivity_description,
3290                    R.styleable.AndroidManifestActivity_enabled);
3291        }
3292
3293        mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
3294        mParseActivityArgs.sa = sa;
3295        mParseActivityArgs.flags = flags;
3296
3297        Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
3298        if (outError[0] != null) {
3299            sa.recycle();
3300            return null;
3301        }
3302
3303        boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
3304        if (setExported) {
3305            a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false);
3306        }
3307
3308        a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
3309
3310        a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
3311                a.info.applicationInfo.uiOptions);
3312
3313        String parentName = sa.getNonConfigurationString(
3314                R.styleable.AndroidManifestActivity_parentActivityName,
3315                Configuration.NATIVE_CONFIG_VERSION);
3316        if (parentName != null) {
3317            String parentClassName = buildClassName(a.info.packageName, parentName, outError);
3318            if (outError[0] == null) {
3319                a.info.parentActivityName = parentClassName;
3320            } else {
3321                Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " +
3322                        parentName);
3323                outError[0] = null;
3324            }
3325        }
3326
3327        String str;
3328        str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
3329        if (str == null) {
3330            a.info.permission = owner.applicationInfo.permission;
3331        } else {
3332            a.info.permission = str.length() > 0 ? str.toString().intern() : null;
3333        }
3334
3335        str = sa.getNonConfigurationString(
3336                R.styleable.AndroidManifestActivity_taskAffinity,
3337                Configuration.NATIVE_CONFIG_VERSION);
3338        a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
3339                owner.applicationInfo.taskAffinity, str, outError);
3340
3341        a.info.flags = 0;
3342        if (sa.getBoolean(
3343                R.styleable.AndroidManifestActivity_multiprocess, false)) {
3344            a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
3345        }
3346
3347        if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
3348            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
3349        }
3350
3351        if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
3352            a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
3353        }
3354
3355        if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
3356            a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
3357        }
3358
3359        if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
3360            a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
3361        }
3362
3363        if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
3364            a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
3365        }
3366
3367        if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
3368            a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
3369        }
3370
3371        if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
3372                (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
3373            a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
3374        }
3375
3376        if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) {
3377            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
3378        }
3379
3380        if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
3381                || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
3382            a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
3383        }
3384
3385        if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
3386            a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
3387        }
3388
3389        if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
3390            a.info.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
3391        }
3392
3393        if (!receiver) {
3394            if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
3395                    hardwareAccelerated)) {
3396                a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
3397            }
3398
3399            a.info.launchMode = sa.getInt(
3400                    R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
3401            a.info.documentLaunchMode = sa.getInt(
3402                    R.styleable.AndroidManifestActivity_documentLaunchMode,
3403                    ActivityInfo.DOCUMENT_LAUNCH_NONE);
3404            a.info.maxRecents = sa.getInt(
3405                    R.styleable.AndroidManifestActivity_maxRecents,
3406                    ActivityManager.getDefaultAppRecentsLimitStatic());
3407            a.info.configChanges = sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0);
3408            a.info.softInputMode = sa.getInt(
3409                    R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
3410
3411            a.info.persistableMode = sa.getInteger(
3412                    R.styleable.AndroidManifestActivity_persistableMode,
3413                    ActivityInfo.PERSIST_ROOT_ONLY);
3414
3415            if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
3416                a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
3417            }
3418
3419            if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) {
3420                a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
3421            }
3422
3423            if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) {
3424                a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
3425            }
3426
3427            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
3428                a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
3429            }
3430
3431            a.info.screenOrientation = sa.getInt(
3432                    R.styleable.AndroidManifestActivity_screenOrientation,
3433                    SCREEN_ORIENTATION_UNSPECIFIED);
3434
3435            a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
3436            final boolean appDefault = (owner.applicationInfo.privateFlags
3437                    & PRIVATE_FLAG_RESIZEABLE_ACTIVITIES) != 0;
3438            final boolean resizeable = sa.getBoolean(
3439                    R.styleable.AndroidManifestActivity_resizeableActivity, appDefault);
3440
3441            if (resizeable) {
3442                if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
3443                        false)) {
3444                    a.info.resizeMode = RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
3445                } else {
3446                    a.info.resizeMode = RESIZE_MODE_RESIZEABLE;
3447                }
3448            } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
3449                a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
3450            } else if (a.info.screenOrientation == SCREEN_ORIENTATION_UNSPECIFIED
3451                    && (a.info.flags & FLAG_IMMERSIVE) == 0) {
3452                a.info.resizeMode = RESIZE_MODE_CROP_WINDOWS;
3453            }
3454
3455            if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
3456                a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
3457            }
3458
3459            a.info.lockTaskLaunchMode =
3460                    sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
3461
3462            a.info.encryptionAware = sa.getBoolean(
3463                    R.styleable.AndroidManifestActivity_encryptionAware,
3464                    owner.applicationInfo.isEncryptionAware());
3465        } else {
3466            a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
3467            a.info.configChanges = 0;
3468
3469            if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
3470                a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
3471                if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
3472                    Slog.w(TAG, "Activity exported request ignored due to singleUser: "
3473                            + a.className + " at " + mArchiveSourcePath + " "
3474                            + parser.getPositionDescription());
3475                    a.info.exported = false;
3476                    setExported = true;
3477                }
3478            }
3479
3480            a.info.encryptionAware = sa.getBoolean(
3481                    R.styleable.AndroidManifestActivity_encryptionAware,
3482                    owner.applicationInfo.isEncryptionAware());
3483        }
3484
3485        if (a.info.encryptionAware) {
3486            owner.applicationInfo.privateFlags |=
3487                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE;
3488        }
3489
3490        sa.recycle();
3491
3492        if (receiver && (owner.applicationInfo.privateFlags
3493                &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
3494            // A heavy-weight application can not have receives in its main process
3495            // We can do direct compare because we intern all strings.
3496            if (a.info.processName == owner.packageName) {
3497                outError[0] = "Heavy-weight applications can not have receivers in main process";
3498            }
3499        }
3500
3501        if (outError[0] != null) {
3502            return null;
3503        }
3504
3505        int outerDepth = parser.getDepth();
3506        int type;
3507        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3508               && (type != XmlPullParser.END_TAG
3509                       || parser.getDepth() > outerDepth)) {
3510            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3511                continue;
3512            }
3513
3514            if (parser.getName().equals("intent-filter")) {
3515                ActivityIntentInfo intent = new ActivityIntentInfo(a);
3516                if (!parseIntent(res, parser, true, true, intent, outError)) {
3517                    return null;
3518                }
3519                if (intent.countActions() == 0) {
3520                    Slog.w(TAG, "No actions in intent filter at "
3521                            + mArchiveSourcePath + " "
3522                            + parser.getPositionDescription());
3523                } else {
3524                    a.intents.add(intent);
3525                }
3526            } else if (!receiver && parser.getName().equals("preferred")) {
3527                ActivityIntentInfo intent = new ActivityIntentInfo(a);
3528                if (!parseIntent(res, parser, false, false, intent, outError)) {
3529                    return null;
3530                }
3531                if (intent.countActions() == 0) {
3532                    Slog.w(TAG, "No actions in preferred at "
3533                            + mArchiveSourcePath + " "
3534                            + parser.getPositionDescription());
3535                } else {
3536                    if (owner.preferredActivityFilters == null) {
3537                        owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
3538                    }
3539                    owner.preferredActivityFilters.add(intent);
3540                }
3541            } else if (parser.getName().equals("meta-data")) {
3542                if ((a.metaData = parseMetaData(res, parser, a.metaData,
3543                        outError)) == null) {
3544                    return null;
3545                }
3546            } else if (!receiver && parser.getName().equals("layout")) {
3547                parseLayout(res, parser, a);
3548            } else {
3549                if (!RIGID_PARSER) {
3550                    Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
3551                    if (receiver) {
3552                        Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
3553                                + " at " + mArchiveSourcePath + " "
3554                                + parser.getPositionDescription());
3555                    } else {
3556                        Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
3557                                + " at " + mArchiveSourcePath + " "
3558                                + parser.getPositionDescription());
3559                    }
3560                    XmlUtils.skipCurrentTag(parser);
3561                    continue;
3562                } else {
3563                    if (receiver) {
3564                        outError[0] = "Bad element under <receiver>: " + parser.getName();
3565                    } else {
3566                        outError[0] = "Bad element under <activity>: " + parser.getName();
3567                    }
3568                    return null;
3569                }
3570            }
3571        }
3572
3573        if (!setExported) {
3574            a.info.exported = a.intents.size() > 0;
3575        }
3576
3577        return a;
3578    }
3579
3580    private void parseLayout(Resources res, AttributeSet attrs, Activity a) {
3581        TypedArray sw = res.obtainAttributes(attrs,
3582                com.android.internal.R.styleable.AndroidManifestLayout);
3583        int width = -1;
3584        float widthFraction = -1f;
3585        int height = -1;
3586        float heightFraction = -1f;
3587        final int widthType = sw.getType(
3588                com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth);
3589        if (widthType == TypedValue.TYPE_FRACTION) {
3590            widthFraction = sw.getFraction(
3591                    com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth,
3592                    1, 1, -1);
3593        } else if (widthType == TypedValue.TYPE_DIMENSION) {
3594            width = sw.getDimensionPixelSize(
3595                    com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth,
3596                    -1);
3597        }
3598        final int heightType = sw.getType(
3599                com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight);
3600        if (heightType == TypedValue.TYPE_FRACTION) {
3601            heightFraction = sw.getFraction(
3602                    com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight,
3603                    1, 1, -1);
3604        } else if (heightType == TypedValue.TYPE_DIMENSION) {
3605            height = sw.getDimensionPixelSize(
3606                    com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight,
3607                    -1);
3608        }
3609        int gravity = sw.getInt(
3610                com.android.internal.R.styleable.AndroidManifestLayout_gravity,
3611                Gravity.CENTER);
3612        int minimalSize = sw.getDimensionPixelSize(
3613                com.android.internal.R.styleable.AndroidManifestLayout_minimalSize,
3614                -1);
3615        sw.recycle();
3616        a.info.layout = new ActivityInfo.Layout(width, widthFraction,
3617                height, heightFraction, gravity, minimalSize);
3618    }
3619
3620    private Activity parseActivityAlias(Package owner, Resources res,
3621            XmlResourceParser parser, int flags, String[] outError)
3622            throws XmlPullParserException, IOException {
3623        TypedArray sa = res.obtainAttributes(parser,
3624                com.android.internal.R.styleable.AndroidManifestActivityAlias);
3625
3626        String targetActivity = sa.getNonConfigurationString(
3627                com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity,
3628                Configuration.NATIVE_CONFIG_VERSION);
3629        if (targetActivity == null) {
3630            outError[0] = "<activity-alias> does not specify android:targetActivity";
3631            sa.recycle();
3632            return null;
3633        }
3634
3635        targetActivity = buildClassName(owner.applicationInfo.packageName,
3636                targetActivity, outError);
3637        if (targetActivity == null) {
3638            sa.recycle();
3639            return null;
3640        }
3641
3642        if (mParseActivityAliasArgs == null) {
3643            mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
3644                    com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
3645                    com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
3646                    com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
3647                    com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
3648                    com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
3649                    mSeparateProcesses,
3650                    0,
3651                    com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
3652                    com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
3653            mParseActivityAliasArgs.tag = "<activity-alias>";
3654        }
3655
3656        mParseActivityAliasArgs.sa = sa;
3657        mParseActivityAliasArgs.flags = flags;
3658
3659        Activity target = null;
3660
3661        final int NA = owner.activities.size();
3662        for (int i=0; i<NA; i++) {
3663            Activity t = owner.activities.get(i);
3664            if (targetActivity.equals(t.info.name)) {
3665                target = t;
3666                break;
3667            }
3668        }
3669
3670        if (target == null) {
3671            outError[0] = "<activity-alias> target activity " + targetActivity
3672                    + " not found in manifest";
3673            sa.recycle();
3674            return null;
3675        }
3676
3677        ActivityInfo info = new ActivityInfo();
3678        info.targetActivity = targetActivity;
3679        info.configChanges = target.info.configChanges;
3680        info.flags = target.info.flags;
3681        info.icon = target.info.icon;
3682        info.logo = target.info.logo;
3683        info.banner = target.info.banner;
3684        info.labelRes = target.info.labelRes;
3685        info.nonLocalizedLabel = target.info.nonLocalizedLabel;
3686        info.launchMode = target.info.launchMode;
3687        info.lockTaskLaunchMode = target.info.lockTaskLaunchMode;
3688        info.processName = target.info.processName;
3689        if (info.descriptionRes == 0) {
3690            info.descriptionRes = target.info.descriptionRes;
3691        }
3692        info.screenOrientation = target.info.screenOrientation;
3693        info.taskAffinity = target.info.taskAffinity;
3694        info.theme = target.info.theme;
3695        info.softInputMode = target.info.softInputMode;
3696        info.uiOptions = target.info.uiOptions;
3697        info.parentActivityName = target.info.parentActivityName;
3698        info.maxRecents = target.info.maxRecents;
3699        info.layout = target.info.layout;
3700        info.resizeMode = target.info.resizeMode;
3701        info.encryptionAware = target.info.encryptionAware;
3702
3703        Activity a = new Activity(mParseActivityAliasArgs, info);
3704        if (outError[0] != null) {
3705            sa.recycle();
3706            return null;
3707        }
3708
3709        final boolean setExported = sa.hasValue(
3710                com.android.internal.R.styleable.AndroidManifestActivityAlias_exported);
3711        if (setExported) {
3712            a.info.exported = sa.getBoolean(
3713                    com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false);
3714        }
3715
3716        String str;
3717        str = sa.getNonConfigurationString(
3718                com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0);
3719        if (str != null) {
3720            a.info.permission = str.length() > 0 ? str.toString().intern() : null;
3721        }
3722
3723        String parentName = sa.getNonConfigurationString(
3724                com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName,
3725                Configuration.NATIVE_CONFIG_VERSION);
3726        if (parentName != null) {
3727            String parentClassName = buildClassName(a.info.packageName, parentName, outError);
3728            if (outError[0] == null) {
3729                a.info.parentActivityName = parentClassName;
3730            } else {
3731                Log.e(TAG, "Activity alias " + a.info.name +
3732                        " specified invalid parentActivityName " + parentName);
3733                outError[0] = null;
3734            }
3735        }
3736
3737        sa.recycle();
3738
3739        if (outError[0] != null) {
3740            return null;
3741        }
3742
3743        int outerDepth = parser.getDepth();
3744        int type;
3745        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3746               && (type != XmlPullParser.END_TAG
3747                       || parser.getDepth() > outerDepth)) {
3748            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3749                continue;
3750            }
3751
3752            if (parser.getName().equals("intent-filter")) {
3753                ActivityIntentInfo intent = new ActivityIntentInfo(a);
3754                if (!parseIntent(res, parser, true, true, intent, outError)) {
3755                    return null;
3756                }
3757                if (intent.countActions() == 0) {
3758                    Slog.w(TAG, "No actions in intent filter at "
3759                            + mArchiveSourcePath + " "
3760                            + parser.getPositionDescription());
3761                } else {
3762                    a.intents.add(intent);
3763                }
3764            } else if (parser.getName().equals("meta-data")) {
3765                if ((a.metaData=parseMetaData(res, parser, a.metaData,
3766                        outError)) == null) {
3767                    return null;
3768                }
3769            } else {
3770                if (!RIGID_PARSER) {
3771                    Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName()
3772                            + " at " + mArchiveSourcePath + " "
3773                            + parser.getPositionDescription());
3774                    XmlUtils.skipCurrentTag(parser);
3775                    continue;
3776                } else {
3777                    outError[0] = "Bad element under <activity-alias>: " + parser.getName();
3778                    return null;
3779                }
3780            }
3781        }
3782
3783        if (!setExported) {
3784            a.info.exported = a.intents.size() > 0;
3785        }
3786
3787        return a;
3788    }
3789
3790    private Provider parseProvider(Package owner, Resources res,
3791            XmlResourceParser parser, int flags, String[] outError)
3792            throws XmlPullParserException, IOException {
3793        TypedArray sa = res.obtainAttributes(parser,
3794                com.android.internal.R.styleable.AndroidManifestProvider);
3795
3796        if (mParseProviderArgs == null) {
3797            mParseProviderArgs = new ParseComponentArgs(owner, outError,
3798                    com.android.internal.R.styleable.AndroidManifestProvider_name,
3799                    com.android.internal.R.styleable.AndroidManifestProvider_label,
3800                    com.android.internal.R.styleable.AndroidManifestProvider_icon,
3801                    com.android.internal.R.styleable.AndroidManifestProvider_logo,
3802                    com.android.internal.R.styleable.AndroidManifestProvider_banner,
3803                    mSeparateProcesses,
3804                    com.android.internal.R.styleable.AndroidManifestProvider_process,
3805                    com.android.internal.R.styleable.AndroidManifestProvider_description,
3806                    com.android.internal.R.styleable.AndroidManifestProvider_enabled);
3807            mParseProviderArgs.tag = "<provider>";
3808        }
3809
3810        mParseProviderArgs.sa = sa;
3811        mParseProviderArgs.flags = flags;
3812
3813        Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
3814        if (outError[0] != null) {
3815            sa.recycle();
3816            return null;
3817        }
3818
3819        boolean providerExportedDefault = false;
3820
3821        if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
3822            // For compatibility, applications targeting API level 16 or lower
3823            // should have their content providers exported by default, unless they
3824            // specify otherwise.
3825            providerExportedDefault = true;
3826        }
3827
3828        p.info.exported = sa.getBoolean(
3829                com.android.internal.R.styleable.AndroidManifestProvider_exported,
3830                providerExportedDefault);
3831
3832        String cpname = sa.getNonConfigurationString(
3833                com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0);
3834
3835        p.info.isSyncable = sa.getBoolean(
3836                com.android.internal.R.styleable.AndroidManifestProvider_syncable,
3837                false);
3838
3839        String permission = sa.getNonConfigurationString(
3840                com.android.internal.R.styleable.AndroidManifestProvider_permission, 0);
3841        String str = sa.getNonConfigurationString(
3842                com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0);
3843        if (str == null) {
3844            str = permission;
3845        }
3846        if (str == null) {
3847            p.info.readPermission = owner.applicationInfo.permission;
3848        } else {
3849            p.info.readPermission =
3850                str.length() > 0 ? str.toString().intern() : null;
3851        }
3852        str = sa.getNonConfigurationString(
3853                com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0);
3854        if (str == null) {
3855            str = permission;
3856        }
3857        if (str == null) {
3858            p.info.writePermission = owner.applicationInfo.permission;
3859        } else {
3860            p.info.writePermission =
3861                str.length() > 0 ? str.toString().intern() : null;
3862        }
3863
3864        p.info.grantUriPermissions = sa.getBoolean(
3865                com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
3866                false);
3867
3868        p.info.multiprocess = sa.getBoolean(
3869                com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
3870                false);
3871
3872        p.info.initOrder = sa.getInt(
3873                com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
3874                0);
3875
3876        p.info.flags = 0;
3877
3878        if (sa.getBoolean(
3879                com.android.internal.R.styleable.AndroidManifestProvider_singleUser,
3880                false)) {
3881            p.info.flags |= ProviderInfo.FLAG_SINGLE_USER;
3882            if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
3883                Slog.w(TAG, "Provider exported request ignored due to singleUser: "
3884                        + p.className + " at " + mArchiveSourcePath + " "
3885                        + parser.getPositionDescription());
3886                p.info.exported = false;
3887            }
3888        }
3889
3890        p.info.encryptionAware = sa.getBoolean(
3891                R.styleable.AndroidManifestProvider_encryptionAware,
3892                owner.applicationInfo.isEncryptionAware());
3893        if (p.info.encryptionAware) {
3894            owner.applicationInfo.privateFlags |=
3895                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE;
3896        }
3897
3898        sa.recycle();
3899
3900        if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
3901                != 0) {
3902            // A heavy-weight application can not have providers in its main process
3903            // We can do direct compare because we intern all strings.
3904            if (p.info.processName == owner.packageName) {
3905                outError[0] = "Heavy-weight applications can not have providers in main process";
3906                return null;
3907            }
3908        }
3909
3910        if (cpname == null) {
3911            outError[0] = "<provider> does not include authorities attribute";
3912            return null;
3913        }
3914        if (cpname.length() <= 0) {
3915            outError[0] = "<provider> has empty authorities attribute";
3916            return null;
3917        }
3918        p.info.authority = cpname.intern();
3919
3920        if (!parseProviderTags(res, parser, p, outError)) {
3921            return null;
3922        }
3923
3924        return p;
3925    }
3926
3927    private boolean parseProviderTags(Resources res,
3928            XmlResourceParser parser, Provider outInfo, String[] outError)
3929            throws XmlPullParserException, IOException {
3930        int outerDepth = parser.getDepth();
3931        int type;
3932        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3933               && (type != XmlPullParser.END_TAG
3934                       || parser.getDepth() > outerDepth)) {
3935            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3936                continue;
3937            }
3938
3939            if (parser.getName().equals("intent-filter")) {
3940                ProviderIntentInfo intent = new ProviderIntentInfo(outInfo);
3941                if (!parseIntent(res, parser, true, false, intent, outError)) {
3942                    return false;
3943                }
3944                outInfo.intents.add(intent);
3945
3946            } else if (parser.getName().equals("meta-data")) {
3947                if ((outInfo.metaData=parseMetaData(res, parser,
3948                        outInfo.metaData, outError)) == null) {
3949                    return false;
3950                }
3951
3952            } else if (parser.getName().equals("grant-uri-permission")) {
3953                TypedArray sa = res.obtainAttributes(parser,
3954                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
3955
3956                PatternMatcher pa = null;
3957
3958                String str = sa.getNonConfigurationString(
3959                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0);
3960                if (str != null) {
3961                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
3962                }
3963
3964                str = sa.getNonConfigurationString(
3965                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
3966                if (str != null) {
3967                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
3968                }
3969
3970                str = sa.getNonConfigurationString(
3971                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
3972                if (str != null) {
3973                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
3974                }
3975
3976                sa.recycle();
3977
3978                if (pa != null) {
3979                    if (outInfo.info.uriPermissionPatterns == null) {
3980                        outInfo.info.uriPermissionPatterns = new PatternMatcher[1];
3981                        outInfo.info.uriPermissionPatterns[0] = pa;
3982                    } else {
3983                        final int N = outInfo.info.uriPermissionPatterns.length;
3984                        PatternMatcher[] newp = new PatternMatcher[N+1];
3985                        System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N);
3986                        newp[N] = pa;
3987                        outInfo.info.uriPermissionPatterns = newp;
3988                    }
3989                    outInfo.info.grantUriPermissions = true;
3990                } else {
3991                    if (!RIGID_PARSER) {
3992                        Slog.w(TAG, "Unknown element under <path-permission>: "
3993                                + parser.getName() + " at " + mArchiveSourcePath + " "
3994                                + parser.getPositionDescription());
3995                        XmlUtils.skipCurrentTag(parser);
3996                        continue;
3997                    } else {
3998                        outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
3999                        return false;
4000                    }
4001                }
4002                XmlUtils.skipCurrentTag(parser);
4003
4004            } else if (parser.getName().equals("path-permission")) {
4005                TypedArray sa = res.obtainAttributes(parser,
4006                        com.android.internal.R.styleable.AndroidManifestPathPermission);
4007
4008                PathPermission pa = null;
4009
4010                String permission = sa.getNonConfigurationString(
4011                        com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0);
4012                String readPermission = sa.getNonConfigurationString(
4013                        com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0);
4014                if (readPermission == null) {
4015                    readPermission = permission;
4016                }
4017                String writePermission = sa.getNonConfigurationString(
4018                        com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0);
4019                if (writePermission == null) {
4020                    writePermission = permission;
4021                }
4022
4023                boolean havePerm = false;
4024                if (readPermission != null) {
4025                    readPermission = readPermission.intern();
4026                    havePerm = true;
4027                }
4028                if (writePermission != null) {
4029                    writePermission = writePermission.intern();
4030                    havePerm = true;
4031                }
4032
4033                if (!havePerm) {
4034                    if (!RIGID_PARSER) {
4035                        Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
4036                                + parser.getName() + " at " + mArchiveSourcePath + " "
4037                                + parser.getPositionDescription());
4038                        XmlUtils.skipCurrentTag(parser);
4039                        continue;
4040                    } else {
4041                        outError[0] = "No readPermission or writePermssion for <path-permission>";
4042                        return false;
4043                    }
4044                }
4045
4046                String path = sa.getNonConfigurationString(
4047                        com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0);
4048                if (path != null) {
4049                    pa = new PathPermission(path,
4050                            PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
4051                }
4052
4053                path = sa.getNonConfigurationString(
4054                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
4055                if (path != null) {
4056                    pa = new PathPermission(path,
4057                            PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
4058                }
4059
4060                path = sa.getNonConfigurationString(
4061                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0);
4062                if (path != null) {
4063                    pa = new PathPermission(path,
4064                            PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
4065                }
4066
4067                sa.recycle();
4068
4069                if (pa != null) {
4070                    if (outInfo.info.pathPermissions == null) {
4071                        outInfo.info.pathPermissions = new PathPermission[1];
4072                        outInfo.info.pathPermissions[0] = pa;
4073                    } else {
4074                        final int N = outInfo.info.pathPermissions.length;
4075                        PathPermission[] newp = new PathPermission[N+1];
4076                        System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
4077                        newp[N] = pa;
4078                        outInfo.info.pathPermissions = newp;
4079                    }
4080                } else {
4081                    if (!RIGID_PARSER) {
4082                        Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
4083                                + parser.getName() + " at " + mArchiveSourcePath + " "
4084                                + parser.getPositionDescription());
4085                        XmlUtils.skipCurrentTag(parser);
4086                        continue;
4087                    }
4088                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
4089                    return false;
4090                }
4091                XmlUtils.skipCurrentTag(parser);
4092
4093            } else {
4094                if (!RIGID_PARSER) {
4095                    Slog.w(TAG, "Unknown element under <provider>: "
4096                            + parser.getName() + " at " + mArchiveSourcePath + " "
4097                            + parser.getPositionDescription());
4098                    XmlUtils.skipCurrentTag(parser);
4099                    continue;
4100                } else {
4101                    outError[0] = "Bad element under <provider>: " + parser.getName();
4102                    return false;
4103                }
4104            }
4105        }
4106        return true;
4107    }
4108
4109    private Service parseService(Package owner, Resources res,
4110            XmlResourceParser parser, int flags, String[] outError)
4111            throws XmlPullParserException, IOException {
4112        TypedArray sa = res.obtainAttributes(parser,
4113                com.android.internal.R.styleable.AndroidManifestService);
4114
4115        if (mParseServiceArgs == null) {
4116            mParseServiceArgs = new ParseComponentArgs(owner, outError,
4117                    com.android.internal.R.styleable.AndroidManifestService_name,
4118                    com.android.internal.R.styleable.AndroidManifestService_label,
4119                    com.android.internal.R.styleable.AndroidManifestService_icon,
4120                    com.android.internal.R.styleable.AndroidManifestService_logo,
4121                    com.android.internal.R.styleable.AndroidManifestService_banner,
4122                    mSeparateProcesses,
4123                    com.android.internal.R.styleable.AndroidManifestService_process,
4124                    com.android.internal.R.styleable.AndroidManifestService_description,
4125                    com.android.internal.R.styleable.AndroidManifestService_enabled);
4126            mParseServiceArgs.tag = "<service>";
4127        }
4128
4129        mParseServiceArgs.sa = sa;
4130        mParseServiceArgs.flags = flags;
4131
4132        Service s = new Service(mParseServiceArgs, new ServiceInfo());
4133        if (outError[0] != null) {
4134            sa.recycle();
4135            return null;
4136        }
4137
4138        boolean setExported = sa.hasValue(
4139                com.android.internal.R.styleable.AndroidManifestService_exported);
4140        if (setExported) {
4141            s.info.exported = sa.getBoolean(
4142                    com.android.internal.R.styleable.AndroidManifestService_exported, false);
4143        }
4144
4145        String str = sa.getNonConfigurationString(
4146                com.android.internal.R.styleable.AndroidManifestService_permission, 0);
4147        if (str == null) {
4148            s.info.permission = owner.applicationInfo.permission;
4149        } else {
4150            s.info.permission = str.length() > 0 ? str.toString().intern() : null;
4151        }
4152
4153        s.info.flags = 0;
4154        if (sa.getBoolean(
4155                com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
4156                false)) {
4157            s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
4158        }
4159        if (sa.getBoolean(
4160                com.android.internal.R.styleable.AndroidManifestService_isolatedProcess,
4161                false)) {
4162            s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
4163        }
4164        if (sa.getBoolean(
4165                com.android.internal.R.styleable.AndroidManifestService_externalService,
4166                false)) {
4167            s.info.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
4168        }
4169        if (sa.getBoolean(
4170                com.android.internal.R.styleable.AndroidManifestService_singleUser,
4171                false)) {
4172            s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
4173            if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
4174                Slog.w(TAG, "Service exported request ignored due to singleUser: "
4175                        + s.className + " at " + mArchiveSourcePath + " "
4176                        + parser.getPositionDescription());
4177                s.info.exported = false;
4178                setExported = true;
4179            }
4180        }
4181
4182        s.info.encryptionAware = sa.getBoolean(
4183                R.styleable.AndroidManifestService_encryptionAware,
4184                owner.applicationInfo.isEncryptionAware());
4185        if (s.info.encryptionAware) {
4186            owner.applicationInfo.privateFlags |=
4187                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE;
4188        }
4189
4190        sa.recycle();
4191
4192        if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
4193                != 0) {
4194            // A heavy-weight application can not have services in its main process
4195            // We can do direct compare because we intern all strings.
4196            if (s.info.processName == owner.packageName) {
4197                outError[0] = "Heavy-weight applications can not have services in main process";
4198                return null;
4199            }
4200        }
4201
4202        int outerDepth = parser.getDepth();
4203        int type;
4204        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4205               && (type != XmlPullParser.END_TAG
4206                       || parser.getDepth() > outerDepth)) {
4207            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4208                continue;
4209            }
4210
4211            if (parser.getName().equals("intent-filter")) {
4212                ServiceIntentInfo intent = new ServiceIntentInfo(s);
4213                if (!parseIntent(res, parser, true, false, intent, outError)) {
4214                    return null;
4215                }
4216
4217                s.intents.add(intent);
4218            } else if (parser.getName().equals("meta-data")) {
4219                if ((s.metaData=parseMetaData(res, parser, s.metaData,
4220                        outError)) == null) {
4221                    return null;
4222                }
4223            } else {
4224                if (!RIGID_PARSER) {
4225                    Slog.w(TAG, "Unknown element under <service>: "
4226                            + parser.getName() + " at " + mArchiveSourcePath + " "
4227                            + parser.getPositionDescription());
4228                    XmlUtils.skipCurrentTag(parser);
4229                    continue;
4230                } else {
4231                    outError[0] = "Bad element under <service>: " + parser.getName();
4232                    return null;
4233                }
4234            }
4235        }
4236
4237        if (!setExported) {
4238            s.info.exported = s.intents.size() > 0;
4239        }
4240
4241        return s;
4242    }
4243
4244    private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag,
4245            Component<?> outInfo, String[] outError) throws XmlPullParserException, IOException {
4246        int outerDepth = parser.getDepth();
4247        int type;
4248        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4249               && (type != XmlPullParser.END_TAG
4250                       || parser.getDepth() > outerDepth)) {
4251            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4252                continue;
4253            }
4254
4255            if (parser.getName().equals("meta-data")) {
4256                if ((outInfo.metaData=parseMetaData(res, parser,
4257                        outInfo.metaData, outError)) == null) {
4258                    return false;
4259                }
4260            } else {
4261                if (!RIGID_PARSER) {
4262                    Slog.w(TAG, "Unknown element under " + tag + ": "
4263                            + parser.getName() + " at " + mArchiveSourcePath + " "
4264                            + parser.getPositionDescription());
4265                    XmlUtils.skipCurrentTag(parser);
4266                    continue;
4267                } else {
4268                    outError[0] = "Bad element under " + tag + ": " + parser.getName();
4269                    return false;
4270                }
4271            }
4272        }
4273        return true;
4274    }
4275
4276    private Bundle parseMetaData(Resources res,
4277            XmlResourceParser parser, Bundle data, String[] outError)
4278            throws XmlPullParserException, IOException {
4279
4280        TypedArray sa = res.obtainAttributes(parser,
4281                com.android.internal.R.styleable.AndroidManifestMetaData);
4282
4283        if (data == null) {
4284            data = new Bundle();
4285        }
4286
4287        String name = sa.getNonConfigurationString(
4288                com.android.internal.R.styleable.AndroidManifestMetaData_name, 0);
4289        if (name == null) {
4290            outError[0] = "<meta-data> requires an android:name attribute";
4291            sa.recycle();
4292            return null;
4293        }
4294
4295        name = name.intern();
4296
4297        TypedValue v = sa.peekValue(
4298                com.android.internal.R.styleable.AndroidManifestMetaData_resource);
4299        if (v != null && v.resourceId != 0) {
4300            //Slog.i(TAG, "Meta data ref " + name + ": " + v);
4301            data.putInt(name, v.resourceId);
4302        } else {
4303            v = sa.peekValue(
4304                    com.android.internal.R.styleable.AndroidManifestMetaData_value);
4305            //Slog.i(TAG, "Meta data " + name + ": " + v);
4306            if (v != null) {
4307                if (v.type == TypedValue.TYPE_STRING) {
4308                    CharSequence cs = v.coerceToString();
4309                    data.putString(name, cs != null ? cs.toString().intern() : null);
4310                } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
4311                    data.putBoolean(name, v.data != 0);
4312                } else if (v.type >= TypedValue.TYPE_FIRST_INT
4313                        && v.type <= TypedValue.TYPE_LAST_INT) {
4314                    data.putInt(name, v.data);
4315                } else if (v.type == TypedValue.TYPE_FLOAT) {
4316                    data.putFloat(name, v.getFloat());
4317                } else {
4318                    if (!RIGID_PARSER) {
4319                        Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: "
4320                                + parser.getName() + " at " + mArchiveSourcePath + " "
4321                                + parser.getPositionDescription());
4322                    } else {
4323                        outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types";
4324                        data = null;
4325                    }
4326                }
4327            } else {
4328                outError[0] = "<meta-data> requires an android:value or android:resource attribute";
4329                data = null;
4330            }
4331        }
4332
4333        sa.recycle();
4334
4335        XmlUtils.skipCurrentTag(parser);
4336
4337        return data;
4338    }
4339
4340    private static VerifierInfo parseVerifier(Resources res, XmlPullParser parser,
4341            AttributeSet attrs, int flags) {
4342        final TypedArray sa = res.obtainAttributes(attrs,
4343                com.android.internal.R.styleable.AndroidManifestPackageVerifier);
4344
4345        final String packageName = sa.getNonResourceString(
4346                com.android.internal.R.styleable.AndroidManifestPackageVerifier_name);
4347
4348        final String encodedPublicKey = sa.getNonResourceString(
4349                com.android.internal.R.styleable.AndroidManifestPackageVerifier_publicKey);
4350
4351        sa.recycle();
4352
4353        if (packageName == null || packageName.length() == 0) {
4354            Slog.i(TAG, "verifier package name was null; skipping");
4355            return null;
4356        }
4357
4358        final PublicKey publicKey = parsePublicKey(encodedPublicKey);
4359        if (publicKey == null) {
4360            Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
4361            return null;
4362        }
4363
4364        return new VerifierInfo(packageName, publicKey);
4365    }
4366
4367    public static final PublicKey parsePublicKey(final String encodedPublicKey) {
4368        if (encodedPublicKey == null) {
4369            Slog.w(TAG, "Could not parse null public key");
4370            return null;
4371        }
4372
4373        EncodedKeySpec keySpec;
4374        try {
4375            final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT);
4376            keySpec = new X509EncodedKeySpec(encoded);
4377        } catch (IllegalArgumentException e) {
4378            Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
4379            return null;
4380        }
4381
4382        /* First try the key as an RSA key. */
4383        try {
4384            final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
4385            return keyFactory.generatePublic(keySpec);
4386        } catch (NoSuchAlgorithmException e) {
4387            Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build");
4388        } catch (InvalidKeySpecException e) {
4389            // Not a RSA public key.
4390        }
4391
4392        /* Now try it as a ECDSA key. */
4393        try {
4394            final KeyFactory keyFactory = KeyFactory.getInstance("EC");
4395            return keyFactory.generatePublic(keySpec);
4396        } catch (NoSuchAlgorithmException e) {
4397            Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build");
4398        } catch (InvalidKeySpecException e) {
4399            // Not a ECDSA public key.
4400        }
4401
4402        /* Now try it as a DSA key. */
4403        try {
4404            final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
4405            return keyFactory.generatePublic(keySpec);
4406        } catch (NoSuchAlgorithmException e) {
4407            Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build");
4408        } catch (InvalidKeySpecException e) {
4409            // Not a DSA public key.
4410        }
4411
4412        /* Not a supported key type */
4413        return null;
4414    }
4415
4416    private static final String ANDROID_RESOURCES
4417            = "http://schemas.android.com/apk/res/android";
4418
4419    private boolean parseIntent(Resources res, XmlResourceParser parser,
4420            boolean allowGlobs, boolean allowAutoVerify, IntentInfo outInfo, String[] outError)
4421            throws XmlPullParserException, IOException {
4422
4423        TypedArray sa = res.obtainAttributes(parser,
4424                com.android.internal.R.styleable.AndroidManifestIntentFilter);
4425
4426        int priority = sa.getInt(
4427                com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
4428        outInfo.setPriority(priority);
4429
4430        TypedValue v = sa.peekValue(
4431                com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
4432        if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
4433            outInfo.nonLocalizedLabel = v.coerceToString();
4434        }
4435
4436        outInfo.icon = sa.getResourceId(
4437                com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
4438
4439        outInfo.logo = sa.getResourceId(
4440                com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
4441
4442        outInfo.banner = sa.getResourceId(
4443                com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0);
4444
4445        if (allowAutoVerify) {
4446            outInfo.setAutoVerify(sa.getBoolean(
4447                    com.android.internal.R.styleable.AndroidManifestIntentFilter_autoVerify,
4448                    false));
4449        }
4450
4451        sa.recycle();
4452
4453        int outerDepth = parser.getDepth();
4454        int type;
4455        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4456                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4457            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4458                continue;
4459            }
4460
4461            String nodeName = parser.getName();
4462            if (nodeName.equals("action")) {
4463                String value = parser.getAttributeValue(
4464                        ANDROID_RESOURCES, "name");
4465                if (value == null || value == "") {
4466                    outError[0] = "No value supplied for <android:name>";
4467                    return false;
4468                }
4469                XmlUtils.skipCurrentTag(parser);
4470
4471                outInfo.addAction(value);
4472            } else if (nodeName.equals("category")) {
4473                String value = parser.getAttributeValue(
4474                        ANDROID_RESOURCES, "name");
4475                if (value == null || value == "") {
4476                    outError[0] = "No value supplied for <android:name>";
4477                    return false;
4478                }
4479                XmlUtils.skipCurrentTag(parser);
4480
4481                outInfo.addCategory(value);
4482
4483            } else if (nodeName.equals("data")) {
4484                sa = res.obtainAttributes(parser,
4485                        com.android.internal.R.styleable.AndroidManifestData);
4486
4487                String str = sa.getNonConfigurationString(
4488                        com.android.internal.R.styleable.AndroidManifestData_mimeType, 0);
4489                if (str != null) {
4490                    try {
4491                        outInfo.addDataType(str);
4492                    } catch (IntentFilter.MalformedMimeTypeException e) {
4493                        outError[0] = e.toString();
4494                        sa.recycle();
4495                        return false;
4496                    }
4497                }
4498
4499                str = sa.getNonConfigurationString(
4500                        com.android.internal.R.styleable.AndroidManifestData_scheme, 0);
4501                if (str != null) {
4502                    outInfo.addDataScheme(str);
4503                }
4504
4505                str = sa.getNonConfigurationString(
4506                        com.android.internal.R.styleable.AndroidManifestData_ssp, 0);
4507                if (str != null) {
4508                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
4509                }
4510
4511                str = sa.getNonConfigurationString(
4512                        com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0);
4513                if (str != null) {
4514                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
4515                }
4516
4517                str = sa.getNonConfigurationString(
4518                        com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0);
4519                if (str != null) {
4520                    if (!allowGlobs) {
4521                        outError[0] = "sspPattern not allowed here; ssp must be literal";
4522                        return false;
4523                    }
4524                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
4525                }
4526
4527                String host = sa.getNonConfigurationString(
4528                        com.android.internal.R.styleable.AndroidManifestData_host, 0);
4529                String port = sa.getNonConfigurationString(
4530                        com.android.internal.R.styleable.AndroidManifestData_port, 0);
4531                if (host != null) {
4532                    outInfo.addDataAuthority(host, port);
4533                }
4534
4535                str = sa.getNonConfigurationString(
4536                        com.android.internal.R.styleable.AndroidManifestData_path, 0);
4537                if (str != null) {
4538                    outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
4539                }
4540
4541                str = sa.getNonConfigurationString(
4542                        com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0);
4543                if (str != null) {
4544                    outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
4545                }
4546
4547                str = sa.getNonConfigurationString(
4548                        com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
4549                if (str != null) {
4550                    if (!allowGlobs) {
4551                        outError[0] = "pathPattern not allowed here; path must be literal";
4552                        return false;
4553                    }
4554                    outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
4555                }
4556
4557                sa.recycle();
4558                XmlUtils.skipCurrentTag(parser);
4559            } else if (!RIGID_PARSER) {
4560                Slog.w(TAG, "Unknown element under <intent-filter>: "
4561                        + parser.getName() + " at " + mArchiveSourcePath + " "
4562                        + parser.getPositionDescription());
4563                XmlUtils.skipCurrentTag(parser);
4564            } else {
4565                outError[0] = "Bad element under <intent-filter>: " + parser.getName();
4566                return false;
4567            }
4568        }
4569
4570        outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
4571
4572        if (DEBUG_PARSER) {
4573            final StringBuilder cats = new StringBuilder("Intent d=");
4574            cats.append(outInfo.hasDefault);
4575            cats.append(", cat=");
4576
4577            final Iterator<String> it = outInfo.categoriesIterator();
4578            if (it != null) {
4579                while (it.hasNext()) {
4580                    cats.append(' ');
4581                    cats.append(it.next());
4582                }
4583            }
4584            Slog.d(TAG, cats.toString());
4585        }
4586
4587        return true;
4588    }
4589
4590    /**
4591     * Representation of a full package parsed from APK files on disk. A package
4592     * consists of a single base APK, and zero or more split APKs.
4593     */
4594    public final static class Package {
4595
4596        public String packageName;
4597
4598        /** Names of any split APKs, ordered by parsed splitName */
4599        public String[] splitNames;
4600
4601        // TODO: work towards making these paths invariant
4602
4603        public String volumeUuid;
4604
4605        /**
4606         * Path where this package was found on disk. For monolithic packages
4607         * this is path to single base APK file; for cluster packages this is
4608         * path to the cluster directory.
4609         */
4610        public String codePath;
4611
4612        /** Path of base APK */
4613        public String baseCodePath;
4614        /** Paths of any split APKs, ordered by parsed splitName */
4615        public String[] splitCodePaths;
4616
4617        /** Revision code of base APK */
4618        public int baseRevisionCode;
4619        /** Revision codes of any split APKs, ordered by parsed splitName */
4620        public int[] splitRevisionCodes;
4621
4622        /** Flags of any split APKs; ordered by parsed splitName */
4623        public int[] splitFlags;
4624
4625        /**
4626         * Private flags of any split APKs; ordered by parsed splitName.
4627         *
4628         * {@hide}
4629         */
4630        public int[] splitPrivateFlags;
4631
4632        public boolean baseHardwareAccelerated;
4633
4634        // For now we only support one application per package.
4635        public final ApplicationInfo applicationInfo = new ApplicationInfo();
4636
4637        public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
4638        public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
4639        public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
4640        public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
4641        public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
4642        public final ArrayList<Service> services = new ArrayList<Service>(0);
4643        public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
4644
4645        public final ArrayList<String> requestedPermissions = new ArrayList<String>();
4646
4647        public ArrayList<String> protectedBroadcasts;
4648
4649        public Package parentPackage;
4650        public ArrayList<Package> childPackages;
4651
4652        public ArrayList<String> libraryNames = null;
4653        public ArrayList<String> usesLibraries = null;
4654        public ArrayList<String> usesOptionalLibraries = null;
4655        public String[] usesLibraryFiles = null;
4656
4657        public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
4658
4659        public ArrayList<String> mOriginalPackages = null;
4660        public String mRealPackage = null;
4661        public ArrayList<String> mAdoptPermissions = null;
4662
4663        // We store the application meta-data independently to avoid multiple unwanted references
4664        public Bundle mAppMetaData = null;
4665
4666        // The version code declared for this package.
4667        public int mVersionCode;
4668
4669        // The version name declared for this package.
4670        public String mVersionName;
4671
4672        // The shared user id that this package wants to use.
4673        public String mSharedUserId;
4674
4675        // The shared user label that this package wants to use.
4676        public int mSharedUserLabel;
4677
4678        // Signatures that were read from the package.
4679        public Signature[] mSignatures;
4680        public Certificate[][] mCertificates;
4681
4682        // For use by package manager service for quick lookup of
4683        // preferred up order.
4684        public int mPreferredOrder = 0;
4685
4686        // For use by package manager to keep track of where it needs to do dexopt.
4687        public final ArraySet<String> mDexOptPerformed = new ArraySet<>(4);
4688
4689        // For use by package manager to keep track of when a package was last used.
4690        public long mLastPackageUsageTimeInMills;
4691
4692        // // User set enabled state.
4693        // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
4694        //
4695        // // Whether the package has been stopped.
4696        // public boolean mSetStopped = false;
4697
4698        // Additional data supplied by callers.
4699        public Object mExtras;
4700
4701        // Applications hardware preferences
4702        public ArrayList<ConfigurationInfo> configPreferences = null;
4703
4704        // Applications requested features
4705        public ArrayList<FeatureInfo> reqFeatures = null;
4706
4707        // Applications requested feature groups
4708        public ArrayList<FeatureGroupInfo> featureGroups = null;
4709
4710        public int installLocation;
4711
4712        public boolean coreApp;
4713
4714        /* An app that's required for all users and cannot be uninstalled for a user */
4715        public boolean mRequiredForAllUsers;
4716
4717        /* The restricted account authenticator type that is used by this application */
4718        public String mRestrictedAccountType;
4719
4720        /* The required account type without which this application will not function */
4721        public String mRequiredAccountType;
4722
4723        public String mOverlayTarget;
4724        public int mOverlayPriority;
4725        public boolean mTrustedOverlay;
4726
4727        /**
4728         * Data used to feed the KeySetManagerService
4729         */
4730        public ArraySet<PublicKey> mSigningKeys;
4731        public ArraySet<String> mUpgradeKeySets;
4732        public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
4733
4734        /**
4735         * The install time abi override for this package, if any.
4736         *
4737         * TODO: This seems like a horrible place to put the abiOverride because
4738         * this isn't something the packageParser parsers. However, this fits in with
4739         * the rest of the PackageManager where package scanning randomly pushes
4740         * and prods fields out of {@code this.applicationInfo}.
4741         */
4742        public String cpuAbiOverride;
4743
4744        public Package(String packageName) {
4745            this.packageName = packageName;
4746            applicationInfo.packageName = packageName;
4747            applicationInfo.uid = -1;
4748        }
4749
4750        public void setApplicationVolumeUuid(String volumeUuid) {
4751            this.applicationInfo.volumeUuid = volumeUuid;
4752            if (childPackages != null) {
4753                final int packageCount = childPackages.size();
4754                for (int i = 0; i < packageCount; i++) {
4755                    childPackages.get(i).applicationInfo.volumeUuid = volumeUuid;
4756                }
4757            }
4758        }
4759
4760        public void setApplicationInfoCodePath(String codePath) {
4761            this.applicationInfo.setCodePath(codePath);
4762            if (childPackages != null) {
4763                final int packageCount = childPackages.size();
4764                for (int i = 0; i < packageCount; i++) {
4765                    childPackages.get(i).applicationInfo.setCodePath(codePath);
4766                }
4767            }
4768        }
4769
4770        public void setApplicationInfoResourcePath(String resourcePath) {
4771            this.applicationInfo.setResourcePath(resourcePath);
4772            if (childPackages != null) {
4773                final int packageCount = childPackages.size();
4774                for (int i = 0; i < packageCount; i++) {
4775                    childPackages.get(i).applicationInfo.setResourcePath(resourcePath);
4776                }
4777            }
4778        }
4779
4780        public void setApplicationInfoBaseResourcePath(String resourcePath) {
4781            this.applicationInfo.setBaseResourcePath(resourcePath);
4782            if (childPackages != null) {
4783                final int packageCount = childPackages.size();
4784                for (int i = 0; i < packageCount; i++) {
4785                    childPackages.get(i).applicationInfo.setBaseResourcePath(resourcePath);
4786                }
4787            }
4788        }
4789
4790        public void setApplicationInfoBaseCodePath(String baseCodePath) {
4791            this.applicationInfo.setBaseCodePath(baseCodePath);
4792            if (childPackages != null) {
4793                final int packageCount = childPackages.size();
4794                for (int i = 0; i < packageCount; i++) {
4795                    childPackages.get(i).applicationInfo.setBaseCodePath(baseCodePath);
4796                }
4797            }
4798        }
4799
4800        public boolean hasChildPackage(String packageName) {
4801            final int childCount = (childPackages != null) ? childPackages.size() : 0;
4802            for (int i = 0; i < childCount; i++) {
4803                if (childPackages.get(i).packageName.equals(packageName)) {
4804                    return true;
4805                }
4806            }
4807            return false;
4808        }
4809
4810        public void setApplicationInfoSplitCodePaths(String[] splitCodePaths) {
4811            this.applicationInfo.setSplitCodePaths(splitCodePaths);
4812            // Children have no splits
4813        }
4814
4815        public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) {
4816            this.applicationInfo.setSplitResourcePaths(resroucePaths);
4817            // Children have no splits
4818        }
4819
4820        public void setSplitCodePaths(String[] codePaths) {
4821            this.splitCodePaths = codePaths;
4822        }
4823
4824        public void setCodePath(String codePath) {
4825            this.codePath = codePath;
4826            if (childPackages != null) {
4827                final int packageCount = childPackages.size();
4828                for (int i = 0; i < packageCount; i++) {
4829                    childPackages.get(i).codePath = codePath;
4830                }
4831            }
4832        }
4833
4834        public void setBaseCodePath(String baseCodePath) {
4835            this.baseCodePath = baseCodePath;
4836            if (childPackages != null) {
4837                final int packageCount = childPackages.size();
4838                for (int i = 0; i < packageCount; i++) {
4839                    childPackages.get(i).baseCodePath = baseCodePath;
4840                }
4841            }
4842        }
4843
4844        public void setSignatures(Signature[] signatures) {
4845            this.mSignatures = signatures;
4846            if (childPackages != null) {
4847                final int packageCount = childPackages.size();
4848                for (int i = 0; i < packageCount; i++) {
4849                    childPackages.get(i).mSignatures = signatures;
4850                }
4851            }
4852        }
4853
4854        public void setVolumeUuid(String volumeUuid) {
4855            this.volumeUuid = volumeUuid;
4856            if (childPackages != null) {
4857                final int packageCount = childPackages.size();
4858                for (int i = 0; i < packageCount; i++) {
4859                    childPackages.get(i).volumeUuid = volumeUuid;
4860                }
4861            }
4862        }
4863
4864        public void setApplicationInfoFlags(int mask, int flags) {
4865            applicationInfo.flags = (applicationInfo.flags & ~mask) | (mask & flags);
4866            if (childPackages != null) {
4867                final int packageCount = childPackages.size();
4868                for (int i = 0; i < packageCount; i++) {
4869                    childPackages.get(i).applicationInfo.flags =
4870                            (applicationInfo.flags & ~mask) | (mask & flags);
4871                }
4872            }
4873        }
4874
4875        public void setCpuAbiOverride(String cpuAbiOverride) {
4876            this.cpuAbiOverride = cpuAbiOverride;
4877            if (childPackages != null) {
4878                final int packageCount = childPackages.size();
4879                for (int i = 0; i < packageCount; i++) {
4880                    childPackages.get(i).cpuAbiOverride = cpuAbiOverride;
4881                }
4882            }
4883        }
4884
4885        public List<String> getAllCodePaths() {
4886            ArrayList<String> paths = new ArrayList<>();
4887            paths.add(baseCodePath);
4888            if (!ArrayUtils.isEmpty(splitCodePaths)) {
4889                Collections.addAll(paths, splitCodePaths);
4890            }
4891            return paths;
4892        }
4893
4894        /**
4895         * Filtered set of {@link #getAllCodePaths()} that excludes
4896         * resource-only APKs.
4897         */
4898        public List<String> getAllCodePathsExcludingResourceOnly() {
4899            ArrayList<String> paths = new ArrayList<>();
4900            if ((applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
4901                paths.add(baseCodePath);
4902            }
4903            if (!ArrayUtils.isEmpty(splitCodePaths)) {
4904                for (int i = 0; i < splitCodePaths.length; i++) {
4905                    if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
4906                        paths.add(splitCodePaths[i]);
4907                    }
4908                }
4909            }
4910            return paths;
4911        }
4912
4913        public void setPackageName(String newName) {
4914            packageName = newName;
4915            applicationInfo.packageName = newName;
4916            for (int i=permissions.size()-1; i>=0; i--) {
4917                permissions.get(i).setPackageName(newName);
4918            }
4919            for (int i=permissionGroups.size()-1; i>=0; i--) {
4920                permissionGroups.get(i).setPackageName(newName);
4921            }
4922            for (int i=activities.size()-1; i>=0; i--) {
4923                activities.get(i).setPackageName(newName);
4924            }
4925            for (int i=receivers.size()-1; i>=0; i--) {
4926                receivers.get(i).setPackageName(newName);
4927            }
4928            for (int i=providers.size()-1; i>=0; i--) {
4929                providers.get(i).setPackageName(newName);
4930            }
4931            for (int i=services.size()-1; i>=0; i--) {
4932                services.get(i).setPackageName(newName);
4933            }
4934            for (int i=instrumentation.size()-1; i>=0; i--) {
4935                instrumentation.get(i).setPackageName(newName);
4936            }
4937        }
4938
4939        public boolean hasComponentClassName(String name) {
4940            for (int i=activities.size()-1; i>=0; i--) {
4941                if (name.equals(activities.get(i).className)) {
4942                    return true;
4943                }
4944            }
4945            for (int i=receivers.size()-1; i>=0; i--) {
4946                if (name.equals(receivers.get(i).className)) {
4947                    return true;
4948                }
4949            }
4950            for (int i=providers.size()-1; i>=0; i--) {
4951                if (name.equals(providers.get(i).className)) {
4952                    return true;
4953                }
4954            }
4955            for (int i=services.size()-1; i>=0; i--) {
4956                if (name.equals(services.get(i).className)) {
4957                    return true;
4958                }
4959            }
4960            for (int i=instrumentation.size()-1; i>=0; i--) {
4961                if (name.equals(instrumentation.get(i).className)) {
4962                    return true;
4963                }
4964            }
4965            return false;
4966        }
4967
4968        /**
4969         * @hide
4970         */
4971        public boolean isForwardLocked() {
4972            return applicationInfo.isForwardLocked();
4973        }
4974
4975        /**
4976         * @hide
4977         */
4978        public boolean isSystemApp() {
4979            return applicationInfo.isSystemApp();
4980        }
4981
4982        /**
4983         * @hide
4984         */
4985        public boolean isPrivilegedApp() {
4986            return applicationInfo.isPrivilegedApp();
4987        }
4988
4989        /**
4990         * @hide
4991         */
4992        public boolean isUpdatedSystemApp() {
4993            return applicationInfo.isUpdatedSystemApp();
4994        }
4995
4996        /**
4997         * @hide
4998         */
4999        public boolean canHaveOatDir() {
5000            // The following app types CANNOT have oat directory
5001            // - non-updated system apps
5002            // - forward-locked apps or apps installed in ASEC containers
5003            return (!isSystemApp() || isUpdatedSystemApp())
5004                    && !isForwardLocked() && !applicationInfo.isExternalAsec();
5005        }
5006
5007        public boolean isMatch(int flags) {
5008            if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
5009                return isSystemApp();
5010            }
5011            return true;
5012        }
5013
5014        public String toString() {
5015            return "Package{"
5016                + Integer.toHexString(System.identityHashCode(this))
5017                + " " + packageName + "}";
5018        }
5019    }
5020
5021    public static class Component<II extends IntentInfo> {
5022        public final Package owner;
5023        public final ArrayList<II> intents;
5024        public final String className;
5025        public Bundle metaData;
5026
5027        ComponentName componentName;
5028        String componentShortName;
5029
5030        public Component(Package _owner) {
5031            owner = _owner;
5032            intents = null;
5033            className = null;
5034        }
5035
5036        public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
5037            owner = args.owner;
5038            intents = new ArrayList<II>(0);
5039            String name = args.sa.getNonConfigurationString(args.nameRes, 0);
5040            if (name == null) {
5041                className = null;
5042                args.outError[0] = args.tag + " does not specify android:name";
5043                return;
5044            }
5045
5046            outInfo.name
5047                = buildClassName(owner.applicationInfo.packageName, name, args.outError);
5048            if (outInfo.name == null) {
5049                className = null;
5050                args.outError[0] = args.tag + " does not have valid android:name";
5051                return;
5052            }
5053
5054            className = outInfo.name;
5055
5056            int iconVal = args.sa.getResourceId(args.iconRes, 0);
5057            if (iconVal != 0) {
5058                outInfo.icon = iconVal;
5059                outInfo.nonLocalizedLabel = null;
5060            }
5061
5062            int logoVal = args.sa.getResourceId(args.logoRes, 0);
5063            if (logoVal != 0) {
5064                outInfo.logo = logoVal;
5065            }
5066
5067            int bannerVal = args.sa.getResourceId(args.bannerRes, 0);
5068            if (bannerVal != 0) {
5069                outInfo.banner = bannerVal;
5070            }
5071
5072            TypedValue v = args.sa.peekValue(args.labelRes);
5073            if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
5074                outInfo.nonLocalizedLabel = v.coerceToString();
5075            }
5076
5077            outInfo.packageName = owner.packageName;
5078        }
5079
5080        public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
5081            this(args, (PackageItemInfo)outInfo);
5082            if (args.outError[0] != null) {
5083                return;
5084            }
5085
5086            if (args.processRes != 0) {
5087                CharSequence pname;
5088                if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
5089                    pname = args.sa.getNonConfigurationString(args.processRes,
5090                            Configuration.NATIVE_CONFIG_VERSION);
5091                } else {
5092                    // Some older apps have been seen to use a resource reference
5093                    // here that on older builds was ignored (with a warning).  We
5094                    // need to continue to do this for them so they don't break.
5095                    pname = args.sa.getNonResourceString(args.processRes);
5096                }
5097                outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
5098                        owner.applicationInfo.processName, pname,
5099                        args.flags, args.sepProcesses, args.outError);
5100            }
5101
5102            if (args.descriptionRes != 0) {
5103                outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
5104            }
5105
5106            outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
5107        }
5108
5109        public Component(Component<II> clone) {
5110            owner = clone.owner;
5111            intents = clone.intents;
5112            className = clone.className;
5113            componentName = clone.componentName;
5114            componentShortName = clone.componentShortName;
5115        }
5116
5117        public ComponentName getComponentName() {
5118            if (componentName != null) {
5119                return componentName;
5120            }
5121            if (className != null) {
5122                componentName = new ComponentName(owner.applicationInfo.packageName,
5123                        className);
5124            }
5125            return componentName;
5126        }
5127
5128        public void appendComponentShortName(StringBuilder sb) {
5129            ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className);
5130        }
5131
5132        public void printComponentShortName(PrintWriter pw) {
5133            ComponentName.printShortString(pw, owner.applicationInfo.packageName, className);
5134        }
5135
5136        public void setPackageName(String packageName) {
5137            componentName = null;
5138            componentShortName = null;
5139        }
5140    }
5141
5142    public final static class Permission extends Component<IntentInfo> {
5143        public final PermissionInfo info;
5144        public boolean tree;
5145        public PermissionGroup group;
5146
5147        public Permission(Package _owner) {
5148            super(_owner);
5149            info = new PermissionInfo();
5150        }
5151
5152        public Permission(Package _owner, PermissionInfo _info) {
5153            super(_owner);
5154            info = _info;
5155        }
5156
5157        public void setPackageName(String packageName) {
5158            super.setPackageName(packageName);
5159            info.packageName = packageName;
5160        }
5161
5162        public String toString() {
5163            return "Permission{"
5164                + Integer.toHexString(System.identityHashCode(this))
5165                + " " + info.name + "}";
5166        }
5167    }
5168
5169    public final static class PermissionGroup extends Component<IntentInfo> {
5170        public final PermissionGroupInfo info;
5171
5172        public PermissionGroup(Package _owner) {
5173            super(_owner);
5174            info = new PermissionGroupInfo();
5175        }
5176
5177        public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
5178            super(_owner);
5179            info = _info;
5180        }
5181
5182        public void setPackageName(String packageName) {
5183            super.setPackageName(packageName);
5184            info.packageName = packageName;
5185        }
5186
5187        public String toString() {
5188            return "PermissionGroup{"
5189                + Integer.toHexString(System.identityHashCode(this))
5190                + " " + info.name + "}";
5191        }
5192    }
5193
5194    private static boolean copyNeeded(int flags, Package p,
5195            PackageUserState state, Bundle metaData, int userId) {
5196        if (userId != UserHandle.USER_SYSTEM) {
5197            // We always need to copy for other users, since we need
5198            // to fix up the uid.
5199            return true;
5200        }
5201        if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
5202            boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
5203            if (p.applicationInfo.enabled != enabled) {
5204                return true;
5205            }
5206        }
5207        if (!state.installed || state.hidden) {
5208            return true;
5209        }
5210        if (state.stopped) {
5211            return true;
5212        }
5213        if ((flags & PackageManager.GET_META_DATA) != 0
5214                && (metaData != null || p.mAppMetaData != null)) {
5215            return true;
5216        }
5217        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
5218                && p.usesLibraryFiles != null) {
5219            return true;
5220        }
5221        return false;
5222    }
5223
5224    public static ApplicationInfo generateApplicationInfo(Package p, int flags,
5225            PackageUserState state) {
5226        return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
5227    }
5228
5229    private static void updateApplicationInfo(ApplicationInfo ai, int flags,
5230            PackageUserState state) {
5231        // CompatibilityMode is global state.
5232        if (!sCompatibilityModeEnabled) {
5233            ai.disableCompatibilityMode();
5234        }
5235        if (state.installed) {
5236            ai.flags |= ApplicationInfo.FLAG_INSTALLED;
5237        } else {
5238            ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
5239        }
5240        if (state.suspended) {
5241            ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
5242        } else {
5243            ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
5244        }
5245        if (state.hidden) {
5246            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
5247        } else {
5248            ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
5249        }
5250        if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
5251            ai.enabled = true;
5252        } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
5253            ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
5254        } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
5255                || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
5256            ai.enabled = false;
5257        }
5258        ai.enabledSetting = state.enabled;
5259    }
5260
5261    public static ApplicationInfo generateApplicationInfo(Package p, int flags,
5262            PackageUserState state, int userId) {
5263        if (p == null) return null;
5264        if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) {
5265            return null;
5266        }
5267        if (!copyNeeded(flags, p, state, null, userId)
5268                && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0
5269                        || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
5270            // In this case it is safe to directly modify the internal ApplicationInfo state:
5271            // - CompatibilityMode is global state, so will be the same for every call.
5272            // - We only come in to here if the app should reported as installed; this is the
5273            // default state, and we will do a copy otherwise.
5274            // - The enable state will always be reported the same for the application across
5275            // calls; the only exception is for the UNTIL_USED mode, and in that case we will
5276            // be doing a copy.
5277            updateApplicationInfo(p.applicationInfo, flags, state);
5278            return p.applicationInfo;
5279        }
5280
5281        // Make shallow copy so we can store the metadata/libraries safely
5282        ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
5283        ai.initForUser(userId);
5284        if ((flags & PackageManager.GET_META_DATA) != 0) {
5285            ai.metaData = p.mAppMetaData;
5286        }
5287        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
5288            ai.sharedLibraryFiles = p.usesLibraryFiles;
5289        }
5290        if (state.stopped) {
5291            ai.flags |= ApplicationInfo.FLAG_STOPPED;
5292        } else {
5293            ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
5294        }
5295        updateApplicationInfo(ai, flags, state);
5296        return ai;
5297    }
5298
5299    public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags,
5300            PackageUserState state, int userId) {
5301        if (ai == null) return null;
5302        if (!checkUseInstalledOrHidden(flags, state)) {
5303            return null;
5304        }
5305        // This is only used to return the ResolverActivity; we will just always
5306        // make a copy.
5307        ai = new ApplicationInfo(ai);
5308        ai.initForUser(userId);
5309        if (state.stopped) {
5310            ai.flags |= ApplicationInfo.FLAG_STOPPED;
5311        } else {
5312            ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
5313        }
5314        updateApplicationInfo(ai, flags, state);
5315        return ai;
5316    }
5317
5318    public static final PermissionInfo generatePermissionInfo(
5319            Permission p, int flags) {
5320        if (p == null) return null;
5321        if ((flags&PackageManager.GET_META_DATA) == 0) {
5322            return p.info;
5323        }
5324        PermissionInfo pi = new PermissionInfo(p.info);
5325        pi.metaData = p.metaData;
5326        return pi;
5327    }
5328
5329    public static final PermissionGroupInfo generatePermissionGroupInfo(
5330            PermissionGroup pg, int flags) {
5331        if (pg == null) return null;
5332        if ((flags&PackageManager.GET_META_DATA) == 0) {
5333            return pg.info;
5334        }
5335        PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);
5336        pgi.metaData = pg.metaData;
5337        return pgi;
5338    }
5339
5340    public final static class Activity extends Component<ActivityIntentInfo> {
5341        public final ActivityInfo info;
5342
5343        public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
5344            super(args, _info);
5345            info = _info;
5346            info.applicationInfo = args.owner.applicationInfo;
5347        }
5348
5349        public void setPackageName(String packageName) {
5350            super.setPackageName(packageName);
5351            info.packageName = packageName;
5352        }
5353
5354        public String toString() {
5355            StringBuilder sb = new StringBuilder(128);
5356            sb.append("Activity{");
5357            sb.append(Integer.toHexString(System.identityHashCode(this)));
5358            sb.append(' ');
5359            appendComponentShortName(sb);
5360            sb.append('}');
5361            return sb.toString();
5362        }
5363    }
5364
5365    public static final ActivityInfo generateActivityInfo(Activity a, int flags,
5366            PackageUserState state, int userId) {
5367        if (a == null) return null;
5368        if (!checkUseInstalledOrHidden(flags, state)) {
5369            return null;
5370        }
5371        if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
5372            return a.info;
5373        }
5374        // Make shallow copies so we can store the metadata safely
5375        ActivityInfo ai = new ActivityInfo(a.info);
5376        ai.metaData = a.metaData;
5377        ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);
5378        return ai;
5379    }
5380
5381    public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags,
5382            PackageUserState state, int userId) {
5383        if (ai == null) return null;
5384        if (!checkUseInstalledOrHidden(flags, state)) {
5385            return null;
5386        }
5387        // This is only used to return the ResolverActivity; we will just always
5388        // make a copy.
5389        ai = new ActivityInfo(ai);
5390        ai.applicationInfo = generateApplicationInfo(ai.applicationInfo, flags, state, userId);
5391        return ai;
5392    }
5393
5394    public final static class Service extends Component<ServiceIntentInfo> {
5395        public final ServiceInfo info;
5396
5397        public Service(final ParseComponentArgs args, final ServiceInfo _info) {
5398            super(args, _info);
5399            info = _info;
5400            info.applicationInfo = args.owner.applicationInfo;
5401        }
5402
5403        public void setPackageName(String packageName) {
5404            super.setPackageName(packageName);
5405            info.packageName = packageName;
5406        }
5407
5408        public String toString() {
5409            StringBuilder sb = new StringBuilder(128);
5410            sb.append("Service{");
5411            sb.append(Integer.toHexString(System.identityHashCode(this)));
5412            sb.append(' ');
5413            appendComponentShortName(sb);
5414            sb.append('}');
5415            return sb.toString();
5416        }
5417    }
5418
5419    public static final ServiceInfo generateServiceInfo(Service s, int flags,
5420            PackageUserState state, int userId) {
5421        if (s == null) return null;
5422        if (!checkUseInstalledOrHidden(flags, state)) {
5423            return null;
5424        }
5425        if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
5426            return s.info;
5427        }
5428        // Make shallow copies so we can store the metadata safely
5429        ServiceInfo si = new ServiceInfo(s.info);
5430        si.metaData = s.metaData;
5431        si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId);
5432        return si;
5433    }
5434
5435    public final static class Provider extends Component<ProviderIntentInfo> {
5436        public final ProviderInfo info;
5437        public boolean syncable;
5438
5439        public Provider(final ParseComponentArgs args, final ProviderInfo _info) {
5440            super(args, _info);
5441            info = _info;
5442            info.applicationInfo = args.owner.applicationInfo;
5443            syncable = false;
5444        }
5445
5446        public Provider(Provider existingProvider) {
5447            super(existingProvider);
5448            this.info = existingProvider.info;
5449            this.syncable = existingProvider.syncable;
5450        }
5451
5452        public void setPackageName(String packageName) {
5453            super.setPackageName(packageName);
5454            info.packageName = packageName;
5455        }
5456
5457        public String toString() {
5458            StringBuilder sb = new StringBuilder(128);
5459            sb.append("Provider{");
5460            sb.append(Integer.toHexString(System.identityHashCode(this)));
5461            sb.append(' ');
5462            appendComponentShortName(sb);
5463            sb.append('}');
5464            return sb.toString();
5465        }
5466    }
5467
5468    public static final ProviderInfo generateProviderInfo(Provider p, int flags,
5469            PackageUserState state, int userId) {
5470        if (p == null) return null;
5471        if (!checkUseInstalledOrHidden(flags, state)) {
5472            return null;
5473        }
5474        if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
5475                && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
5476                        || p.info.uriPermissionPatterns == null)) {
5477            return p.info;
5478        }
5479        // Make shallow copies so we can store the metadata safely
5480        ProviderInfo pi = new ProviderInfo(p.info);
5481        pi.metaData = p.metaData;
5482        if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
5483            pi.uriPermissionPatterns = null;
5484        }
5485        pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId);
5486        return pi;
5487    }
5488
5489    public final static class Instrumentation extends Component {
5490        public final InstrumentationInfo info;
5491
5492        public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
5493            super(args, _info);
5494            info = _info;
5495        }
5496
5497        public void setPackageName(String packageName) {
5498            super.setPackageName(packageName);
5499            info.packageName = packageName;
5500        }
5501
5502        public String toString() {
5503            StringBuilder sb = new StringBuilder(128);
5504            sb.append("Instrumentation{");
5505            sb.append(Integer.toHexString(System.identityHashCode(this)));
5506            sb.append(' ');
5507            appendComponentShortName(sb);
5508            sb.append('}');
5509            return sb.toString();
5510        }
5511    }
5512
5513    public static final InstrumentationInfo generateInstrumentationInfo(
5514            Instrumentation i, int flags) {
5515        if (i == null) return null;
5516        if ((flags&PackageManager.GET_META_DATA) == 0) {
5517            return i.info;
5518        }
5519        InstrumentationInfo ii = new InstrumentationInfo(i.info);
5520        ii.metaData = i.metaData;
5521        return ii;
5522    }
5523
5524    public static class IntentInfo extends IntentFilter {
5525        public boolean hasDefault;
5526        public int labelRes;
5527        public CharSequence nonLocalizedLabel;
5528        public int icon;
5529        public int logo;
5530        public int banner;
5531        public int preferred;
5532    }
5533
5534    public final static class ActivityIntentInfo extends IntentInfo {
5535        public final Activity activity;
5536
5537        public ActivityIntentInfo(Activity _activity) {
5538            activity = _activity;
5539        }
5540
5541        public String toString() {
5542            StringBuilder sb = new StringBuilder(128);
5543            sb.append("ActivityIntentInfo{");
5544            sb.append(Integer.toHexString(System.identityHashCode(this)));
5545            sb.append(' ');
5546            activity.appendComponentShortName(sb);
5547            sb.append('}');
5548            return sb.toString();
5549        }
5550    }
5551
5552    public final static class ServiceIntentInfo extends IntentInfo {
5553        public final Service service;
5554
5555        public ServiceIntentInfo(Service _service) {
5556            service = _service;
5557        }
5558
5559        public String toString() {
5560            StringBuilder sb = new StringBuilder(128);
5561            sb.append("ServiceIntentInfo{");
5562            sb.append(Integer.toHexString(System.identityHashCode(this)));
5563            sb.append(' ');
5564            service.appendComponentShortName(sb);
5565            sb.append('}');
5566            return sb.toString();
5567        }
5568    }
5569
5570    public static final class ProviderIntentInfo extends IntentInfo {
5571        public final Provider provider;
5572
5573        public ProviderIntentInfo(Provider provider) {
5574            this.provider = provider;
5575        }
5576
5577        public String toString() {
5578            StringBuilder sb = new StringBuilder(128);
5579            sb.append("ProviderIntentInfo{");
5580            sb.append(Integer.toHexString(System.identityHashCode(this)));
5581            sb.append(' ');
5582            provider.appendComponentShortName(sb);
5583            sb.append('}');
5584            return sb.toString();
5585        }
5586    }
5587
5588    /**
5589     * @hide
5590     */
5591    public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
5592        sCompatibilityModeEnabled = compatibilityModeEnabled;
5593    }
5594
5595    private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>();
5596
5597    public static long readFullyIgnoringContents(InputStream in) throws IOException {
5598        byte[] buffer = sBuffer.getAndSet(null);
5599        if (buffer == null) {
5600            buffer = new byte[4096];
5601        }
5602
5603        int n = 0;
5604        int count = 0;
5605        while ((n = in.read(buffer, 0, buffer.length)) != -1) {
5606            count += n;
5607        }
5608
5609        sBuffer.set(buffer);
5610        return count;
5611    }
5612
5613    public static void closeQuietly(StrictJarFile jarFile) {
5614        if (jarFile != null) {
5615            try {
5616                jarFile.close();
5617            } catch (Exception ignored) {
5618            }
5619        }
5620    }
5621
5622    public static class PackageParserException extends Exception {
5623        public final int error;
5624
5625        public PackageParserException(int error, String detailMessage) {
5626            super(detailMessage);
5627            this.error = error;
5628        }
5629
5630        public PackageParserException(int error, String detailMessage, Throwable throwable) {
5631            super(detailMessage, throwable);
5632            this.error = error;
5633        }
5634    }
5635}
5636