1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content.pm;
18
19import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
20import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
21import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
22import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
23import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
24import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
25import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
26import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
27import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
28import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
29import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
30import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
31import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
32import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
33import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
34import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
35import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
36import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
37import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
38import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
39import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
40import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
41import static android.os.Build.VERSION_CODES.O;
42import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
43import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
44
45import android.annotation.IntRange;
46import android.annotation.NonNull;
47import android.annotation.Nullable;
48import android.annotation.TestApi;
49import android.app.ActivityManager;
50import android.content.ComponentName;
51import android.content.Intent;
52import android.content.IntentFilter;
53import android.content.pm.split.SplitAssetDependencyLoader;
54import android.content.pm.split.SplitAssetLoader;
55import android.content.pm.split.DefaultSplitAssetLoader;
56import android.content.res.AssetManager;
57import android.content.res.Configuration;
58import android.content.res.Resources;
59import android.content.res.TypedArray;
60import android.content.res.XmlResourceParser;
61import android.os.Build;
62import android.os.Bundle;
63import android.os.FileUtils;
64import android.os.Parcel;
65import android.os.Parcelable;
66import android.os.PatternMatcher;
67import android.os.SystemProperties;
68import android.os.Trace;
69import android.os.UserHandle;
70import android.os.storage.StorageManager;
71import android.system.ErrnoException;
72import android.system.OsConstants;
73import android.system.StructStat;
74import android.text.TextUtils;
75import android.util.ArrayMap;
76import android.util.ArraySet;
77import android.util.AttributeSet;
78import android.util.Base64;
79import android.util.DisplayMetrics;
80import android.util.Log;
81import android.util.Pair;
82import android.util.Slog;
83import android.util.SparseArray;
84import android.util.TypedValue;
85import android.util.apk.ApkSignatureSchemeV2Verifier;
86import android.util.jar.StrictJarFile;
87import android.view.Gravity;
88
89import com.android.internal.R;
90import com.android.internal.annotations.VisibleForTesting;
91import com.android.internal.util.ArrayUtils;
92import com.android.internal.util.XmlUtils;
93
94import libcore.io.IoUtils;
95
96import org.xmlpull.v1.XmlPullParser;
97import org.xmlpull.v1.XmlPullParserException;
98
99import java.io.File;
100import java.io.FileOutputStream;
101import java.io.IOException;
102import java.io.InputStream;
103import java.io.PrintWriter;
104import java.lang.reflect.Constructor;
105import java.security.GeneralSecurityException;
106import java.security.KeyFactory;
107import java.security.NoSuchAlgorithmException;
108import java.security.PublicKey;
109import java.security.cert.Certificate;
110import java.security.cert.CertificateEncodingException;
111import java.security.spec.EncodedKeySpec;
112import java.security.spec.InvalidKeySpecException;
113import java.security.spec.X509EncodedKeySpec;
114import java.util.ArrayList;
115import java.util.Arrays;
116import java.util.Collections;
117import java.util.Comparator;
118import java.util.Iterator;
119import java.util.List;
120import java.util.Set;
121import java.util.UUID;
122import java.util.concurrent.atomic.AtomicReference;
123import java.util.zip.ZipEntry;
124
125/**
126 * Parser for package files (APKs) on disk. This supports apps packaged either
127 * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple
128 * APKs in a single directory.
129 * <p>
130 * Apps packaged as multiple APKs always consist of a single "base" APK (with a
131 * {@code null} split name) and zero or more "split" APKs (with unique split
132 * names). Any subset of those split APKs are a valid install, as long as the
133 * following constraints are met:
134 * <ul>
135 * <li>All APKs must have the exact same package name, version code, and signing
136 * certificates.
137 * <li>All APKs must have unique split names.
138 * <li>All installations must contain a single base APK.
139 * </ul>
140 *
141 * @hide
142 */
143public class PackageParser {
144    private static final boolean DEBUG_JAR = false;
145    private static final boolean DEBUG_PARSER = false;
146    private static final boolean DEBUG_BACKUP = false;
147
148    private static final String PROPERTY_CHILD_PACKAGES_ENABLED =
149            "persist.sys.child_packages_enabled";
150
151    private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
152            SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
153
154    private static final int MAX_PACKAGES_PER_APK = 5;
155
156    public static final int APK_SIGNING_UNKNOWN = 0;
157    public static final int APK_SIGNING_V1 = 1;
158    public static final int APK_SIGNING_V2 = 2;
159
160    private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
161
162    // TODO: switch outError users to PackageParserException
163    // TODO: refactor "codePath" to "apkPath"
164
165    /** File name in an APK for the Android manifest. */
166    private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
167
168    /** Path prefix for apps on expanded storage */
169    private static final String MNT_EXPAND = "/mnt/expand/";
170
171    private static final String TAG_MANIFEST = "manifest";
172    private static final String TAG_APPLICATION = "application";
173    private static final String TAG_PACKAGE_VERIFIER = "package-verifier";
174    private static final String TAG_OVERLAY = "overlay";
175    private static final String TAG_KEY_SETS = "key-sets";
176    private static final String TAG_PERMISSION_GROUP = "permission-group";
177    private static final String TAG_PERMISSION = "permission";
178    private static final String TAG_PERMISSION_TREE = "permission-tree";
179    private static final String TAG_USES_PERMISSION = "uses-permission";
180    private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
181    private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";
182    private static final String TAG_USES_CONFIGURATION = "uses-configuration";
183    private static final String TAG_USES_FEATURE = "uses-feature";
184    private static final String TAG_FEATURE_GROUP = "feature-group";
185    private static final String TAG_USES_SDK = "uses-sdk";
186    private static final String TAG_SUPPORT_SCREENS = "supports-screens";
187    private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";
188    private static final String TAG_INSTRUMENTATION = "instrumentation";
189    private static final String TAG_ORIGINAL_PACKAGE = "original-package";
190    private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
191    private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
192    private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";
193    private static final String TAG_SUPPORTS_INPUT = "supports-input";
194    private static final String TAG_EAT_COMMENT = "eat-comment";
195    private static final String TAG_PACKAGE = "package";
196    private static final String TAG_RESTRICT_UPDATE = "restrict-update";
197    private static final String TAG_USES_SPLIT = "uses-split";
198
199    // [b/36551762] STOPSHIP remove the ability to expose components via meta-data
200    // Temporary workaround; allow meta-data to expose components to instant apps
201    private static final String META_DATA_INSTANT_APPS = "instantapps.clients.allowed";
202
203    /**
204     * Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
205     * @hide
206     */
207    private static final int RECREATE_ON_CONFIG_CHANGES_MASK =
208            ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC;
209
210    // These are the tags supported by child packages
211    private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
212    static {
213        CHILD_PACKAGE_TAGS.add(TAG_APPLICATION);
214        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION);
215        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M);
216        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23);
217        CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION);
218        CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE);
219        CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP);
220        CHILD_PACKAGE_TAGS.add(TAG_USES_SDK);
221        CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS);
222        CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION);
223        CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE);
224        CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS);
225        CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT);
226        CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
227    }
228
229    private static final boolean LOG_UNSAFE_BROADCASTS = false;
230
231    // Set of broadcast actions that are safe for manifest receivers
232    private static final Set<String> SAFE_BROADCASTS = new ArraySet<>();
233    static {
234        SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED);
235    }
236
237    /** @hide */
238    public static class NewPermissionInfo {
239        public final String name;
240        public final int sdkVersion;
241        public final int fileVersion;
242
243        public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {
244            this.name = name;
245            this.sdkVersion = sdkVersion;
246            this.fileVersion = fileVersion;
247        }
248    }
249
250    /** @hide */
251    public static class SplitPermissionInfo {
252        public final String rootPerm;
253        public final String[] newPerms;
254        public final int targetSdk;
255
256        public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
257            this.rootPerm = rootPerm;
258            this.newPerms = newPerms;
259            this.targetSdk = targetSdk;
260        }
261    }
262
263    /**
264     * List of new permissions that have been added since 1.0.
265     * NOTE: These must be declared in SDK version order, with permissions
266     * added to older SDKs appearing before those added to newer SDKs.
267     * If sdkVersion is 0, then this is not a permission that we want to
268     * automatically add to older apps, but we do want to allow it to be
269     * granted during a platform update.
270     * @hide
271     */
272    public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] =
273        new PackageParser.NewPermissionInfo[] {
274            new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
275                    android.os.Build.VERSION_CODES.DONUT, 0),
276            new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE,
277                    android.os.Build.VERSION_CODES.DONUT, 0)
278    };
279
280    /**
281     * List of permissions that have been split into more granular or dependent
282     * permissions.
283     * @hide
284     */
285    public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] =
286        new PackageParser.SplitPermissionInfo[] {
287            // READ_EXTERNAL_STORAGE is always required when an app requests
288            // WRITE_EXTERNAL_STORAGE, because we can't have an app that has
289            // write access without read access.  The hack here with the target
290            // target SDK version ensures that this grant is always done.
291            new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
292                    new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE },
293                    android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1),
294            new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
295                    new String[] { android.Manifest.permission.READ_CALL_LOG },
296                    android.os.Build.VERSION_CODES.JELLY_BEAN),
297            new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
298                    new String[] { android.Manifest.permission.WRITE_CALL_LOG },
299                    android.os.Build.VERSION_CODES.JELLY_BEAN)
300    };
301
302    /**
303     * @deprecated callers should move to explicitly passing around source path.
304     */
305    @Deprecated
306    private String mArchiveSourcePath;
307
308    private String[] mSeparateProcesses;
309    private boolean mOnlyCoreApps;
310    private DisplayMetrics mMetrics;
311    private Callback mCallback;
312    private File mCacheDir;
313
314    private static final int SDK_VERSION = Build.VERSION.SDK_INT;
315    private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
316
317    private int mParseError = PackageManager.INSTALL_SUCCEEDED;
318
319    private static boolean sCompatibilityModeEnabled = true;
320    private static final int PARSE_DEFAULT_INSTALL_LOCATION =
321            PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
322    private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
323
324    static class ParsePackageItemArgs {
325        final Package owner;
326        final String[] outError;
327        final int nameRes;
328        final int labelRes;
329        final int iconRes;
330        final int roundIconRes;
331        final int logoRes;
332        final int bannerRes;
333
334        String tag;
335        TypedArray sa;
336
337        ParsePackageItemArgs(Package _owner, String[] _outError,
338                int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
339                int _bannerRes) {
340            owner = _owner;
341            outError = _outError;
342            nameRes = _nameRes;
343            labelRes = _labelRes;
344            iconRes = _iconRes;
345            logoRes = _logoRes;
346            bannerRes = _bannerRes;
347            roundIconRes = _roundIconRes;
348        }
349    }
350
351    /** @hide */
352    @VisibleForTesting
353    public static class ParseComponentArgs extends ParsePackageItemArgs {
354        final String[] sepProcesses;
355        final int processRes;
356        final int descriptionRes;
357        final int enabledRes;
358        int flags;
359
360        public ParseComponentArgs(Package _owner, String[] _outError,
361                int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
362                int _bannerRes,
363                String[] _sepProcesses, int _processRes,
364                int _descriptionRes, int _enabledRes) {
365            super(_owner, _outError, _nameRes, _labelRes, _iconRes, _roundIconRes, _logoRes,
366                    _bannerRes);
367            sepProcesses = _sepProcesses;
368            processRes = _processRes;
369            descriptionRes = _descriptionRes;
370            enabledRes = _enabledRes;
371        }
372    }
373
374    /**
375     * Lightweight parsed details about a single package.
376     */
377    public static class PackageLite {
378        public final String packageName;
379        public final int versionCode;
380        public final int installLocation;
381        public final VerifierInfo[] verifiers;
382
383        /** Names of any split APKs, ordered by parsed splitName */
384        public final String[] splitNames;
385
386        /** Names of any split APKs that are features. Ordered by splitName */
387        public final boolean[] isFeatureSplits;
388
389        /** Dependencies of any split APKs, ordered by parsed splitName */
390        public final String[] usesSplitNames;
391        public final String[] configForSplit;
392
393        /**
394         * Path where this package was found on disk. For monolithic packages
395         * this is path to single base APK file; for cluster packages this is
396         * path to the cluster directory.
397         */
398        public final String codePath;
399
400        /** Path of base APK */
401        public final String baseCodePath;
402        /** Paths of any split APKs, ordered by parsed splitName */
403        public final String[] splitCodePaths;
404
405        /** Revision code of base APK */
406        public final int baseRevisionCode;
407        /** Revision codes of any split APKs, ordered by parsed splitName */
408        public final int[] splitRevisionCodes;
409
410        public final boolean coreApp;
411        public final boolean debuggable;
412        public final boolean multiArch;
413        public final boolean use32bitAbi;
414        public final boolean extractNativeLibs;
415        public final boolean isolatedSplits;
416
417        public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
418                boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit,
419                String[] splitCodePaths, int[] splitRevisionCodes) {
420            this.packageName = baseApk.packageName;
421            this.versionCode = baseApk.versionCode;
422            this.installLocation = baseApk.installLocation;
423            this.verifiers = baseApk.verifiers;
424            this.splitNames = splitNames;
425            this.isFeatureSplits = isFeatureSplits;
426            this.usesSplitNames = usesSplitNames;
427            this.configForSplit = configForSplit;
428            this.codePath = codePath;
429            this.baseCodePath = baseApk.codePath;
430            this.splitCodePaths = splitCodePaths;
431            this.baseRevisionCode = baseApk.revisionCode;
432            this.splitRevisionCodes = splitRevisionCodes;
433            this.coreApp = baseApk.coreApp;
434            this.debuggable = baseApk.debuggable;
435            this.multiArch = baseApk.multiArch;
436            this.use32bitAbi = baseApk.use32bitAbi;
437            this.extractNativeLibs = baseApk.extractNativeLibs;
438            this.isolatedSplits = baseApk.isolatedSplits;
439        }
440
441        public List<String> getAllCodePaths() {
442            ArrayList<String> paths = new ArrayList<>();
443            paths.add(baseCodePath);
444            if (!ArrayUtils.isEmpty(splitCodePaths)) {
445                Collections.addAll(paths, splitCodePaths);
446            }
447            return paths;
448        }
449    }
450
451    /**
452     * Lightweight parsed details about a single APK file.
453     */
454    public static class ApkLite {
455        public final String codePath;
456        public final String packageName;
457        public final String splitName;
458        public boolean isFeatureSplit;
459        public final String configForSplit;
460        public final String usesSplitName;
461        public final int versionCode;
462        public final int revisionCode;
463        public final int installLocation;
464        public final VerifierInfo[] verifiers;
465        public final Signature[] signatures;
466        public final Certificate[][] certificates;
467        public final boolean coreApp;
468        public final boolean debuggable;
469        public final boolean multiArch;
470        public final boolean use32bitAbi;
471        public final boolean extractNativeLibs;
472        public final boolean isolatedSplits;
473
474        public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
475                String configForSplit, String usesSplitName, int versionCode, int revisionCode,
476                int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
477                Certificate[][] certificates, boolean coreApp, boolean debuggable,
478                boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs,
479                boolean isolatedSplits) {
480            this.codePath = codePath;
481            this.packageName = packageName;
482            this.splitName = splitName;
483            this.isFeatureSplit = isFeatureSplit;
484            this.configForSplit = configForSplit;
485            this.usesSplitName = usesSplitName;
486            this.versionCode = versionCode;
487            this.revisionCode = revisionCode;
488            this.installLocation = installLocation;
489            this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
490            this.signatures = signatures;
491            this.certificates = certificates;
492            this.coreApp = coreApp;
493            this.debuggable = debuggable;
494            this.multiArch = multiArch;
495            this.use32bitAbi = use32bitAbi;
496            this.extractNativeLibs = extractNativeLibs;
497            this.isolatedSplits = isolatedSplits;
498        }
499    }
500
501    private ParsePackageItemArgs mParseInstrumentationArgs;
502    private ParseComponentArgs mParseActivityArgs;
503    private ParseComponentArgs mParseActivityAliasArgs;
504    private ParseComponentArgs mParseServiceArgs;
505    private ParseComponentArgs mParseProviderArgs;
506
507    /** If set to true, we will only allow package files that exactly match
508     *  the DTD.  Otherwise, we try to get as much from the package as we
509     *  can without failing.  This should normally be set to false, to
510     *  support extensions to the DTD in future versions. */
511    private static final boolean RIGID_PARSER = false;
512
513    private static final String TAG = "PackageParser";
514
515    public PackageParser() {
516        mMetrics = new DisplayMetrics();
517        mMetrics.setToDefaults();
518    }
519
520    public void setSeparateProcesses(String[] procs) {
521        mSeparateProcesses = procs;
522    }
523
524    /**
525     * Flag indicating this parser should only consider apps with
526     * {@code coreApp} manifest attribute to be valid apps. This is useful when
527     * creating a minimalist boot environment.
528     */
529    public void setOnlyCoreApps(boolean onlyCoreApps) {
530        mOnlyCoreApps = onlyCoreApps;
531    }
532
533    public void setDisplayMetrics(DisplayMetrics metrics) {
534        mMetrics = metrics;
535    }
536
537    /**
538     * Sets the cache directory for this package parser.
539     */
540    public void setCacheDir(File cacheDir) {
541        mCacheDir = cacheDir;
542    }
543
544    /**
545     * Callback interface for retrieving information that may be needed while parsing
546     * a package.
547     */
548    public interface Callback {
549        boolean hasFeature(String feature);
550        String[] getOverlayPaths(String targetPackageName, String targetPath);
551        String[] getOverlayApks(String targetPackageName);
552    }
553
554    /**
555     * Standard implementation of {@link Callback} on top of the public {@link PackageManager}
556     * class.
557     */
558    public static final class CallbackImpl implements Callback {
559        private final PackageManager mPm;
560
561        public CallbackImpl(PackageManager pm) {
562            mPm = pm;
563        }
564
565        @Override public boolean hasFeature(String feature) {
566            return mPm.hasSystemFeature(feature);
567        }
568
569        @Override public String[] getOverlayPaths(String targetPackageName, String targetPath) {
570            return null;
571        }
572
573        @Override public String[] getOverlayApks(String targetPackageName) {
574            return null;
575        }
576    }
577
578    /**
579     * Set the {@link Callback} that can be used while parsing.
580     */
581    public void setCallback(Callback cb) {
582        mCallback = cb;
583    }
584
585    public static final boolean isApkFile(File file) {
586        return isApkPath(file.getName());
587    }
588
589    public static boolean isApkPath(String path) {
590        return path.endsWith(".apk");
591    }
592
593    /**
594     * Generate and return the {@link PackageInfo} for a parsed package.
595     *
596     * @param p the parsed package.
597     * @param flags indicating which optional information is included.
598     */
599    public static PackageInfo generatePackageInfo(PackageParser.Package p,
600            int gids[], int flags, long firstInstallTime, long lastUpdateTime,
601            Set<String> grantedPermissions, PackageUserState state) {
602
603        return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
604                grantedPermissions, state, UserHandle.getCallingUserId());
605    }
606
607    /**
608     * Returns true if the package is installed and not hidden, or if the caller
609     * explicitly wanted all uninstalled and hidden packages as well.
610     * @param appInfo The applicationInfo of the app being checked.
611     */
612    private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state,
613            ApplicationInfo appInfo) {
614        // If available for the target user, or trying to match uninstalled packages and it's
615        // a system app.
616        return state.isAvailable(flags)
617                || (appInfo != null && appInfo.isSystemApp()
618                        && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0);
619    }
620
621    public static boolean isAvailable(PackageUserState state) {
622        return checkUseInstalledOrHidden(0, state, null);
623    }
624
625    public static PackageInfo generatePackageInfo(PackageParser.Package p,
626            int gids[], int flags, long firstInstallTime, long lastUpdateTime,
627            Set<String> grantedPermissions, PackageUserState state, int userId) {
628        if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
629            return null;
630        }
631        PackageInfo pi = new PackageInfo();
632        pi.packageName = p.packageName;
633        pi.splitNames = p.splitNames;
634        pi.versionCode = p.mVersionCode;
635        pi.baseRevisionCode = p.baseRevisionCode;
636        pi.splitRevisionCodes = p.splitRevisionCodes;
637        pi.versionName = p.mVersionName;
638        pi.sharedUserId = p.mSharedUserId;
639        pi.sharedUserLabel = p.mSharedUserLabel;
640        pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
641        pi.installLocation = p.installLocation;
642        pi.coreApp = p.coreApp;
643        if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0
644                || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
645            pi.requiredForAllUsers = p.mRequiredForAllUsers;
646        }
647        pi.restrictedAccountType = p.mRestrictedAccountType;
648        pi.requiredAccountType = p.mRequiredAccountType;
649        pi.overlayTarget = p.mOverlayTarget;
650        pi.overlayPriority = p.mOverlayPriority;
651        pi.isStaticOverlay = p.mIsStaticOverlay;
652        pi.firstInstallTime = firstInstallTime;
653        pi.lastUpdateTime = lastUpdateTime;
654        if ((flags&PackageManager.GET_GIDS) != 0) {
655            pi.gids = gids;
656        }
657        if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) {
658            int N = p.configPreferences != null ? p.configPreferences.size() : 0;
659            if (N > 0) {
660                pi.configPreferences = new ConfigurationInfo[N];
661                p.configPreferences.toArray(pi.configPreferences);
662            }
663            N = p.reqFeatures != null ? p.reqFeatures.size() : 0;
664            if (N > 0) {
665                pi.reqFeatures = new FeatureInfo[N];
666                p.reqFeatures.toArray(pi.reqFeatures);
667            }
668            N = p.featureGroups != null ? p.featureGroups.size() : 0;
669            if (N > 0) {
670                pi.featureGroups = new FeatureGroupInfo[N];
671                p.featureGroups.toArray(pi.featureGroups);
672            }
673        }
674        if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
675            final int N = p.activities.size();
676            if (N > 0) {
677                int num = 0;
678                final ActivityInfo[] res = new ActivityInfo[N];
679                for (int i = 0; i < N; i++) {
680                    final Activity a = p.activities.get(i);
681                    if (state.isMatch(a.info, flags)) {
682                        res[num++] = generateActivityInfo(a, flags, state, userId);
683                    }
684                }
685                pi.activities = ArrayUtils.trimToSize(res, num);
686            }
687        }
688        if ((flags & PackageManager.GET_RECEIVERS) != 0) {
689            final int N = p.receivers.size();
690            if (N > 0) {
691                int num = 0;
692                final ActivityInfo[] res = new ActivityInfo[N];
693                for (int i = 0; i < N; i++) {
694                    final Activity a = p.receivers.get(i);
695                    if (state.isMatch(a.info, flags)) {
696                        res[num++] = generateActivityInfo(a, flags, state, userId);
697                    }
698                }
699                pi.receivers = ArrayUtils.trimToSize(res, num);
700            }
701        }
702        if ((flags & PackageManager.GET_SERVICES) != 0) {
703            final int N = p.services.size();
704            if (N > 0) {
705                int num = 0;
706                final ServiceInfo[] res = new ServiceInfo[N];
707                for (int i = 0; i < N; i++) {
708                    final Service s = p.services.get(i);
709                    if (state.isMatch(s.info, flags)) {
710                        res[num++] = generateServiceInfo(s, flags, state, userId);
711                    }
712                }
713                pi.services = ArrayUtils.trimToSize(res, num);
714            }
715        }
716        if ((flags & PackageManager.GET_PROVIDERS) != 0) {
717            final int N = p.providers.size();
718            if (N > 0) {
719                int num = 0;
720                final ProviderInfo[] res = new ProviderInfo[N];
721                for (int i = 0; i < N; i++) {
722                    final Provider pr = p.providers.get(i);
723                    if (state.isMatch(pr.info, flags)) {
724                        res[num++] = generateProviderInfo(pr, flags, state, userId);
725                    }
726                }
727                pi.providers = ArrayUtils.trimToSize(res, num);
728            }
729        }
730        if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) {
731            int N = p.instrumentation.size();
732            if (N > 0) {
733                pi.instrumentation = new InstrumentationInfo[N];
734                for (int i=0; i<N; i++) {
735                    pi.instrumentation[i] = generateInstrumentationInfo(
736                            p.instrumentation.get(i), flags);
737                }
738            }
739        }
740        if ((flags&PackageManager.GET_PERMISSIONS) != 0) {
741            int N = p.permissions.size();
742            if (N > 0) {
743                pi.permissions = new PermissionInfo[N];
744                for (int i=0; i<N; i++) {
745                    pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags);
746                }
747            }
748            N = p.requestedPermissions.size();
749            if (N > 0) {
750                pi.requestedPermissions = new String[N];
751                pi.requestedPermissionsFlags = new int[N];
752                for (int i=0; i<N; i++) {
753                    final String perm = p.requestedPermissions.get(i);
754                    pi.requestedPermissions[i] = perm;
755                    // The notion of required permissions is deprecated but for compatibility.
756                    pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
757                    if (grantedPermissions != null && grantedPermissions.contains(perm)) {
758                        pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
759                    }
760                }
761            }
762        }
763        if ((flags&PackageManager.GET_SIGNATURES) != 0) {
764           int N = (p.mSignatures != null) ? p.mSignatures.length : 0;
765           if (N > 0) {
766                pi.signatures = new Signature[N];
767                System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);
768            }
769        }
770        return pi;
771    }
772
773    private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry)
774            throws PackageParserException {
775        InputStream is = null;
776        try {
777            // We must read the stream for the JarEntry to retrieve
778            // its certificates.
779            is = jarFile.getInputStream(entry);
780            readFullyIgnoringContents(is);
781            return jarFile.getCertificateChains(entry);
782        } catch (IOException | RuntimeException e) {
783            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
784                    "Failed reading " + entry.getName() + " in " + jarFile, e);
785        } finally {
786            IoUtils.closeQuietly(is);
787        }
788    }
789
790    public final static int PARSE_IS_SYSTEM = 1<<0;
791    public final static int PARSE_CHATTY = 1<<1;
792    public final static int PARSE_MUST_BE_APK = 1<<2;
793    public final static int PARSE_IGNORE_PROCESSES = 1<<3;
794    public final static int PARSE_FORWARD_LOCK = 1<<4;
795    public final static int PARSE_EXTERNAL_STORAGE = 1<<5;
796    public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
797    public final static int PARSE_IS_PRIVILEGED = 1<<7;
798    public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
799    public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
800    public final static int PARSE_ENFORCE_CODE = 1<<10;
801    /** @deprecated remove when fixing b/34761192 */
802    @Deprecated
803    public final static int PARSE_IS_EPHEMERAL = 1<<11;
804    public final static int PARSE_FORCE_SDK = 1<<12;
805
806    private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
807
808    /**
809     * Used to sort a set of APKs based on their split names, always placing the
810     * base APK (with {@code null} split name) first.
811     */
812    private static class SplitNameComparator implements Comparator<String> {
813        @Override
814        public int compare(String lhs, String rhs) {
815            if (lhs == null) {
816                return -1;
817            } else if (rhs == null) {
818                return 1;
819            } else {
820                return lhs.compareTo(rhs);
821            }
822        }
823    }
824
825    /**
826     * Parse only lightweight details about the package at the given location.
827     * Automatically detects if the package is a monolithic style (single APK
828     * file) or cluster style (directory of APKs).
829     * <p>
830     * This performs sanity checking on cluster style packages, such as
831     * requiring identical package name and version codes, a single base APK,
832     * and unique split names.
833     *
834     * @see PackageParser#parsePackage(File, int)
835     */
836    public static PackageLite parsePackageLite(File packageFile, int flags)
837            throws PackageParserException {
838        if (packageFile.isDirectory()) {
839            return parseClusterPackageLite(packageFile, flags);
840        } else {
841            return parseMonolithicPackageLite(packageFile, flags);
842        }
843    }
844
845    private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)
846            throws PackageParserException {
847        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
848        final ApkLite baseApk = parseApkLite(packageFile, flags);
849        final String packagePath = packageFile.getAbsolutePath();
850        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
851        return new PackageLite(packagePath, baseApk, null, null, null, null, null, null);
852    }
853
854    static PackageLite parseClusterPackageLite(File packageDir, int flags)
855            throws PackageParserException {
856        final File[] files = packageDir.listFiles();
857        if (ArrayUtils.isEmpty(files)) {
858            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
859                    "No packages found in split");
860        }
861
862        String packageName = null;
863        int versionCode = 0;
864
865        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
866        final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
867        for (File file : files) {
868            if (isApkFile(file)) {
869                final ApkLite lite = parseApkLite(file, flags);
870
871                // Assert that all package names and version codes are
872                // consistent with the first one we encounter.
873                if (packageName == null) {
874                    packageName = lite.packageName;
875                    versionCode = lite.versionCode;
876                } else {
877                    if (!packageName.equals(lite.packageName)) {
878                        throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
879                                "Inconsistent package " + lite.packageName + " in " + file
880                                + "; expected " + packageName);
881                    }
882                    if (versionCode != lite.versionCode) {
883                        throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
884                                "Inconsistent version " + lite.versionCode + " in " + file
885                                + "; expected " + versionCode);
886                    }
887                }
888
889                // Assert that each split is defined only once
890                if (apks.put(lite.splitName, lite) != null) {
891                    throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
892                            "Split name " + lite.splitName
893                            + " defined more than once; most recent was " + file);
894                }
895            }
896        }
897        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
898
899        final ApkLite baseApk = apks.remove(null);
900        if (baseApk == null) {
901            throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
902                    "Missing base APK in " + packageDir);
903        }
904
905        // Always apply deterministic ordering based on splitName
906        final int size = apks.size();
907
908        String[] splitNames = null;
909        boolean[] isFeatureSplits = null;
910        String[] usesSplitNames = null;
911        String[] configForSplits = null;
912        String[] splitCodePaths = null;
913        int[] splitRevisionCodes = null;
914        if (size > 0) {
915            splitNames = new String[size];
916            isFeatureSplits = new boolean[size];
917            usesSplitNames = new String[size];
918            configForSplits = new String[size];
919            splitCodePaths = new String[size];
920            splitRevisionCodes = new int[size];
921
922            splitNames = apks.keySet().toArray(splitNames);
923            Arrays.sort(splitNames, sSplitNameComparator);
924
925            for (int i = 0; i < size; i++) {
926                final ApkLite apk = apks.get(splitNames[i]);
927                usesSplitNames[i] = apk.usesSplitName;
928                isFeatureSplits[i] = apk.isFeatureSplit;
929                configForSplits[i] = apk.configForSplit;
930                splitCodePaths[i] = apk.codePath;
931                splitRevisionCodes[i] = apk.revisionCode;
932            }
933        }
934
935        final String codePath = packageDir.getAbsolutePath();
936        return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
937                configForSplits, splitCodePaths, splitRevisionCodes);
938    }
939
940    /**
941     * Parse the package at the given location. Automatically detects if the
942     * package is a monolithic style (single APK file) or cluster style
943     * (directory of APKs).
944     * <p>
945     * This performs sanity checking on cluster style packages, such as
946     * requiring identical package name and version codes, a single base APK,
947     * and unique split names.
948     * <p>
949     * Note that this <em>does not</em> perform signature verification; that
950     * must be done separately in {@link #collectCertificates(Package, int)}.
951     *
952     * If {@code useCaches} is true, the package parser might return a cached
953     * result from a previous parse of the same {@code packageFile} with the same
954     * {@code flags}. Note that this method does not check whether {@code packageFile}
955     * has changed since the last parse, it's up to callers to do so.
956     *
957     * @see #parsePackageLite(File, int)
958     */
959    public Package parsePackage(File packageFile, int flags, boolean useCaches)
960            throws PackageParserException {
961        Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
962        if (parsed != null) {
963            return parsed;
964        }
965
966        if (packageFile.isDirectory()) {
967            parsed = parseClusterPackage(packageFile, flags);
968        } else {
969            parsed = parseMonolithicPackage(packageFile, flags);
970        }
971
972        cacheResult(packageFile, flags, parsed);
973
974        return parsed;
975    }
976
977    /**
978     * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
979     */
980    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
981        return parsePackage(packageFile, flags, false /* useCaches */);
982    }
983
984    /**
985     * Returns the cache key for a specificied {@code packageFile} and {@code flags}.
986     */
987    private String getCacheKey(File packageFile, int flags) {
988        StringBuilder sb = new StringBuilder(packageFile.getName());
989        sb.append('-');
990        sb.append(flags);
991
992        return sb.toString();
993    }
994
995    @VisibleForTesting
996    protected Package fromCacheEntry(byte[] bytes) throws IOException {
997        Parcel p = Parcel.obtain();
998        p.unmarshall(bytes, 0, bytes.length);
999        p.setDataPosition(0);
1000
1001        PackageParser.Package pkg = new PackageParser.Package(p);
1002        p.recycle();
1003
1004        return pkg;
1005    }
1006
1007    @VisibleForTesting
1008    protected byte[] toCacheEntry(Package pkg) throws IOException {
1009        Parcel p = Parcel.obtain();
1010        pkg.writeToParcel(p, 0 /* flags */);
1011        byte[] serialized = p.marshall();
1012        p.recycle();
1013
1014        return serialized;
1015    }
1016
1017    /**
1018     * Given a {@code packageFile} and a {@code cacheFile} returns whether the
1019     * cache file is up to date based on the mod-time of both files.
1020     */
1021    private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
1022        try {
1023            // NOTE: We don't use the File.lastModified API because it has the very
1024            // non-ideal failure mode of returning 0 with no excepions thrown.
1025            // The nio2 Files API is a little better but is considerably more expensive.
1026            final StructStat pkg = android.system.Os.stat(packageFile.getAbsolutePath());
1027            final StructStat cache = android.system.Os.stat(cacheFile.getAbsolutePath());
1028            return pkg.st_mtime < cache.st_mtime;
1029        } catch (ErrnoException ee) {
1030            // The most common reason why stat fails is that a given cache file doesn't
1031            // exist. We ignore that here. It's easy to reason that it's safe to say the
1032            // cache isn't up to date if we see any sort of exception here.
1033            //
1034            // (1) Exception while stating the package file : This should never happen,
1035            // and if it does, we do a full package parse (which is likely to throw the
1036            // same exception).
1037            // (2) Exception while stating the cache file : If the file doesn't exist, the
1038            // cache is obviously out of date. If the file *does* exist, we can't read it.
1039            // We will attempt to delete and recreate it after parsing the package.
1040            if (ee.errno != OsConstants.ENOENT) {
1041                Slog.w("Error while stating package cache : ", ee);
1042            }
1043
1044            return false;
1045        }
1046    }
1047
1048    /**
1049     * Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
1050     * or {@code null} if no cached result exists.
1051     */
1052    private Package getCachedResult(File packageFile, int flags) {
1053        if (mCacheDir == null) {
1054            return null;
1055        }
1056
1057        final String cacheKey = getCacheKey(packageFile, flags);
1058        final File cacheFile = new File(mCacheDir, cacheKey);
1059
1060        // If the cache is not up to date, return null.
1061        if (!isCacheUpToDate(packageFile, cacheFile)) {
1062            return null;
1063        }
1064
1065        try {
1066            final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
1067            Package p = fromCacheEntry(bytes);
1068            if (mCallback != null) {
1069                String[] overlayApks = mCallback.getOverlayApks(p.packageName);
1070                if (overlayApks != null && overlayApks.length > 0) {
1071                    for (String overlayApk : overlayApks) {
1072                        // If a static RRO is updated, return null.
1073                        if (!isCacheUpToDate(new File(overlayApk), cacheFile)) {
1074                            return null;
1075                        }
1076                    }
1077                }
1078            }
1079            return p;
1080        } catch (Exception e) {
1081            Slog.w(TAG, "Error reading package cache: ", e);
1082
1083            // If something went wrong while reading the cache entry, delete the cache file
1084            // so that we regenerate it the next time.
1085            cacheFile.delete();
1086            return null;
1087        }
1088    }
1089
1090    /**
1091     * Caches the parse result for {@code packageFile} with flags {@code flags}.
1092     */
1093    private void cacheResult(File packageFile, int flags, Package parsed) {
1094        if (mCacheDir == null) {
1095            return;
1096        }
1097
1098        final String cacheKey = getCacheKey(packageFile, flags);
1099        final File cacheFile = new File(mCacheDir, cacheKey);
1100
1101        if (cacheFile.exists()) {
1102            if (!cacheFile.delete()) {
1103                Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
1104            }
1105        }
1106
1107        final byte[] cacheEntry;
1108        try {
1109            cacheEntry = toCacheEntry(parsed);
1110        } catch (IOException ioe) {
1111            Slog.e(TAG, "Unable to serialize parsed package for: " + packageFile);
1112            return;
1113        }
1114
1115        if (cacheEntry == null) {
1116            return;
1117        }
1118
1119        try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
1120            fos.write(cacheEntry);
1121        } catch (IOException ioe) {
1122            Slog.w(TAG, "Error writing cache entry.", ioe);
1123            cacheFile.delete();
1124        }
1125    }
1126
1127    /**
1128     * Parse all APKs contained in the given directory, treating them as a
1129     * single package. This also performs sanity checking, such as requiring
1130     * identical package name and version codes, a single base APK, and unique
1131     * split names.
1132     * <p>
1133     * Note that this <em>does not</em> perform signature verification; that
1134     * must be done separately in {@link #collectCertificates(Package, int)}.
1135     */
1136    private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
1137        final PackageLite lite = parseClusterPackageLite(packageDir, 0);
1138        if (mOnlyCoreApps && !lite.coreApp) {
1139            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1140                    "Not a coreApp: " + packageDir);
1141        }
1142
1143        // Build the split dependency tree.
1144        SparseArray<int[]> splitDependencies = null;
1145        final SplitAssetLoader assetLoader;
1146        if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
1147            try {
1148                splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
1149                assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
1150            } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
1151                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
1152            }
1153        } else {
1154            assetLoader = new DefaultSplitAssetLoader(lite, flags);
1155        }
1156
1157        try {
1158            final AssetManager assets = assetLoader.getBaseAssetManager();
1159            final File baseApk = new File(lite.baseCodePath);
1160            final Package pkg = parseBaseApk(baseApk, assets, flags);
1161            if (pkg == null) {
1162                throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
1163                        "Failed to parse base APK: " + baseApk);
1164            }
1165
1166            if (!ArrayUtils.isEmpty(lite.splitNames)) {
1167                final int num = lite.splitNames.length;
1168                pkg.splitNames = lite.splitNames;
1169                pkg.splitCodePaths = lite.splitCodePaths;
1170                pkg.splitRevisionCodes = lite.splitRevisionCodes;
1171                pkg.splitFlags = new int[num];
1172                pkg.splitPrivateFlags = new int[num];
1173                pkg.applicationInfo.splitNames = pkg.splitNames;
1174                pkg.applicationInfo.splitDependencies = splitDependencies;
1175
1176                for (int i = 0; i < num; i++) {
1177                    final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
1178                    parseSplitApk(pkg, i, splitAssets, flags);
1179                }
1180            }
1181
1182            pkg.setCodePath(packageDir.getAbsolutePath());
1183            pkg.setUse32bitAbi(lite.use32bitAbi);
1184            return pkg;
1185        } finally {
1186            IoUtils.closeQuietly(assetLoader);
1187        }
1188    }
1189
1190    /**
1191     * Parse the given APK file, treating it as as a single monolithic package.
1192     * <p>
1193     * Note that this <em>does not</em> perform signature verification; that
1194     * must be done separately in {@link #collectCertificates(Package, int)}.
1195     *
1196     * @deprecated external callers should move to
1197     *             {@link #parsePackage(File, int)}. Eventually this method will
1198     *             be marked private.
1199     */
1200    @Deprecated
1201    public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
1202        final AssetManager assets = newConfiguredAssetManager();
1203        final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
1204        if (mOnlyCoreApps) {
1205            if (!lite.coreApp) {
1206                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1207                        "Not a coreApp: " + apkFile);
1208            }
1209        }
1210
1211        try {
1212            final Package pkg = parseBaseApk(apkFile, assets, flags);
1213            pkg.setCodePath(apkFile.getAbsolutePath());
1214            pkg.setUse32bitAbi(lite.use32bitAbi);
1215            return pkg;
1216        } finally {
1217            IoUtils.closeQuietly(assets);
1218        }
1219    }
1220
1221    private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
1222            throws PackageParserException {
1223        if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
1224            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
1225                    "Invalid package file: " + apkPath);
1226        }
1227
1228        // The AssetManager guarantees uniqueness for asset paths, so if this asset path
1229        // already exists in the AssetManager, addAssetPath will only return the cookie
1230        // assigned to it.
1231        int cookie = assets.addAssetPath(apkPath);
1232        if (cookie == 0) {
1233            throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
1234                    "Failed adding asset path: " + apkPath);
1235        }
1236        return cookie;
1237    }
1238
1239    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
1240            throws PackageParserException {
1241        final String apkPath = apkFile.getAbsolutePath();
1242
1243        String volumeUuid = null;
1244        if (apkPath.startsWith(MNT_EXPAND)) {
1245            final int end = apkPath.indexOf('/', MNT_EXPAND.length());
1246            volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
1247        }
1248
1249        mParseError = PackageManager.INSTALL_SUCCEEDED;
1250        mArchiveSourcePath = apkFile.getAbsolutePath();
1251
1252        if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
1253
1254        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
1255
1256        Resources res = null;
1257        XmlResourceParser parser = null;
1258        try {
1259            res = new Resources(assets, mMetrics, null);
1260            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
1261
1262            final String[] outError = new String[1];
1263            final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
1264            if (pkg == null) {
1265                throw new PackageParserException(mParseError,
1266                        apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
1267            }
1268
1269            pkg.setVolumeUuid(volumeUuid);
1270            pkg.setApplicationVolumeUuid(volumeUuid);
1271            pkg.setBaseCodePath(apkPath);
1272            pkg.setSignatures(null);
1273
1274            return pkg;
1275
1276        } catch (PackageParserException e) {
1277            throw e;
1278        } catch (Exception e) {
1279            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
1280                    "Failed to read manifest from " + apkPath, e);
1281        } finally {
1282            IoUtils.closeQuietly(parser);
1283        }
1284    }
1285
1286    private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags)
1287            throws PackageParserException {
1288        final String apkPath = pkg.splitCodePaths[splitIndex];
1289
1290        mParseError = PackageManager.INSTALL_SUCCEEDED;
1291        mArchiveSourcePath = apkPath;
1292
1293        if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
1294
1295        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
1296
1297        final Resources res;
1298        XmlResourceParser parser = null;
1299        try {
1300            res = new Resources(assets, mMetrics, null);
1301            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1302                    Build.VERSION.RESOURCES_SDK_INT);
1303            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
1304
1305            final String[] outError = new String[1];
1306            pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
1307            if (pkg == null) {
1308                throw new PackageParserException(mParseError,
1309                        apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
1310            }
1311
1312        } catch (PackageParserException e) {
1313            throw e;
1314        } catch (Exception e) {
1315            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
1316                    "Failed to read manifest from " + apkPath, e);
1317        } finally {
1318            IoUtils.closeQuietly(parser);
1319        }
1320    }
1321
1322    /**
1323     * Parse the manifest of a <em>split APK</em>.
1324     * <p>
1325     * Note that split APKs have many more restrictions on what they're capable
1326     * of doing, so many valid features of a base APK have been carefully
1327     * omitted here.
1328     */
1329    private Package parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags,
1330            int splitIndex, String[] outError) throws XmlPullParserException, IOException,
1331            PackageParserException {
1332        AttributeSet attrs = parser;
1333
1334        // We parsed manifest tag earlier; just skip past it
1335        parsePackageSplitNames(parser, attrs);
1336
1337        mParseInstrumentationArgs = null;
1338        mParseActivityArgs = null;
1339        mParseServiceArgs = null;
1340        mParseProviderArgs = null;
1341
1342        int type;
1343
1344        boolean foundApp = false;
1345
1346        int outerDepth = parser.getDepth();
1347        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1348                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1349            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1350                continue;
1351            }
1352
1353            String tagName = parser.getName();
1354            if (tagName.equals(TAG_APPLICATION)) {
1355                if (foundApp) {
1356                    if (RIGID_PARSER) {
1357                        outError[0] = "<manifest> has more than one <application>";
1358                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1359                        return null;
1360                    } else {
1361                        Slog.w(TAG, "<manifest> has more than one <application>");
1362                        XmlUtils.skipCurrentTag(parser);
1363                        continue;
1364                    }
1365                }
1366
1367                foundApp = true;
1368                if (!parseSplitApplication(pkg, res, parser, flags, splitIndex, outError)) {
1369                    return null;
1370                }
1371
1372            } else if (RIGID_PARSER) {
1373                outError[0] = "Bad element under <manifest>: "
1374                    + parser.getName();
1375                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1376                return null;
1377
1378            } else {
1379                Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
1380                        + " at " + mArchiveSourcePath + " "
1381                        + parser.getPositionDescription());
1382                XmlUtils.skipCurrentTag(parser);
1383                continue;
1384            }
1385        }
1386
1387        if (!foundApp) {
1388            outError[0] = "<manifest> does not contain an <application>";
1389            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
1390        }
1391
1392        return pkg;
1393    }
1394
1395    public static int getApkSigningVersion(Package pkg) {
1396        try {
1397            if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) {
1398                return APK_SIGNING_V2;
1399            }
1400            return APK_SIGNING_V1;
1401        } catch (IOException e) {
1402        }
1403        return APK_SIGNING_UNKNOWN;
1404    }
1405
1406    /**
1407     * Populates the correct packages fields with the given certificates.
1408     * <p>
1409     * This is useful when we've already processed the certificates [such as during package
1410     * installation through an installer session]. We don't re-process the archive and
1411     * simply populate the correct fields.
1412     */
1413    public static void populateCertificates(Package pkg, Certificate[][] certificates)
1414            throws PackageParserException {
1415        pkg.mCertificates = null;
1416        pkg.mSignatures = null;
1417        pkg.mSigningKeys = null;
1418
1419        pkg.mCertificates = certificates;
1420        try {
1421            pkg.mSignatures = convertToSignatures(certificates);
1422        } catch (CertificateEncodingException e) {
1423            // certificates weren't encoded properly; something went wrong
1424            throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1425                    "Failed to collect certificates from " + pkg.baseCodePath, e);
1426        }
1427        pkg.mSigningKeys = new ArraySet<>(certificates.length);
1428        for (int i = 0; i < certificates.length; i++) {
1429            Certificate[] signerCerts = certificates[i];
1430            Certificate signerCert = signerCerts[0];
1431            pkg.mSigningKeys.add(signerCert.getPublicKey());
1432        }
1433        // add signatures to child packages
1434        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
1435        for (int i = 0; i < childCount; i++) {
1436            Package childPkg = pkg.childPackages.get(i);
1437            childPkg.mCertificates = pkg.mCertificates;
1438            childPkg.mSignatures = pkg.mSignatures;
1439            childPkg.mSigningKeys = pkg.mSigningKeys;
1440        }
1441    }
1442
1443    /**
1444     * Collect certificates from all the APKs described in the given package,
1445     * populating {@link Package#mSignatures}. Also asserts that all APK
1446     * contents are signed correctly and consistently.
1447     */
1448    public static void collectCertificates(Package pkg, int parseFlags)
1449            throws PackageParserException {
1450        collectCertificatesInternal(pkg, parseFlags);
1451        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
1452        for (int i = 0; i < childCount; i++) {
1453            Package childPkg = pkg.childPackages.get(i);
1454            childPkg.mCertificates = pkg.mCertificates;
1455            childPkg.mSignatures = pkg.mSignatures;
1456            childPkg.mSigningKeys = pkg.mSigningKeys;
1457        }
1458    }
1459
1460    private static void collectCertificatesInternal(Package pkg, int parseFlags)
1461            throws PackageParserException {
1462        pkg.mCertificates = null;
1463        pkg.mSignatures = null;
1464        pkg.mSigningKeys = null;
1465
1466        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
1467        try {
1468            collectCertificates(pkg, new File(pkg.baseCodePath), parseFlags);
1469
1470            if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
1471                for (int i = 0; i < pkg.splitCodePaths.length; i++) {
1472                    collectCertificates(pkg, new File(pkg.splitCodePaths[i]), parseFlags);
1473                }
1474            }
1475        } finally {
1476            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1477        }
1478    }
1479
1480    private static void collectCertificates(Package pkg, File apkFile, int parseFlags)
1481            throws PackageParserException {
1482        final String apkPath = apkFile.getAbsolutePath();
1483
1484        // Try to verify the APK using APK Signature Scheme v2.
1485        boolean verified = false;
1486        {
1487            Certificate[][] allSignersCerts = null;
1488            Signature[] signatures = null;
1489            try {
1490                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2");
1491                allSignersCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
1492                signatures = convertToSignatures(allSignersCerts);
1493                // APK verified using APK Signature Scheme v2.
1494                verified = true;
1495            } catch (ApkSignatureSchemeV2Verifier.SignatureNotFoundException e) {
1496                // No APK Signature Scheme v2 signature found
1497                if ((parseFlags & PARSE_IS_EPHEMERAL) != 0) {
1498                    throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1499                        "No APK Signature Scheme v2 signature in ephemeral package " + apkPath,
1500                        e);
1501                }
1502                // Static shared libraries must use only the V2 signing scheme
1503                if (pkg.applicationInfo.isStaticSharedLibrary()) {
1504                    throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1505                            "Static shared libs must use v2 signature scheme " + apkPath);
1506                }
1507            } catch (Exception e) {
1508                // APK Signature Scheme v2 signature was found but did not verify
1509                throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1510                        "Failed to collect certificates from " + apkPath
1511                                + " using APK Signature Scheme v2",
1512                        e);
1513            } finally {
1514                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1515            }
1516
1517            if (verified) {
1518                if (pkg.mCertificates == null) {
1519                    pkg.mCertificates = allSignersCerts;
1520                    pkg.mSignatures = signatures;
1521                    pkg.mSigningKeys = new ArraySet<>(allSignersCerts.length);
1522                    for (int i = 0; i < allSignersCerts.length; i++) {
1523                        Certificate[] signerCerts = allSignersCerts[i];
1524                        Certificate signerCert = signerCerts[0];
1525                        pkg.mSigningKeys.add(signerCert.getPublicKey());
1526                    }
1527                } else {
1528                    if (!Signature.areExactMatch(pkg.mSignatures, signatures)) {
1529                        throw new PackageParserException(
1530                                INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
1531                                apkPath + " has mismatched certificates");
1532                    }
1533                }
1534                // Not yet done, because we need to confirm that AndroidManifest.xml exists and,
1535                // if requested, that classes.dex exists.
1536            }
1537        }
1538
1539        StrictJarFile jarFile = null;
1540        try {
1541            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
1542            // Ignore signature stripping protections when verifying APKs from system partition.
1543            // For those APKs we only care about extracting signer certificates, and don't care
1544            // about verifying integrity.
1545            boolean signatureSchemeRollbackProtectionsEnforced =
1546                    (parseFlags & PARSE_IS_SYSTEM_DIR) == 0;
1547            jarFile = new StrictJarFile(
1548                    apkPath,
1549                    !verified, // whether to verify JAR signature
1550                    signatureSchemeRollbackProtectionsEnforced);
1551            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1552
1553            // Always verify manifest, regardless of source
1554            final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
1555            if (manifestEntry == null) {
1556                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
1557                        "Package " + apkPath + " has no manifest");
1558            }
1559
1560            // Optimization: early termination when APK already verified
1561            if (verified) {
1562                return;
1563            }
1564
1565            // APK's integrity needs to be verified using JAR signature scheme.
1566            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV1");
1567            final List<ZipEntry> toVerify = new ArrayList<>();
1568            toVerify.add(manifestEntry);
1569
1570            // If we're parsing an untrusted package, verify all contents
1571            if ((parseFlags & PARSE_IS_SYSTEM_DIR) == 0) {
1572                final Iterator<ZipEntry> i = jarFile.iterator();
1573                while (i.hasNext()) {
1574                    final ZipEntry entry = i.next();
1575
1576                    if (entry.isDirectory()) continue;
1577
1578                    final String entryName = entry.getName();
1579                    if (entryName.startsWith("META-INF/")) continue;
1580                    if (entryName.equals(ANDROID_MANIFEST_FILENAME)) continue;
1581
1582                    toVerify.add(entry);
1583                }
1584            }
1585
1586            // Verify that entries are signed consistently with the first entry
1587            // we encountered. Note that for splits, certificates may have
1588            // already been populated during an earlier parse of a base APK.
1589            for (ZipEntry entry : toVerify) {
1590                final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
1591                if (ArrayUtils.isEmpty(entryCerts)) {
1592                    throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1593                            "Package " + apkPath + " has no certificates at entry "
1594                            + entry.getName());
1595                }
1596                final Signature[] entrySignatures = convertToSignatures(entryCerts);
1597
1598                if (pkg.mCertificates == null) {
1599                    pkg.mCertificates = entryCerts;
1600                    pkg.mSignatures = entrySignatures;
1601                    pkg.mSigningKeys = new ArraySet<PublicKey>();
1602                    for (int i=0; i < entryCerts.length; i++) {
1603                        pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
1604                    }
1605                } else {
1606                    if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {
1607                        throw new PackageParserException(
1608                                INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath
1609                                        + " has mismatched certificates at entry "
1610                                        + entry.getName());
1611                    }
1612                }
1613            }
1614            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1615        } catch (GeneralSecurityException e) {
1616            throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
1617                    "Failed to collect certificates from " + apkPath, e);
1618        } catch (IOException | RuntimeException e) {
1619            throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1620                    "Failed to collect certificates from " + apkPath, e);
1621        } finally {
1622            closeQuietly(jarFile);
1623        }
1624    }
1625
1626    private static Signature[] convertToSignatures(Certificate[][] certs)
1627            throws CertificateEncodingException {
1628        final Signature[] res = new Signature[certs.length];
1629        for (int i = 0; i < certs.length; i++) {
1630            res[i] = new Signature(certs[i]);
1631        }
1632        return res;
1633    }
1634
1635    private static AssetManager newConfiguredAssetManager() {
1636        AssetManager assetManager = new AssetManager();
1637        assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1638                Build.VERSION.RESOURCES_SDK_INT);
1639        return assetManager;
1640    }
1641
1642    /**
1643     * Utility method that retrieves lightweight details about a single APK
1644     * file, including package name, split name, and install location.
1645     *
1646     * @param apkFile path to a single APK
1647     * @param flags optional parse flags, such as
1648     *            {@link #PARSE_COLLECT_CERTIFICATES}
1649     */
1650    public static ApkLite parseApkLite(File apkFile, int flags)
1651            throws PackageParserException {
1652        final String apkPath = apkFile.getAbsolutePath();
1653
1654        AssetManager assets = null;
1655        XmlResourceParser parser = null;
1656        try {
1657            assets = newConfiguredAssetManager();
1658            int cookie = assets.addAssetPath(apkPath);
1659            if (cookie == 0) {
1660                throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
1661                        "Failed to parse " + apkPath);
1662            }
1663
1664            final DisplayMetrics metrics = new DisplayMetrics();
1665            metrics.setToDefaults();
1666
1667            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
1668
1669            final Signature[] signatures;
1670            final Certificate[][] certificates;
1671            if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
1672                // TODO: factor signature related items out of Package object
1673                final Package tempPkg = new Package((String) null);
1674                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
1675                try {
1676                    collectCertificates(tempPkg, apkFile, flags);
1677                } finally {
1678                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1679                }
1680                signatures = tempPkg.mSignatures;
1681                certificates = tempPkg.mCertificates;
1682            } else {
1683                signatures = null;
1684                certificates = null;
1685            }
1686
1687            final AttributeSet attrs = parser;
1688            return parseApkLite(apkPath, parser, attrs, flags, signatures, certificates);
1689
1690        } catch (XmlPullParserException | IOException | RuntimeException e) {
1691            Slog.w(TAG, "Failed to parse " + apkPath, e);
1692            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
1693                    "Failed to parse " + apkPath, e);
1694        } finally {
1695            IoUtils.closeQuietly(parser);
1696            IoUtils.closeQuietly(assets);
1697        }
1698    }
1699
1700    private static String validateName(String name, boolean requireSeparator,
1701            boolean requireFilename) {
1702        final int N = name.length();
1703        boolean hasSep = false;
1704        boolean front = true;
1705        for (int i=0; i<N; i++) {
1706            final char c = name.charAt(i);
1707            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
1708                front = false;
1709                continue;
1710            }
1711            if (!front) {
1712                if ((c >= '0' && c <= '9') || c == '_') {
1713                    continue;
1714                }
1715            }
1716            if (c == '.') {
1717                hasSep = true;
1718                front = true;
1719                continue;
1720            }
1721            return "bad character '" + c + "'";
1722        }
1723        if (requireFilename && !FileUtils.isValidExtFilename(name)) {
1724            return "Invalid filename";
1725        }
1726        return hasSep || !requireSeparator
1727                ? null : "must have at least one '.' separator";
1728    }
1729
1730    private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
1731            AttributeSet attrs) throws IOException, XmlPullParserException,
1732            PackageParserException {
1733
1734        int type;
1735        while ((type = parser.next()) != XmlPullParser.START_TAG
1736                && type != XmlPullParser.END_DOCUMENT) {
1737        }
1738
1739        if (type != XmlPullParser.START_TAG) {
1740            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1741                    "No start tag found");
1742        }
1743        if (!parser.getName().equals(TAG_MANIFEST)) {
1744            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1745                    "No <manifest> tag");
1746        }
1747
1748        final String packageName = attrs.getAttributeValue(null, "package");
1749        if (!"android".equals(packageName)) {
1750            final String error = validateName(packageName, true, true);
1751            if (error != null) {
1752                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
1753                        "Invalid manifest package: " + error);
1754            }
1755        }
1756
1757        String splitName = attrs.getAttributeValue(null, "split");
1758        if (splitName != null) {
1759            if (splitName.length() == 0) {
1760                splitName = null;
1761            } else {
1762                final String error = validateName(splitName, false, false);
1763                if (error != null) {
1764                    throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
1765                            "Invalid manifest split: " + error);
1766                }
1767            }
1768        }
1769
1770        return Pair.create(packageName.intern(),
1771                (splitName != null) ? splitName.intern() : splitName);
1772    }
1773
1774    private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
1775            int flags, Signature[] signatures, Certificate[][] certificates)
1776            throws IOException, XmlPullParserException, PackageParserException {
1777        final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
1778
1779        int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
1780        int versionCode = 0;
1781        int revisionCode = 0;
1782        boolean coreApp = false;
1783        boolean debuggable = false;
1784        boolean multiArch = false;
1785        boolean use32bitAbi = false;
1786        boolean extractNativeLibs = true;
1787        boolean isolatedSplits = false;
1788        boolean isFeatureSplit = false;
1789        String configForSplit = null;
1790        String usesSplitName = null;
1791
1792        for (int i = 0; i < attrs.getAttributeCount(); i++) {
1793            final String attr = attrs.getAttributeName(i);
1794            if (attr.equals("installLocation")) {
1795                installLocation = attrs.getAttributeIntValue(i,
1796                        PARSE_DEFAULT_INSTALL_LOCATION);
1797            } else if (attr.equals("versionCode")) {
1798                versionCode = attrs.getAttributeIntValue(i, 0);
1799            } else if (attr.equals("revisionCode")) {
1800                revisionCode = attrs.getAttributeIntValue(i, 0);
1801            } else if (attr.equals("coreApp")) {
1802                coreApp = attrs.getAttributeBooleanValue(i, false);
1803            } else if (attr.equals("isolatedSplits")) {
1804                isolatedSplits = attrs.getAttributeBooleanValue(i, false);
1805            } else if (attr.equals("configForSplit")) {
1806                configForSplit = attrs.getAttributeValue(i);
1807            } else if (attr.equals("isFeatureSplit")) {
1808                isFeatureSplit = attrs.getAttributeBooleanValue(i, false);
1809            }
1810        }
1811
1812        // Only search the tree when the tag is directly below <manifest>
1813        int type;
1814        final int searchDepth = parser.getDepth() + 1;
1815
1816        final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
1817        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1818                && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {
1819            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1820                continue;
1821            }
1822
1823            if (parser.getDepth() != searchDepth) {
1824                continue;
1825            }
1826
1827            if (TAG_PACKAGE_VERIFIER.equals(parser.getName())) {
1828                final VerifierInfo verifier = parseVerifier(attrs);
1829                if (verifier != null) {
1830                    verifiers.add(verifier);
1831                }
1832            } else if (TAG_APPLICATION.equals(parser.getName())) {
1833                for (int i = 0; i < attrs.getAttributeCount(); ++i) {
1834                    final String attr = attrs.getAttributeName(i);
1835                    if ("debuggable".equals(attr)) {
1836                        debuggable = attrs.getAttributeBooleanValue(i, false);
1837                    }
1838                    if ("multiArch".equals(attr)) {
1839                        multiArch = attrs.getAttributeBooleanValue(i, false);
1840                    }
1841                    if ("use32bitAbi".equals(attr)) {
1842                        use32bitAbi = attrs.getAttributeBooleanValue(i, false);
1843                    }
1844                    if ("extractNativeLibs".equals(attr)) {
1845                        extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
1846                    }
1847                }
1848            } else if (TAG_USES_SPLIT.equals(parser.getName())) {
1849                if (usesSplitName != null) {
1850                    Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others.");
1851                    continue;
1852                }
1853
1854                usesSplitName = attrs.getAttributeValue(ANDROID_RESOURCES, "name");
1855                if (usesSplitName == null) {
1856                    throw new PackageParserException(
1857                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1858                            "<uses-split> tag requires 'android:name' attribute");
1859                }
1860            }
1861        }
1862
1863        return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
1864                configForSplit, usesSplitName, versionCode, revisionCode, installLocation,
1865                verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi,
1866                extractNativeLibs, isolatedSplits);
1867    }
1868
1869    /**
1870     * Temporary.
1871     */
1872    static public Signature stringToSignature(String str) {
1873        final int N = str.length();
1874        byte[] sig = new byte[N];
1875        for (int i=0; i<N; i++) {
1876            sig[i] = (byte)str.charAt(i);
1877        }
1878        return new Signature(sig);
1879    }
1880
1881    /**
1882     * Parses a child package and adds it to the parent if successful. If you add
1883     * new tags that need to be supported by child packages make sure to add them
1884     * to {@link #CHILD_PACKAGE_TAGS}.
1885     *
1886     * @param parentPkg The parent that contains the child
1887     * @param res Resources against which to resolve values
1888     * @param parser Parser of the manifest
1889     * @param flags Flags about how to parse
1890     * @param outError Human readable error if parsing fails
1891     * @return True of parsing succeeded.
1892     *
1893     * @throws XmlPullParserException
1894     * @throws IOException
1895     */
1896    private boolean parseBaseApkChild(Package parentPkg, Resources res, XmlResourceParser parser,
1897            int flags, String[] outError) throws XmlPullParserException, IOException {
1898        // Let ppl not abuse this mechanism by limiting the packages per APK
1899        if (parentPkg.childPackages != null && parentPkg.childPackages.size() + 2
1900                > MAX_PACKAGES_PER_APK) {
1901            outError[0] = "Maximum number of packages per APK is: " + MAX_PACKAGES_PER_APK;
1902            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1903            return false;
1904        }
1905
1906        // Make sure we have a valid child package name
1907        String childPackageName = parser.getAttributeValue(null, "package");
1908        if (validateName(childPackageName, true, false) != null) {
1909            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1910            return false;
1911        }
1912
1913        // Child packages must be unique
1914        if (childPackageName.equals(parentPkg.packageName)) {
1915            String message = "Child package name cannot be equal to parent package name: "
1916                    + parentPkg.packageName;
1917            Slog.w(TAG, message);
1918            outError[0] = message;
1919            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1920            return false;
1921        }
1922
1923        // Child packages must be unique
1924        if (parentPkg.hasChildPackage(childPackageName)) {
1925            String message = "Duplicate child package:" + childPackageName;
1926            Slog.w(TAG, message);
1927            outError[0] = message;
1928            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1929            return false;
1930        }
1931
1932        // Go ahead and parse the child
1933        Package childPkg = new Package(childPackageName);
1934
1935        // Child package inherits parent version code/name/target SDK
1936        childPkg.mVersionCode = parentPkg.mVersionCode;
1937        childPkg.baseRevisionCode = parentPkg.baseRevisionCode;
1938        childPkg.mVersionName = parentPkg.mVersionName;
1939        childPkg.applicationInfo.targetSdkVersion = parentPkg.applicationInfo.targetSdkVersion;
1940        childPkg.applicationInfo.minSdkVersion = parentPkg.applicationInfo.minSdkVersion;
1941
1942        childPkg = parseBaseApkCommon(childPkg, CHILD_PACKAGE_TAGS, res, parser, flags, outError);
1943        if (childPkg == null) {
1944            // If we got null then error was set during child parsing
1945            return false;
1946        }
1947
1948        // Set the parent-child relation
1949        if (parentPkg.childPackages == null) {
1950            parentPkg.childPackages = new ArrayList<>();
1951        }
1952        parentPkg.childPackages.add(childPkg);
1953        childPkg.parentPackage = parentPkg;
1954
1955        return true;
1956    }
1957
1958    /**
1959     * Parse the manifest of a <em>base APK</em>. When adding new features you
1960     * need to consider whether they should be supported by split APKs and child
1961     * packages.
1962     *
1963     * @param apkPath The package apk file path
1964     * @param res The resources from which to resolve values
1965     * @param parser The manifest parser
1966     * @param flags Flags how to parse
1967     * @param outError Human readable error message
1968     * @return Parsed package or null on error.
1969     *
1970     * @throws XmlPullParserException
1971     * @throws IOException
1972     */
1973    private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
1974            String[] outError) throws XmlPullParserException, IOException {
1975        final String splitName;
1976        final String pkgName;
1977
1978        try {
1979            Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser);
1980            pkgName = packageSplit.first;
1981            splitName = packageSplit.second;
1982
1983            if (!TextUtils.isEmpty(splitName)) {
1984                outError[0] = "Expected base APK, but found split " + splitName;
1985                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1986                return null;
1987            }
1988        } catch (PackageParserException e) {
1989            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1990            return null;
1991        }
1992
1993        if (mCallback != null) {
1994            String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath);
1995            if (overlayPaths != null && overlayPaths.length > 0) {
1996                for (String overlayPath : overlayPaths) {
1997                    res.getAssets().addOverlayPath(overlayPath);
1998                }
1999            }
2000        }
2001
2002        final Package pkg = new Package(pkgName);
2003
2004        TypedArray sa = res.obtainAttributes(parser,
2005                com.android.internal.R.styleable.AndroidManifest);
2006
2007        pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
2008                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
2009        pkg.baseRevisionCode = sa.getInteger(
2010                com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
2011        pkg.mVersionName = sa.getNonConfigurationString(
2012                com.android.internal.R.styleable.AndroidManifest_versionName, 0);
2013        if (pkg.mVersionName != null) {
2014            pkg.mVersionName = pkg.mVersionName.intern();
2015        }
2016
2017        pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
2018
2019        sa.recycle();
2020
2021        return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
2022    }
2023
2024    /**
2025     * This is the common parsing routing for handling parent and child
2026     * packages in a base APK. The difference between parent and child
2027     * parsing is that some tags are not supported by child packages as
2028     * well as some manifest attributes are ignored. The implementation
2029     * assumes the calling code has already handled the manifest tag if needed
2030     * (this applies to the parent only).
2031     *
2032     * @param pkg The package which to populate
2033     * @param acceptedTags Which tags to handle, null to handle all
2034     * @param res Resources against which to resolve values
2035     * @param parser Parser of the manifest
2036     * @param flags Flags about how to parse
2037     * @param outError Human readable error if parsing fails
2038     * @return The package if parsing succeeded or null.
2039     *
2040     * @throws XmlPullParserException
2041     * @throws IOException
2042     */
2043    private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
2044            XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
2045            IOException {
2046        mParseInstrumentationArgs = null;
2047        mParseActivityArgs = null;
2048        mParseServiceArgs = null;
2049        mParseProviderArgs = null;
2050
2051        int type;
2052        boolean foundApp = false;
2053
2054        TypedArray sa = res.obtainAttributes(parser,
2055                com.android.internal.R.styleable.AndroidManifest);
2056
2057        String str = sa.getNonConfigurationString(
2058                com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
2059        if (str != null && str.length() > 0) {
2060            if ((flags & PARSE_IS_EPHEMERAL) != 0) {
2061                outError[0] = "sharedUserId not allowed in ephemeral application";
2062                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
2063                return null;
2064            }
2065            String nameError = validateName(str, true, false);
2066            if (nameError != null && !"android".equals(pkg.packageName)) {
2067                outError[0] = "<manifest> specifies bad sharedUserId name \""
2068                    + str + "\": " + nameError;
2069                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
2070                return null;
2071            }
2072            pkg.mSharedUserId = str.intern();
2073            pkg.mSharedUserLabel = sa.getResourceId(
2074                    com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
2075        }
2076
2077        pkg.installLocation = sa.getInteger(
2078                com.android.internal.R.styleable.AndroidManifest_installLocation,
2079                PARSE_DEFAULT_INSTALL_LOCATION);
2080        pkg.applicationInfo.installLocation = pkg.installLocation;
2081
2082        final int targetSandboxVersion = sa.getInteger(
2083                com.android.internal.R.styleable.AndroidManifest_targetSandboxVersion,
2084                PARSE_DEFAULT_TARGET_SANDBOX);
2085        pkg.applicationInfo.targetSandboxVersion = targetSandboxVersion;
2086
2087        /* Set the global "forward lock" flag */
2088        if ((flags & PARSE_FORWARD_LOCK) != 0) {
2089            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
2090        }
2091
2092        /* Set the global "on SD card" flag */
2093        if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
2094            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
2095        }
2096
2097        if (sa.getBoolean(com.android.internal.R.styleable.AndroidManifest_isolatedSplits, false)) {
2098            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
2099        }
2100
2101        // Resource boolean are -1, so 1 means we don't know the value.
2102        int supportsSmallScreens = 1;
2103        int supportsNormalScreens = 1;
2104        int supportsLargeScreens = 1;
2105        int supportsXLargeScreens = 1;
2106        int resizeable = 1;
2107        int anyDensity = 1;
2108
2109        int outerDepth = parser.getDepth();
2110        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2111                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2112            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2113                continue;
2114            }
2115
2116            String tagName = parser.getName();
2117
2118            if (acceptedTags != null && !acceptedTags.contains(tagName)) {
2119                Slog.w(TAG, "Skipping unsupported element under <manifest>: "
2120                        + tagName + " at " + mArchiveSourcePath + " "
2121                        + parser.getPositionDescription());
2122                XmlUtils.skipCurrentTag(parser);
2123                continue;
2124            }
2125
2126            if (tagName.equals(TAG_APPLICATION)) {
2127                if (foundApp) {
2128                    if (RIGID_PARSER) {
2129                        outError[0] = "<manifest> has more than one <application>";
2130                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2131                        return null;
2132                    } else {
2133                        Slog.w(TAG, "<manifest> has more than one <application>");
2134                        XmlUtils.skipCurrentTag(parser);
2135                        continue;
2136                    }
2137                }
2138
2139                foundApp = true;
2140                if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
2141                    return null;
2142                }
2143            } else if (tagName.equals(TAG_OVERLAY)) {
2144                sa = res.obtainAttributes(parser,
2145                        com.android.internal.R.styleable.AndroidManifestResourceOverlay);
2146                pkg.mOverlayTarget = sa.getString(
2147                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
2148                pkg.mOverlayPriority = sa.getInt(
2149                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
2150                        0);
2151                pkg.mIsStaticOverlay = sa.getBoolean(
2152                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_isStatic,
2153                        false);
2154                final String propName = sa.getString(
2155                        com.android.internal.R.styleable
2156                        .AndroidManifestResourceOverlay_requiredSystemPropertyName);
2157                final String propValue = sa.getString(
2158                        com.android.internal.R.styleable
2159                        .AndroidManifestResourceOverlay_requiredSystemPropertyValue);
2160                sa.recycle();
2161
2162                if (pkg.mOverlayTarget == null) {
2163                    outError[0] = "<overlay> does not specify a target package";
2164                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2165                    return null;
2166                }
2167
2168                if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
2169                    outError[0] = "<overlay> priority must be between 0 and 9999";
2170                    mParseError =
2171                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2172                    return null;
2173                }
2174
2175                // check to see if overlay should be excluded based on system property condition
2176                if (!checkOverlayRequiredSystemProperty(propName, propValue)) {
2177                    Slog.i(TAG, "Skipping target and overlay pair " + pkg.mOverlayTarget + " and "
2178                        + pkg.baseCodePath+ ": overlay ignored due to required system property: "
2179                        + propName + " with value: " + propValue);
2180                    return null;
2181                }
2182
2183                XmlUtils.skipCurrentTag(parser);
2184
2185            } else if (tagName.equals(TAG_KEY_SETS)) {
2186                if (!parseKeySets(pkg, res, parser, outError)) {
2187                    return null;
2188                }
2189            } else if (tagName.equals(TAG_PERMISSION_GROUP)) {
2190                if (!parsePermissionGroup(pkg, flags, res, parser, outError)) {
2191                    return null;
2192                }
2193            } else if (tagName.equals(TAG_PERMISSION)) {
2194                if (!parsePermission(pkg, res, parser, outError)) {
2195                    return null;
2196                }
2197            } else if (tagName.equals(TAG_PERMISSION_TREE)) {
2198                if (!parsePermissionTree(pkg, res, parser, outError)) {
2199                    return null;
2200                }
2201            } else if (tagName.equals(TAG_USES_PERMISSION)) {
2202                if (!parseUsesPermission(pkg, res, parser)) {
2203                    return null;
2204                }
2205            } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)
2206                    || tagName.equals(TAG_USES_PERMISSION_SDK_23)) {
2207                if (!parseUsesPermission(pkg, res, parser)) {
2208                    return null;
2209                }
2210            } else if (tagName.equals(TAG_USES_CONFIGURATION)) {
2211                ConfigurationInfo cPref = new ConfigurationInfo();
2212                sa = res.obtainAttributes(parser,
2213                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration);
2214                cPref.reqTouchScreen = sa.getInt(
2215                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
2216                        Configuration.TOUCHSCREEN_UNDEFINED);
2217                cPref.reqKeyboardType = sa.getInt(
2218                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
2219                        Configuration.KEYBOARD_UNDEFINED);
2220                if (sa.getBoolean(
2221                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
2222                        false)) {
2223                    cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
2224                }
2225                cPref.reqNavigation = sa.getInt(
2226                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
2227                        Configuration.NAVIGATION_UNDEFINED);
2228                if (sa.getBoolean(
2229                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
2230                        false)) {
2231                    cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
2232                }
2233                sa.recycle();
2234                pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
2235
2236                XmlUtils.skipCurrentTag(parser);
2237
2238            } else if (tagName.equals(TAG_USES_FEATURE)) {
2239                FeatureInfo fi = parseUsesFeature(res, parser);
2240                pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi);
2241
2242                if (fi.name == null) {
2243                    ConfigurationInfo cPref = new ConfigurationInfo();
2244                    cPref.reqGlEsVersion = fi.reqGlEsVersion;
2245                    pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
2246                }
2247
2248                XmlUtils.skipCurrentTag(parser);
2249
2250            } else if (tagName.equals(TAG_FEATURE_GROUP)) {
2251                FeatureGroupInfo group = new FeatureGroupInfo();
2252                ArrayList<FeatureInfo> features = null;
2253                final int innerDepth = parser.getDepth();
2254                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2255                        && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
2256                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2257                        continue;
2258                    }
2259
2260                    final String innerTagName = parser.getName();
2261                    if (innerTagName.equals("uses-feature")) {
2262                        FeatureInfo featureInfo = parseUsesFeature(res, parser);
2263                        // FeatureGroups are stricter and mandate that
2264                        // any <uses-feature> declared are mandatory.
2265                        featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
2266                        features = ArrayUtils.add(features, featureInfo);
2267                    } else {
2268                        Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName +
2269                                " at " + mArchiveSourcePath + " " +
2270                                parser.getPositionDescription());
2271                    }
2272                    XmlUtils.skipCurrentTag(parser);
2273                }
2274
2275                if (features != null) {
2276                    group.features = new FeatureInfo[features.size()];
2277                    group.features = features.toArray(group.features);
2278                }
2279                pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group);
2280
2281            } else if (tagName.equals(TAG_USES_SDK)) {
2282                if (SDK_VERSION > 0) {
2283                    sa = res.obtainAttributes(parser,
2284                            com.android.internal.R.styleable.AndroidManifestUsesSdk);
2285
2286                    int minVers = 1;
2287                    String minCode = null;
2288                    int targetVers = 0;
2289                    String targetCode = null;
2290
2291                    TypedValue val = sa.peekValue(
2292                            com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
2293                    if (val != null) {
2294                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
2295                            targetCode = minCode = val.string.toString();
2296                        } else {
2297                            // If it's not a string, it's an integer.
2298                            targetVers = minVers = val.data;
2299                        }
2300                    }
2301
2302                    val = sa.peekValue(
2303                            com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
2304                    if (val != null) {
2305                        if (val.type == TypedValue.TYPE_STRING && val.string != null) {
2306                            targetCode = val.string.toString();
2307                            if (minCode == null) {
2308                                minCode = targetCode;
2309                            }
2310                        } else {
2311                            // If it's not a string, it's an integer.
2312                            targetVers = val.data;
2313                        }
2314                    }
2315
2316                    sa.recycle();
2317
2318                    final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode,
2319                            SDK_VERSION, SDK_CODENAMES, outError);
2320                    if (minSdkVersion < 0) {
2321                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
2322                        return null;
2323                    }
2324
2325                    final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers,
2326                            targetCode, SDK_VERSION, SDK_CODENAMES, outError);
2327                    if (targetSdkVersion < 0) {
2328                        mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
2329                        return null;
2330                    }
2331
2332                    pkg.applicationInfo.minSdkVersion = minSdkVersion;
2333                    pkg.applicationInfo.targetSdkVersion = targetSdkVersion;
2334                }
2335
2336                XmlUtils.skipCurrentTag(parser);
2337
2338            } else if (tagName.equals(TAG_SUPPORT_SCREENS)) {
2339                sa = res.obtainAttributes(parser,
2340                        com.android.internal.R.styleable.AndroidManifestSupportsScreens);
2341
2342                pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger(
2343                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp,
2344                        0);
2345                pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger(
2346                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp,
2347                        0);
2348                pkg.applicationInfo.largestWidthLimitDp = sa.getInteger(
2349                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp,
2350                        0);
2351
2352                // This is a trick to get a boolean and still able to detect
2353                // if a value was actually set.
2354                supportsSmallScreens = sa.getInteger(
2355                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens,
2356                        supportsSmallScreens);
2357                supportsNormalScreens = sa.getInteger(
2358                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens,
2359                        supportsNormalScreens);
2360                supportsLargeScreens = sa.getInteger(
2361                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens,
2362                        supportsLargeScreens);
2363                supportsXLargeScreens = sa.getInteger(
2364                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens,
2365                        supportsXLargeScreens);
2366                resizeable = sa.getInteger(
2367                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable,
2368                        resizeable);
2369                anyDensity = sa.getInteger(
2370                        com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity,
2371                        anyDensity);
2372
2373                sa.recycle();
2374
2375                XmlUtils.skipCurrentTag(parser);
2376
2377            } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) {
2378                sa = res.obtainAttributes(parser,
2379                        com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
2380
2381                // Note: don't allow this value to be a reference to a resource
2382                // that may change.
2383                String name = sa.getNonResourceString(
2384                        com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name);
2385
2386                sa.recycle();
2387
2388                if (name != null && (flags&PARSE_IS_SYSTEM) != 0) {
2389                    if (pkg.protectedBroadcasts == null) {
2390                        pkg.protectedBroadcasts = new ArrayList<String>();
2391                    }
2392                    if (!pkg.protectedBroadcasts.contains(name)) {
2393                        pkg.protectedBroadcasts.add(name.intern());
2394                    }
2395                }
2396
2397                XmlUtils.skipCurrentTag(parser);
2398
2399            } else if (tagName.equals(TAG_INSTRUMENTATION)) {
2400                if (parseInstrumentation(pkg, res, parser, outError) == null) {
2401                    return null;
2402                }
2403            } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) {
2404                sa = res.obtainAttributes(parser,
2405                        com.android.internal.R.styleable.AndroidManifestOriginalPackage);
2406
2407                String orig =sa.getNonConfigurationString(
2408                        com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
2409                if (!pkg.packageName.equals(orig)) {
2410                    if (pkg.mOriginalPackages == null) {
2411                        pkg.mOriginalPackages = new ArrayList<String>();
2412                        pkg.mRealPackage = pkg.packageName;
2413                    }
2414                    pkg.mOriginalPackages.add(orig);
2415                }
2416
2417                sa.recycle();
2418
2419                XmlUtils.skipCurrentTag(parser);
2420
2421            } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) {
2422                sa = res.obtainAttributes(parser,
2423                        com.android.internal.R.styleable.AndroidManifestOriginalPackage);
2424
2425                String name = sa.getNonConfigurationString(
2426                        com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
2427
2428                sa.recycle();
2429
2430                if (name != null) {
2431                    if (pkg.mAdoptPermissions == null) {
2432                        pkg.mAdoptPermissions = new ArrayList<String>();
2433                    }
2434                    pkg.mAdoptPermissions.add(name);
2435                }
2436
2437                XmlUtils.skipCurrentTag(parser);
2438
2439            } else if (tagName.equals(TAG_USES_GL_TEXTURE)) {
2440                // Just skip this tag
2441                XmlUtils.skipCurrentTag(parser);
2442                continue;
2443
2444            } else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) {
2445                // Just skip this tag
2446                XmlUtils.skipCurrentTag(parser);
2447                continue;
2448            } else if (tagName.equals(TAG_SUPPORTS_INPUT)) {//
2449                XmlUtils.skipCurrentTag(parser);
2450                continue;
2451
2452            } else if (tagName.equals(TAG_EAT_COMMENT)) {
2453                // Just skip this tag
2454                XmlUtils.skipCurrentTag(parser);
2455                continue;
2456
2457            } else if (tagName.equals(TAG_PACKAGE)) {
2458                if (!MULTI_PACKAGE_APK_ENABLED) {
2459                    XmlUtils.skipCurrentTag(parser);
2460                    continue;
2461                }
2462                if (!parseBaseApkChild(pkg, res, parser, flags, outError)) {
2463                    // If parsing a child failed the error is already set
2464                    return null;
2465                }
2466
2467            } else if (tagName.equals(TAG_RESTRICT_UPDATE)) {
2468                if ((flags & PARSE_IS_SYSTEM_DIR) != 0) {
2469                    sa = res.obtainAttributes(parser,
2470                            com.android.internal.R.styleable.AndroidManifestRestrictUpdate);
2471                    final String hash = sa.getNonConfigurationString(
2472                            com.android.internal.R.styleable.AndroidManifestRestrictUpdate_hash, 0);
2473                    sa.recycle();
2474
2475                    pkg.restrictUpdateHash = null;
2476                    if (hash != null) {
2477                        final int hashLength = hash.length();
2478                        final byte[] hashBytes = new byte[hashLength / 2];
2479                        for (int i = 0; i < hashLength; i += 2){
2480                            hashBytes[i/2] = (byte) ((Character.digit(hash.charAt(i), 16) << 4)
2481                                    + Character.digit(hash.charAt(i + 1), 16));
2482                        }
2483                        pkg.restrictUpdateHash = hashBytes;
2484                    }
2485                }
2486
2487                XmlUtils.skipCurrentTag(parser);
2488
2489            } else if (RIGID_PARSER) {
2490                outError[0] = "Bad element under <manifest>: "
2491                    + parser.getName();
2492                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2493                return null;
2494
2495            } else {
2496                Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
2497                        + " at " + mArchiveSourcePath + " "
2498                        + parser.getPositionDescription());
2499                XmlUtils.skipCurrentTag(parser);
2500                continue;
2501            }
2502        }
2503
2504        if (!foundApp && pkg.instrumentation.size() == 0) {
2505            outError[0] = "<manifest> does not contain an <application> or <instrumentation>";
2506            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
2507        }
2508
2509        final int NP = PackageParser.NEW_PERMISSIONS.length;
2510        StringBuilder implicitPerms = null;
2511        for (int ip=0; ip<NP; ip++) {
2512            final PackageParser.NewPermissionInfo npi
2513                    = PackageParser.NEW_PERMISSIONS[ip];
2514            if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
2515                break;
2516            }
2517            if (!pkg.requestedPermissions.contains(npi.name)) {
2518                if (implicitPerms == null) {
2519                    implicitPerms = new StringBuilder(128);
2520                    implicitPerms.append(pkg.packageName);
2521                    implicitPerms.append(": compat added ");
2522                } else {
2523                    implicitPerms.append(' ');
2524                }
2525                implicitPerms.append(npi.name);
2526                pkg.requestedPermissions.add(npi.name);
2527            }
2528        }
2529        if (implicitPerms != null) {
2530            Slog.i(TAG, implicitPerms.toString());
2531        }
2532
2533        final int NS = PackageParser.SPLIT_PERMISSIONS.length;
2534        for (int is=0; is<NS; is++) {
2535            final PackageParser.SplitPermissionInfo spi
2536                    = PackageParser.SPLIT_PERMISSIONS[is];
2537            if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
2538                    || !pkg.requestedPermissions.contains(spi.rootPerm)) {
2539                continue;
2540            }
2541            for (int in=0; in<spi.newPerms.length; in++) {
2542                final String perm = spi.newPerms[in];
2543                if (!pkg.requestedPermissions.contains(perm)) {
2544                    pkg.requestedPermissions.add(perm);
2545                }
2546            }
2547        }
2548
2549        if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
2550                && pkg.applicationInfo.targetSdkVersion
2551                        >= android.os.Build.VERSION_CODES.DONUT)) {
2552            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
2553        }
2554        if (supportsNormalScreens != 0) {
2555            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
2556        }
2557        if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
2558                && pkg.applicationInfo.targetSdkVersion
2559                        >= android.os.Build.VERSION_CODES.DONUT)) {
2560            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
2561        }
2562        if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
2563                && pkg.applicationInfo.targetSdkVersion
2564                        >= android.os.Build.VERSION_CODES.GINGERBREAD)) {
2565            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
2566        }
2567        if (resizeable < 0 || (resizeable > 0
2568                && pkg.applicationInfo.targetSdkVersion
2569                        >= android.os.Build.VERSION_CODES.DONUT)) {
2570            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
2571        }
2572        if (anyDensity < 0 || (anyDensity > 0
2573                && pkg.applicationInfo.targetSdkVersion
2574                        >= android.os.Build.VERSION_CODES.DONUT)) {
2575            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
2576        }
2577
2578        // At this point we can check if an application is not supporting densities and hence
2579        // cannot be windowed / resized. Note that an SDK version of 0 is common for
2580        // pre-Doughnut applications.
2581        if (pkg.applicationInfo.usesCompatibilityMode()) {
2582            adjustPackageToBeUnresizeableAndUnpipable(pkg);
2583        }
2584        return pkg;
2585    }
2586
2587    private boolean checkOverlayRequiredSystemProperty(String propName, String propValue) {
2588
2589        if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) {
2590            if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) {
2591                // malformed condition - incomplete
2592                Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName
2593                    + "=" + propValue + "' - require both requiredSystemPropertyName"
2594                    + " AND requiredSystemPropertyValue to be specified.");
2595                return false;
2596            }
2597            // no valid condition set - so no exclusion criteria, overlay will be included.
2598            return true;
2599        }
2600
2601        // check property value - make sure it is both set and equal to expected value
2602        final String currValue = SystemProperties.get(propName);
2603        return (currValue != null && currValue.equals(propValue));
2604    }
2605
2606    /**
2607     * This is a pre-density application which will get scaled - instead of being pixel perfect.
2608     * This type of application is not resizable.
2609     *
2610     * @param pkg The package which needs to be marked as unresizable.
2611     */
2612    private void adjustPackageToBeUnresizeableAndUnpipable(Package pkg) {
2613        for (Activity a : pkg.activities) {
2614            a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
2615            a.info.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE;
2616        }
2617    }
2618
2619    /**
2620     * Computes the targetSdkVersion to use at runtime. If the package is not
2621     * compatible with this platform, populates {@code outError[0]} with an
2622     * error message.
2623     * <p>
2624     * If {@code targetCode} is not specified, e.g. the value is {@code null},
2625     * then the {@code targetVers} will be returned unmodified.
2626     * <p>
2627     * Otherwise, the behavior varies based on whether the current platform
2628     * is a pre-release version, e.g. the {@code platformSdkCodenames} array
2629     * has length > 0:
2630     * <ul>
2631     * <li>If this is a pre-release platform and the value specified by
2632     * {@code targetCode} is contained within the array of allowed pre-release
2633     * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
2634     * <li>If this is a released platform, this method will return -1 to
2635     * indicate that the package is not compatible with this platform.
2636     * </ul>
2637     *
2638     * @param targetVers targetSdkVersion number, if specified in the
2639     *                   application manifest, or 0 otherwise
2640     * @param targetCode targetSdkVersion code, if specified in the application
2641     *                   manifest, or {@code null} otherwise
2642     * @param platformSdkVersion platform SDK version number, typically
2643     *                           Build.VERSION.SDK_INT
2644     * @param platformSdkCodenames array of allowed pre-release SDK codenames
2645     *                             for this platform
2646     * @param outError output array to populate with error, if applicable
2647     * @return the targetSdkVersion to use at runtime, or -1 if the package is
2648     *         not compatible with this platform
2649     * @hide Exposed for unit testing only.
2650     */
2651    @TestApi
2652    public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
2653            @Nullable String targetCode, @IntRange(from = 1) int platformSdkVersion,
2654            @NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
2655        // If it's a release SDK, return the version number unmodified.
2656        if (targetCode == null) {
2657            return targetVers;
2658        }
2659
2660        // If it's a pre-release SDK and the codename matches this platform, it
2661        // definitely targets this SDK.
2662        if (ArrayUtils.contains(platformSdkCodenames, targetCode)) {
2663            return Build.VERSION_CODES.CUR_DEVELOPMENT;
2664        }
2665
2666        // Otherwise, we're looking at an incompatible pre-release SDK.
2667        if (platformSdkCodenames.length > 0) {
2668            outError[0] = "Requires development platform " + targetCode
2669                    + " (current platform is any of "
2670                    + Arrays.toString(platformSdkCodenames) + ")";
2671        } else {
2672            outError[0] = "Requires development platform " + targetCode
2673                    + " but this is a release platform.";
2674        }
2675        return -1;
2676    }
2677
2678    /**
2679     * Computes the minSdkVersion to use at runtime. If the package is not
2680     * compatible with this platform, populates {@code outError[0]} with an
2681     * error message.
2682     * <p>
2683     * If {@code minCode} is not specified, e.g. the value is {@code null},
2684     * then behavior varies based on the {@code platformSdkVersion}:
2685     * <ul>
2686     * <li>If the platform SDK version is greater than or equal to the
2687     * {@code minVers}, returns the {@code mniVers} unmodified.
2688     * <li>Otherwise, returns -1 to indicate that the package is not
2689     * compatible with this platform.
2690     * </ul>
2691     * <p>
2692     * Otherwise, the behavior varies based on whether the current platform
2693     * is a pre-release version, e.g. the {@code platformSdkCodenames} array
2694     * has length > 0:
2695     * <ul>
2696     * <li>If this is a pre-release platform and the value specified by
2697     * {@code targetCode} is contained within the array of allowed pre-release
2698     * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
2699     * <li>If this is a released platform, this method will return -1 to
2700     * indicate that the package is not compatible with this platform.
2701     * </ul>
2702     *
2703     * @param minVers minSdkVersion number, if specified in the application
2704     *                manifest, or 1 otherwise
2705     * @param minCode minSdkVersion code, if specified in the application
2706     *                manifest, or {@code null} otherwise
2707     * @param platformSdkVersion platform SDK version number, typically
2708     *                           Build.VERSION.SDK_INT
2709     * @param platformSdkCodenames array of allowed prerelease SDK codenames
2710     *                             for this platform
2711     * @param outError output array to populate with error, if applicable
2712     * @return the minSdkVersion to use at runtime, or -1 if the package is not
2713     *         compatible with this platform
2714     * @hide Exposed for unit testing only.
2715     */
2716    @TestApi
2717    public static int computeMinSdkVersion(@IntRange(from = 1) int minVers,
2718            @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
2719            @NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
2720        // If it's a release SDK, make sure we meet the minimum SDK requirement.
2721        if (minCode == null) {
2722            if (minVers <= platformSdkVersion) {
2723                return minVers;
2724            }
2725
2726            // We don't meet the minimum SDK requirement.
2727            outError[0] = "Requires newer sdk version #" + minVers
2728                    + " (current version is #" + platformSdkVersion + ")";
2729            return -1;
2730        }
2731
2732        // If it's a pre-release SDK and the codename matches this platform, we
2733        // definitely meet the minimum SDK requirement.
2734        if (ArrayUtils.contains(platformSdkCodenames, minCode)) {
2735            return Build.VERSION_CODES.CUR_DEVELOPMENT;
2736        }
2737
2738        // Otherwise, we're looking at an incompatible pre-release SDK.
2739        if (platformSdkCodenames.length > 0) {
2740            outError[0] = "Requires development platform " + minCode
2741                    + " (current platform is any of "
2742                    + Arrays.toString(platformSdkCodenames) + ")";
2743        } else {
2744            outError[0] = "Requires development platform " + minCode
2745                    + " but this is a release platform.";
2746        }
2747        return -1;
2748    }
2749
2750    private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs) {
2751        FeatureInfo fi = new FeatureInfo();
2752        TypedArray sa = res.obtainAttributes(attrs,
2753                com.android.internal.R.styleable.AndroidManifestUsesFeature);
2754        // Note: don't allow this value to be a reference to a resource
2755        // that may change.
2756        fi.name = sa.getNonResourceString(
2757                com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
2758        fi.version = sa.getInt(
2759                com.android.internal.R.styleable.AndroidManifestUsesFeature_version, 0);
2760        if (fi.name == null) {
2761            fi.reqGlEsVersion = sa.getInt(
2762                        com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
2763                        FeatureInfo.GL_ES_VERSION_UNDEFINED);
2764        }
2765        if (sa.getBoolean(
2766                com.android.internal.R.styleable.AndroidManifestUsesFeature_required, true)) {
2767            fi.flags |= FeatureInfo.FLAG_REQUIRED;
2768        }
2769        sa.recycle();
2770        return fi;
2771    }
2772
2773    private boolean parseUsesStaticLibrary(Package pkg, Resources res, XmlResourceParser parser,
2774            String[] outError) throws XmlPullParserException, IOException {
2775        TypedArray sa = res.obtainAttributes(parser,
2776                com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary);
2777
2778        // Note: don't allow this value to be a reference to a resource that may change.
2779        String lname = sa.getNonResourceString(
2780                com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
2781        final int version = sa.getInt(
2782                com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary_version, -1);
2783        String certSha256 = sa.getNonResourceString(com.android.internal.R.styleable
2784                .AndroidManifestUsesStaticLibrary_certDigest);
2785        sa.recycle();
2786
2787        // Since an APK providing a static shared lib can only provide the lib - fail if malformed
2788        if (lname == null || version < 0 || certSha256 == null) {
2789            outError[0] = "Bad uses-static-library declaration name: " + lname + " version: "
2790                    + version + " certDigest" + certSha256;
2791            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2792            XmlUtils.skipCurrentTag(parser);
2793            return false;
2794        }
2795
2796        // Can depend only on one version of the same library
2797        if (pkg.usesStaticLibraries != null && pkg.usesStaticLibraries.contains(lname)) {
2798            outError[0] = "Depending on multiple versions of static library " + lname;
2799            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2800            XmlUtils.skipCurrentTag(parser);
2801            return false;
2802        }
2803
2804        lname = lname.intern();
2805        // We allow ":" delimiters in the SHA declaration as this is the format
2806        // emitted by the certtool making it easy for developers to copy/paste.
2807        certSha256 = certSha256.replace(":", "").toLowerCase();
2808        pkg.usesStaticLibraries = ArrayUtils.add(pkg.usesStaticLibraries, lname);
2809        pkg.usesStaticLibrariesVersions = ArrayUtils.appendInt(
2810                pkg.usesStaticLibrariesVersions, version, true);
2811        pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String.class,
2812                pkg.usesStaticLibrariesCertDigests, certSha256, true);
2813
2814        XmlUtils.skipCurrentTag(parser);
2815
2816        return true;
2817    }
2818
2819    private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser)
2820            throws XmlPullParserException, IOException {
2821        TypedArray sa = res.obtainAttributes(parser,
2822                com.android.internal.R.styleable.AndroidManifestUsesPermission);
2823
2824        // Note: don't allow this value to be a reference to a resource
2825        // that may change.
2826        String name = sa.getNonResourceString(
2827                com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
2828
2829        int maxSdkVersion = 0;
2830        TypedValue val = sa.peekValue(
2831                com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
2832        if (val != null) {
2833            if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
2834                maxSdkVersion = val.data;
2835            }
2836        }
2837
2838        final String requiredFeature = sa.getNonConfigurationString(
2839                com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
2840
2841        final String requiredNotfeature = sa.getNonConfigurationString(
2842                com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredNotFeature, 0);
2843
2844        sa.recycle();
2845
2846        XmlUtils.skipCurrentTag(parser);
2847
2848        if (name == null) {
2849            return true;
2850        }
2851
2852        if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
2853            return true;
2854        }
2855
2856        // Only allow requesting this permission if the platform supports the given feature.
2857        if (requiredFeature != null && mCallback != null && !mCallback.hasFeature(requiredFeature)) {
2858            return true;
2859        }
2860
2861        // Only allow requesting this permission if the platform doesn't support the given feature.
2862        if (requiredNotfeature != null && mCallback != null
2863                && mCallback.hasFeature(requiredNotfeature)) {
2864            return true;
2865        }
2866
2867        int index = pkg.requestedPermissions.indexOf(name);
2868        if (index == -1) {
2869            pkg.requestedPermissions.add(name.intern());
2870        } else {
2871            Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
2872                    + name + " in package: " + pkg.packageName + " at: "
2873                    + parser.getPositionDescription());
2874        }
2875
2876        return true;
2877    }
2878
2879    private static String buildClassName(String pkg, CharSequence clsSeq,
2880            String[] outError) {
2881        if (clsSeq == null || clsSeq.length() <= 0) {
2882            outError[0] = "Empty class name in package " + pkg;
2883            return null;
2884        }
2885        String cls = clsSeq.toString();
2886        char c = cls.charAt(0);
2887        if (c == '.') {
2888            return pkg + cls;
2889        }
2890        if (cls.indexOf('.') < 0) {
2891            StringBuilder b = new StringBuilder(pkg);
2892            b.append('.');
2893            b.append(cls);
2894            return b.toString();
2895        }
2896        return cls;
2897    }
2898
2899    private static String buildCompoundName(String pkg,
2900            CharSequence procSeq, String type, String[] outError) {
2901        String proc = procSeq.toString();
2902        char c = proc.charAt(0);
2903        if (pkg != null && c == ':') {
2904            if (proc.length() < 2) {
2905                outError[0] = "Bad " + type + " name " + proc + " in package " + pkg
2906                        + ": must be at least two characters";
2907                return null;
2908            }
2909            String subName = proc.substring(1);
2910            String nameError = validateName(subName, false, false);
2911            if (nameError != null) {
2912                outError[0] = "Invalid " + type + " name " + proc + " in package "
2913                        + pkg + ": " + nameError;
2914                return null;
2915            }
2916            return pkg + proc;
2917        }
2918        String nameError = validateName(proc, true, false);
2919        if (nameError != null && !"system".equals(proc)) {
2920            outError[0] = "Invalid " + type + " name " + proc + " in package "
2921                    + pkg + ": " + nameError;
2922            return null;
2923        }
2924        return proc;
2925    }
2926
2927    private static String buildProcessName(String pkg, String defProc,
2928            CharSequence procSeq, int flags, String[] separateProcesses,
2929            String[] outError) {
2930        if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
2931            return defProc != null ? defProc : pkg;
2932        }
2933        if (separateProcesses != null) {
2934            for (int i=separateProcesses.length-1; i>=0; i--) {
2935                String sp = separateProcesses[i];
2936                if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) {
2937                    return pkg;
2938                }
2939            }
2940        }
2941        if (procSeq == null || procSeq.length() <= 0) {
2942            return defProc;
2943        }
2944        return buildCompoundName(pkg, procSeq, "process", outError);
2945    }
2946
2947    private static String buildTaskAffinityName(String pkg, String defProc,
2948            CharSequence procSeq, String[] outError) {
2949        if (procSeq == null) {
2950            return defProc;
2951        }
2952        if (procSeq.length() <= 0) {
2953            return null;
2954        }
2955        return buildCompoundName(pkg, procSeq, "taskAffinity", outError);
2956    }
2957
2958    private boolean parseKeySets(Package owner, Resources res,
2959            XmlResourceParser parser, String[] outError)
2960            throws XmlPullParserException, IOException {
2961        // we've encountered the 'key-sets' tag
2962        // all the keys and keysets that we want must be defined here
2963        // so we're going to iterate over the parser and pull out the things we want
2964        int outerDepth = parser.getDepth();
2965        int currentKeySetDepth = -1;
2966        int type;
2967        String currentKeySet = null;
2968        ArrayMap<String, PublicKey> publicKeys = new ArrayMap<String, PublicKey>();
2969        ArraySet<String> upgradeKeySets = new ArraySet<String>();
2970        ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<String, ArraySet<String>>();
2971        ArraySet<String> improperKeySets = new ArraySet<String>();
2972        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2973                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2974            if (type == XmlPullParser.END_TAG) {
2975                if (parser.getDepth() == currentKeySetDepth) {
2976                    currentKeySet = null;
2977                    currentKeySetDepth = -1;
2978                }
2979                continue;
2980            }
2981            String tagName = parser.getName();
2982            if (tagName.equals("key-set")) {
2983                if (currentKeySet != null) {
2984                    outError[0] = "Improperly nested 'key-set' tag at "
2985                            + parser.getPositionDescription();
2986                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2987                    return false;
2988                }
2989                final TypedArray sa = res.obtainAttributes(parser,
2990                        com.android.internal.R.styleable.AndroidManifestKeySet);
2991                final String keysetName = sa.getNonResourceString(
2992                    com.android.internal.R.styleable.AndroidManifestKeySet_name);
2993                definedKeySets.put(keysetName, new ArraySet<String>());
2994                currentKeySet = keysetName;
2995                currentKeySetDepth = parser.getDepth();
2996                sa.recycle();
2997            } else if (tagName.equals("public-key")) {
2998                if (currentKeySet == null) {
2999                    outError[0] = "Improperly nested 'key-set' tag at "
3000                            + parser.getPositionDescription();
3001                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3002                    return false;
3003                }
3004                final TypedArray sa = res.obtainAttributes(parser,
3005                        com.android.internal.R.styleable.AndroidManifestPublicKey);
3006                final String publicKeyName = sa.getNonResourceString(
3007                        com.android.internal.R.styleable.AndroidManifestPublicKey_name);
3008                final String encodedKey = sa.getNonResourceString(
3009                            com.android.internal.R.styleable.AndroidManifestPublicKey_value);
3010                if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
3011                    outError[0] = "'public-key' " + publicKeyName + " must define a public-key value"
3012                            + " on first use at " + parser.getPositionDescription();
3013                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3014                    sa.recycle();
3015                    return false;
3016                } else if (encodedKey != null) {
3017                    PublicKey currentKey = parsePublicKey(encodedKey);
3018                    if (currentKey == null) {
3019                        Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
3020                                + parser.getPositionDescription() + " key-set " + currentKeySet
3021                                + " will not be added to the package's defined key-sets.");
3022                        sa.recycle();
3023                        improperKeySets.add(currentKeySet);
3024                        XmlUtils.skipCurrentTag(parser);
3025                        continue;
3026                    }
3027                    if (publicKeys.get(publicKeyName) == null
3028                            || publicKeys.get(publicKeyName).equals(currentKey)) {
3029
3030                        /* public-key first definition, or matches old definition */
3031                        publicKeys.put(publicKeyName, currentKey);
3032                    } else {
3033                        outError[0] = "Value of 'public-key' " + publicKeyName
3034                               + " conflicts with previously defined value at "
3035                               + parser.getPositionDescription();
3036                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3037                        sa.recycle();
3038                        return false;
3039                    }
3040                }
3041                definedKeySets.get(currentKeySet).add(publicKeyName);
3042                sa.recycle();
3043                XmlUtils.skipCurrentTag(parser);
3044            } else if (tagName.equals("upgrade-key-set")) {
3045                final TypedArray sa = res.obtainAttributes(parser,
3046                        com.android.internal.R.styleable.AndroidManifestUpgradeKeySet);
3047                String name = sa.getNonResourceString(
3048                        com.android.internal.R.styleable.AndroidManifestUpgradeKeySet_name);
3049                upgradeKeySets.add(name);
3050                sa.recycle();
3051                XmlUtils.skipCurrentTag(parser);
3052            } else if (RIGID_PARSER) {
3053                outError[0] = "Bad element under <key-sets>: " + parser.getName()
3054                        + " at " + mArchiveSourcePath + " "
3055                        + parser.getPositionDescription();
3056                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3057                return false;
3058            } else {
3059                Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName()
3060                        + " at " + mArchiveSourcePath + " "
3061                        + parser.getPositionDescription());
3062                XmlUtils.skipCurrentTag(parser);
3063                continue;
3064            }
3065        }
3066        Set<String> publicKeyNames = publicKeys.keySet();
3067        if (publicKeyNames.removeAll(definedKeySets.keySet())) {
3068            outError[0] = "Package" + owner.packageName + " AndroidManifext.xml "
3069                    + "'key-set' and 'public-key' names must be distinct.";
3070            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3071            return false;
3072        }
3073        owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>();
3074        for (ArrayMap.Entry<String, ArraySet<String>> e: definedKeySets.entrySet()) {
3075            final String keySetName = e.getKey();
3076            if (e.getValue().size() == 0) {
3077                Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
3078                        + "'key-set' " + keySetName + " has no valid associated 'public-key'."
3079                        + " Not including in package's defined key-sets.");
3080                continue;
3081            } else if (improperKeySets.contains(keySetName)) {
3082                Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
3083                        + "'key-set' " + keySetName + " contained improper 'public-key'"
3084                        + " tags. Not including in package's defined key-sets.");
3085                continue;
3086            }
3087            owner.mKeySetMapping.put(keySetName, new ArraySet<PublicKey>());
3088            for (String s : e.getValue()) {
3089                owner.mKeySetMapping.get(keySetName).add(publicKeys.get(s));
3090            }
3091        }
3092        if (owner.mKeySetMapping.keySet().containsAll(upgradeKeySets)) {
3093            owner.mUpgradeKeySets = upgradeKeySets;
3094        } else {
3095            outError[0] ="Package" + owner.packageName + " AndroidManifext.xml "
3096                   + "does not define all 'upgrade-key-set's .";
3097            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3098            return false;
3099        }
3100        return true;
3101    }
3102
3103    private boolean parsePermissionGroup(Package owner, int flags, Resources res,
3104            XmlResourceParser parser, String[] outError)
3105            throws XmlPullParserException, IOException {
3106        PermissionGroup perm = new PermissionGroup(owner);
3107
3108        TypedArray sa = res.obtainAttributes(parser,
3109                com.android.internal.R.styleable.AndroidManifestPermissionGroup);
3110        if (!parsePackageItemInfo(owner, perm.info, outError,
3111                "<permission-group>", sa, true /*nameRequired*/,
3112                com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
3113                com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
3114                com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
3115                com.android.internal.R.styleable.AndroidManifestPermissionGroup_roundIcon,
3116                com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
3117                com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
3118            sa.recycle();
3119            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3120            return false;
3121        }
3122
3123        perm.info.descriptionRes = sa.getResourceId(
3124                com.android.internal.R.styleable.AndroidManifestPermissionGroup_description,
3125                0);
3126        perm.info.flags = sa.getInt(
3127                com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0);
3128        perm.info.priority = sa.getInt(
3129                com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0);
3130        if (perm.info.priority > 0 && (flags&PARSE_IS_SYSTEM) == 0) {
3131            perm.info.priority = 0;
3132        }
3133
3134        sa.recycle();
3135
3136        if (!parseAllMetaData(res, parser, "<permission-group>", perm,
3137                outError)) {
3138            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3139            return false;
3140        }
3141
3142        owner.permissionGroups.add(perm);
3143
3144        return true;
3145    }
3146
3147    private boolean parsePermission(Package owner, Resources res,
3148            XmlResourceParser parser, String[] outError)
3149        throws XmlPullParserException, IOException {
3150
3151        TypedArray sa = res.obtainAttributes(parser,
3152                com.android.internal.R.styleable.AndroidManifestPermission);
3153
3154        Permission perm = new Permission(owner);
3155        if (!parsePackageItemInfo(owner, perm.info, outError,
3156                "<permission>", sa, true /*nameRequired*/,
3157                com.android.internal.R.styleable.AndroidManifestPermission_name,
3158                com.android.internal.R.styleable.AndroidManifestPermission_label,
3159                com.android.internal.R.styleable.AndroidManifestPermission_icon,
3160                com.android.internal.R.styleable.AndroidManifestPermission_roundIcon,
3161                com.android.internal.R.styleable.AndroidManifestPermission_logo,
3162                com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
3163            sa.recycle();
3164            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3165            return false;
3166        }
3167
3168        // Note: don't allow this value to be a reference to a resource
3169        // that may change.
3170        perm.info.group = sa.getNonResourceString(
3171                com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup);
3172        if (perm.info.group != null) {
3173            perm.info.group = perm.info.group.intern();
3174        }
3175
3176        perm.info.descriptionRes = sa.getResourceId(
3177                com.android.internal.R.styleable.AndroidManifestPermission_description,
3178                0);
3179
3180        perm.info.protectionLevel = sa.getInt(
3181                com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel,
3182                PermissionInfo.PROTECTION_NORMAL);
3183
3184        perm.info.flags = sa.getInt(
3185                com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0);
3186
3187        sa.recycle();
3188
3189        if (perm.info.protectionLevel == -1) {
3190            outError[0] = "<permission> does not specify protectionLevel";
3191            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3192            return false;
3193        }
3194
3195        perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
3196
3197        if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) {
3198            if ( (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_EPHEMERAL) == 0
3199                    && (perm.info.protectionLevel&PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) == 0
3200                    && (perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=
3201                    PermissionInfo.PROTECTION_SIGNATURE) {
3202                outError[0] = "<permission>  protectionLevel specifies a non-ephemeral flag but is "
3203                        + "not based on signature type";
3204                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3205                return false;
3206            }
3207        }
3208
3209        if (!parseAllMetaData(res, parser, "<permission>", perm, outError)) {
3210            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3211            return false;
3212        }
3213
3214        owner.permissions.add(perm);
3215
3216        return true;
3217    }
3218
3219    private boolean parsePermissionTree(Package owner, Resources res,
3220            XmlResourceParser parser, String[] outError)
3221        throws XmlPullParserException, IOException {
3222        Permission perm = new Permission(owner);
3223
3224        TypedArray sa = res.obtainAttributes(parser,
3225                com.android.internal.R.styleable.AndroidManifestPermissionTree);
3226
3227        if (!parsePackageItemInfo(owner, perm.info, outError,
3228                "<permission-tree>", sa, true /*nameRequired*/,
3229                com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
3230                com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
3231                com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
3232                com.android.internal.R.styleable.AndroidManifestPermissionTree_roundIcon,
3233                com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,
3234                com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
3235            sa.recycle();
3236            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3237            return false;
3238        }
3239
3240        sa.recycle();
3241
3242        int index = perm.info.name.indexOf('.');
3243        if (index > 0) {
3244            index = perm.info.name.indexOf('.', index+1);
3245        }
3246        if (index < 0) {
3247            outError[0] = "<permission-tree> name has less than three segments: "
3248                + perm.info.name;
3249            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3250            return false;
3251        }
3252
3253        perm.info.descriptionRes = 0;
3254        perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
3255        perm.tree = true;
3256
3257        if (!parseAllMetaData(res, parser, "<permission-tree>", perm,
3258                outError)) {
3259            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3260            return false;
3261        }
3262
3263        owner.permissions.add(perm);
3264
3265        return true;
3266    }
3267
3268    private Instrumentation parseInstrumentation(Package owner, Resources res,
3269            XmlResourceParser parser, String[] outError)
3270            throws XmlPullParserException, IOException {
3271        TypedArray sa = res.obtainAttributes(parser,
3272                com.android.internal.R.styleable.AndroidManifestInstrumentation);
3273
3274        if (mParseInstrumentationArgs == null) {
3275            mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError,
3276                    com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
3277                    com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
3278                    com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
3279                    com.android.internal.R.styleable.AndroidManifestInstrumentation_roundIcon,
3280                    com.android.internal.R.styleable.AndroidManifestInstrumentation_logo,
3281                    com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
3282            mParseInstrumentationArgs.tag = "<instrumentation>";
3283        }
3284
3285        mParseInstrumentationArgs.sa = sa;
3286
3287        Instrumentation a = new Instrumentation(mParseInstrumentationArgs,
3288                new InstrumentationInfo());
3289        if (outError[0] != null) {
3290            sa.recycle();
3291            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3292            return null;
3293        }
3294
3295        String str;
3296        // Note: don't allow this value to be a reference to a resource
3297        // that may change.
3298        str = sa.getNonResourceString(
3299                com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage);
3300        a.info.targetPackage = str != null ? str.intern() : null;
3301
3302        str = sa.getNonResourceString(
3303                com.android.internal.R.styleable.AndroidManifestInstrumentation_targetProcesses);
3304        a.info.targetProcesses = str != null ? str.intern() : null;
3305
3306        a.info.handleProfiling = sa.getBoolean(
3307                com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling,
3308                false);
3309
3310        a.info.functionalTest = sa.getBoolean(
3311                com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest,
3312                false);
3313
3314        sa.recycle();
3315
3316        if (a.info.targetPackage == null) {
3317            outError[0] = "<instrumentation> does not specify targetPackage";
3318            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3319            return null;
3320        }
3321
3322        if (!parseAllMetaData(res, parser, "<instrumentation>", a,
3323                outError)) {
3324            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3325            return null;
3326        }
3327
3328        owner.instrumentation.add(a);
3329
3330        return a;
3331    }
3332
3333    /**
3334     * Parse the {@code application} XML tree at the current parse location in a
3335     * <em>base APK</em> manifest.
3336     * <p>
3337     * When adding new features, carefully consider if they should also be
3338     * supported by split APKs.
3339     */
3340    private boolean parseBaseApplication(Package owner, Resources res,
3341            XmlResourceParser parser, int flags, String[] outError)
3342        throws XmlPullParserException, IOException {
3343        final ApplicationInfo ai = owner.applicationInfo;
3344        final String pkgName = owner.applicationInfo.packageName;
3345
3346        TypedArray sa = res.obtainAttributes(parser,
3347                com.android.internal.R.styleable.AndroidManifestApplication);
3348
3349        if (!parsePackageItemInfo(owner, ai, outError,
3350                "<application>", sa, false /*nameRequired*/,
3351                com.android.internal.R.styleable.AndroidManifestApplication_name,
3352                com.android.internal.R.styleable.AndroidManifestApplication_label,
3353                com.android.internal.R.styleable.AndroidManifestApplication_icon,
3354                com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,
3355                com.android.internal.R.styleable.AndroidManifestApplication_logo,
3356                com.android.internal.R.styleable.AndroidManifestApplication_banner)) {
3357            sa.recycle();
3358            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3359            return false;
3360        }
3361
3362        if (ai.name != null) {
3363            ai.className = ai.name;
3364        }
3365
3366        String manageSpaceActivity = sa.getNonConfigurationString(
3367                com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
3368                Configuration.NATIVE_CONFIG_VERSION);
3369        if (manageSpaceActivity != null) {
3370            ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
3371                    outError);
3372        }
3373
3374        boolean allowBackup = sa.getBoolean(
3375                com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
3376        if (allowBackup) {
3377            ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
3378
3379            // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
3380            // and restoreAnyVersion are only relevant if backup is possible for the
3381            // given application.
3382            String backupAgent = sa.getNonConfigurationString(
3383                    com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
3384                    Configuration.NATIVE_CONFIG_VERSION);
3385            if (backupAgent != null) {
3386                ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
3387                if (DEBUG_BACKUP) {
3388                    Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName
3389                            + " from " + pkgName + "+" + backupAgent);
3390                }
3391
3392                if (sa.getBoolean(
3393                        com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore,
3394                        true)) {
3395                    ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
3396                }
3397                if (sa.getBoolean(
3398                        com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion,
3399                        false)) {
3400                    ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
3401                }
3402                if (sa.getBoolean(
3403                        com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly,
3404                        false)) {
3405                    ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
3406                }
3407                if (sa.getBoolean(
3408                        com.android.internal.R.styleable.AndroidManifestApplication_backupInForeground,
3409                        false)) {
3410                    ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
3411                }
3412            }
3413
3414            TypedValue v = sa.peekValue(
3415                    com.android.internal.R.styleable.AndroidManifestApplication_fullBackupContent);
3416            if (v != null && (ai.fullBackupContent = v.resourceId) == 0) {
3417                if (DEBUG_BACKUP) {
3418                    Slog.v(TAG, "fullBackupContent specified as boolean=" +
3419                            (v.data == 0 ? "false" : "true"));
3420                }
3421                // "false" => -1, "true" => 0
3422                ai.fullBackupContent = (v.data == 0 ? -1 : 0);
3423            }
3424            if (DEBUG_BACKUP) {
3425                Slog.v(TAG, "fullBackupContent=" + ai.fullBackupContent + " for " + pkgName);
3426            }
3427        }
3428
3429        ai.theme = sa.getResourceId(
3430                com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
3431        ai.descriptionRes = sa.getResourceId(
3432                com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
3433
3434        if ((flags&PARSE_IS_SYSTEM) != 0) {
3435            if (sa.getBoolean(
3436                    com.android.internal.R.styleable.AndroidManifestApplication_persistent,
3437                    false)) {
3438                // Check if persistence is based on a feature being present
3439                final String requiredFeature = sa.getNonResourceString(
3440                    com.android.internal.R.styleable.
3441                    AndroidManifestApplication_persistentWhenFeatureAvailable);
3442                if (requiredFeature == null || mCallback.hasFeature(requiredFeature)) {
3443                    ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
3444                }
3445            }
3446        }
3447
3448        if (sa.getBoolean(
3449                com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers,
3450                false)) {
3451            owner.mRequiredForAllUsers = true;
3452        }
3453
3454        String restrictedAccountType = sa.getString(com.android.internal.R.styleable
3455                .AndroidManifestApplication_restrictedAccountType);
3456        if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
3457            owner.mRestrictedAccountType = restrictedAccountType;
3458        }
3459
3460        String requiredAccountType = sa.getString(com.android.internal.R.styleable
3461                .AndroidManifestApplication_requiredAccountType);
3462        if (requiredAccountType != null && requiredAccountType.length() > 0) {
3463            owner.mRequiredAccountType = requiredAccountType;
3464        }
3465
3466        if (sa.getBoolean(
3467                com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
3468                false)) {
3469            ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
3470        }
3471
3472        if (sa.getBoolean(
3473                com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode,
3474                false)) {
3475            ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE;
3476        }
3477
3478        owner.baseHardwareAccelerated = sa.getBoolean(
3479                com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
3480                owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
3481        if (owner.baseHardwareAccelerated) {
3482            ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
3483        }
3484
3485        if (sa.getBoolean(
3486                com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
3487                true)) {
3488            ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
3489        }
3490
3491        if (sa.getBoolean(
3492                com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
3493                false)) {
3494            ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
3495        }
3496
3497        if (sa.getBoolean(
3498                com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
3499                true)) {
3500            ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
3501        }
3502
3503        // The parent package controls installation, hence specify test only installs.
3504        if (owner.parentPackage == null) {
3505            if (sa.getBoolean(
3506                    com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
3507                    false)) {
3508                ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
3509            }
3510        }
3511
3512        if (sa.getBoolean(
3513                com.android.internal.R.styleable.AndroidManifestApplication_largeHeap,
3514                false)) {
3515            ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP;
3516        }
3517
3518        if (sa.getBoolean(
3519                com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic,
3520                true)) {
3521            ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
3522        }
3523
3524        if (sa.getBoolean(
3525                com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl,
3526                false /* default is no RTL support*/)) {
3527            ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
3528        }
3529
3530        if (sa.getBoolean(
3531                com.android.internal.R.styleable.AndroidManifestApplication_multiArch,
3532                false)) {
3533            ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
3534        }
3535
3536        if (sa.getBoolean(
3537                com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
3538                true)) {
3539            ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
3540        }
3541
3542        if (sa.getBoolean(
3543                R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
3544                false)) {
3545            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
3546        }
3547        if (sa.getBoolean(
3548                R.styleable.AndroidManifestApplication_directBootAware,
3549                false)) {
3550            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
3551        }
3552
3553        if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
3554            if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity, true)) {
3555                ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
3556            } else {
3557                ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
3558            }
3559        } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
3560            ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
3561        }
3562
3563        ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0);
3564
3565        ai.networkSecurityConfigRes = sa.getResourceId(
3566                com.android.internal.R.styleable.AndroidManifestApplication_networkSecurityConfig,
3567                0);
3568        ai.category = sa.getInt(
3569                com.android.internal.R.styleable.AndroidManifestApplication_appCategory,
3570                ApplicationInfo.CATEGORY_UNDEFINED);
3571
3572        String str;
3573        str = sa.getNonConfigurationString(
3574                com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
3575        ai.permission = (str != null && str.length() > 0) ? str.intern() : null;
3576
3577        if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
3578            str = sa.getNonConfigurationString(
3579                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity,
3580                    Configuration.NATIVE_CONFIG_VERSION);
3581        } else {
3582            // Some older apps have been seen to use a resource reference
3583            // here that on older builds was ignored (with a warning).  We
3584            // need to continue to do this for them so they don't break.
3585            str = sa.getNonResourceString(
3586                    com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
3587        }
3588        ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
3589                str, outError);
3590
3591        if (outError[0] == null) {
3592            CharSequence pname;
3593            if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
3594                pname = sa.getNonConfigurationString(
3595                        com.android.internal.R.styleable.AndroidManifestApplication_process,
3596                        Configuration.NATIVE_CONFIG_VERSION);
3597            } else {
3598                // Some older apps have been seen to use a resource reference
3599                // here that on older builds was ignored (with a warning).  We
3600                // need to continue to do this for them so they don't break.
3601                pname = sa.getNonResourceString(
3602                        com.android.internal.R.styleable.AndroidManifestApplication_process);
3603            }
3604            ai.processName = buildProcessName(ai.packageName, null, pname,
3605                    flags, mSeparateProcesses, outError);
3606
3607            ai.enabled = sa.getBoolean(
3608                    com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
3609
3610            if (sa.getBoolean(
3611                    com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) {
3612                ai.flags |= ApplicationInfo.FLAG_IS_GAME;
3613            }
3614
3615            if (false) {
3616                if (sa.getBoolean(
3617                        com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
3618                        false)) {
3619                    ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
3620
3621                    // A heavy-weight application can not be in a custom process.
3622                    // We can do direct compare because we intern all strings.
3623                    if (ai.processName != null && ai.processName != ai.packageName) {
3624                        outError[0] = "cantSaveState applications can not use custom processes";
3625                    }
3626                }
3627            }
3628        }
3629
3630        ai.uiOptions = sa.getInt(
3631                com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);
3632
3633        sa.recycle();
3634
3635        if (outError[0] != null) {
3636            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3637            return false;
3638        }
3639
3640        final int innerDepth = parser.getDepth();
3641        int type;
3642        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3643                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
3644            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3645                continue;
3646            }
3647
3648            String tagName = parser.getName();
3649            if (tagName.equals("activity")) {
3650                Activity a = parseActivity(owner, res, parser, flags, outError, false,
3651                        owner.baseHardwareAccelerated);
3652                if (a == null) {
3653                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3654                    return false;
3655                }
3656
3657                owner.activities.add(a);
3658
3659            } else if (tagName.equals("receiver")) {
3660                Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
3661                if (a == null) {
3662                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3663                    return false;
3664                }
3665
3666                owner.receivers.add(a);
3667
3668            } else if (tagName.equals("service")) {
3669                Service s = parseService(owner, res, parser, flags, outError);
3670                if (s == null) {
3671                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3672                    return false;
3673                }
3674
3675                owner.services.add(s);
3676
3677            } else if (tagName.equals("provider")) {
3678                Provider p = parseProvider(owner, res, parser, flags, outError);
3679                if (p == null) {
3680                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3681                    return false;
3682                }
3683
3684                owner.providers.add(p);
3685
3686            } else if (tagName.equals("activity-alias")) {
3687                Activity a = parseActivityAlias(owner, res, parser, flags, outError);
3688                if (a == null) {
3689                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3690                    return false;
3691                }
3692
3693                owner.activities.add(a);
3694
3695            } else if (parser.getName().equals("meta-data")) {
3696                // note: application meta-data is stored off to the side, so it can
3697                // remain null in the primary copy (we like to avoid extra copies because
3698                // it can be large)
3699                if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
3700                        outError)) == null) {
3701                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3702                    return false;
3703                }
3704            } else if (tagName.equals("static-library")) {
3705                sa = res.obtainAttributes(parser,
3706                        com.android.internal.R.styleable.AndroidManifestStaticLibrary);
3707
3708                // Note: don't allow this value to be a reference to a resource
3709                // that may change.
3710                final String lname = sa.getNonResourceString(
3711                        com.android.internal.R.styleable.AndroidManifestStaticLibrary_name);
3712                final int version = sa.getInt(
3713                        com.android.internal.R.styleable.AndroidManifestStaticLibrary_version, -1);
3714
3715                sa.recycle();
3716
3717                // Since the app canot run without a static lib - fail if malformed
3718                if (lname == null || version < 0) {
3719                    outError[0] = "Bad static-library declaration name: " + lname
3720                            + " version: " + version;
3721                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3722                    XmlUtils.skipCurrentTag(parser);
3723                    return false;
3724                }
3725
3726                if (owner.mSharedUserId != null) {
3727                    outError[0] = "sharedUserId not allowed in static shared library";
3728                    mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
3729                    XmlUtils.skipCurrentTag(parser);
3730                    return false;
3731                }
3732
3733                if (owner.staticSharedLibName != null) {
3734                    outError[0] = "Multiple static-shared libs for package " + pkgName;
3735                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3736                    XmlUtils.skipCurrentTag(parser);
3737                    return false;
3738                }
3739
3740                owner.staticSharedLibName = lname.intern();
3741                owner.staticSharedLibVersion = version;
3742                ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY;
3743
3744                XmlUtils.skipCurrentTag(parser);
3745
3746            } else if (tagName.equals("library")) {
3747                sa = res.obtainAttributes(parser,
3748                        com.android.internal.R.styleable.AndroidManifestLibrary);
3749
3750                // Note: don't allow this value to be a reference to a resource
3751                // that may change.
3752                String lname = sa.getNonResourceString(
3753                        com.android.internal.R.styleable.AndroidManifestLibrary_name);
3754
3755                sa.recycle();
3756
3757                if (lname != null) {
3758                    lname = lname.intern();
3759                    if (!ArrayUtils.contains(owner.libraryNames, lname)) {
3760                        owner.libraryNames = ArrayUtils.add(
3761                                owner.libraryNames, lname);
3762                    }
3763                }
3764
3765                XmlUtils.skipCurrentTag(parser);
3766
3767            } else if (tagName.equals("uses-static-library")) {
3768                if (!parseUsesStaticLibrary(owner, res, parser, outError)) {
3769                    return false;
3770                }
3771
3772            } else if (tagName.equals("uses-library")) {
3773                sa = res.obtainAttributes(parser,
3774                        com.android.internal.R.styleable.AndroidManifestUsesLibrary);
3775
3776                // Note: don't allow this value to be a reference to a resource
3777                // that may change.
3778                String lname = sa.getNonResourceString(
3779                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
3780                boolean req = sa.getBoolean(
3781                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
3782                        true);
3783
3784                sa.recycle();
3785
3786                if (lname != null) {
3787                    lname = lname.intern();
3788                    if (req) {
3789                        owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
3790                    } else {
3791                        owner.usesOptionalLibraries = ArrayUtils.add(
3792                                owner.usesOptionalLibraries, lname);
3793                    }
3794                }
3795
3796                XmlUtils.skipCurrentTag(parser);
3797
3798            } else if (tagName.equals("uses-package")) {
3799                // Dependencies for app installers; we don't currently try to
3800                // enforce this.
3801                XmlUtils.skipCurrentTag(parser);
3802
3803            } else {
3804                if (!RIGID_PARSER) {
3805                    Slog.w(TAG, "Unknown element under <application>: " + tagName
3806                            + " at " + mArchiveSourcePath + " "
3807                            + parser.getPositionDescription());
3808                    XmlUtils.skipCurrentTag(parser);
3809                    continue;
3810                } else {
3811                    outError[0] = "Bad element under <application>: " + tagName;
3812                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3813                    return false;
3814                }
3815            }
3816        }
3817
3818        modifySharedLibrariesForBackwardCompatibility(owner);
3819
3820        if (hasDomainURLs(owner)) {
3821            owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
3822        } else {
3823            owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
3824        }
3825
3826        return true;
3827    }
3828
3829    private static void modifySharedLibrariesForBackwardCompatibility(Package owner) {
3830        // "org.apache.http.legacy" is now a part of the boot classpath so it doesn't need
3831        // to be an explicit dependency.
3832        //
3833        // A future change will remove this library from the boot classpath, at which point
3834        // all apps that target SDK 21 and earlier will have it automatically added to their
3835        // dependency lists.
3836        owner.usesLibraries = ArrayUtils.remove(owner.usesLibraries, "org.apache.http.legacy");
3837        owner.usesOptionalLibraries = ArrayUtils.remove(owner.usesOptionalLibraries,
3838                "org.apache.http.legacy");
3839    }
3840
3841    /**
3842     * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
3843     */
3844    private static boolean hasDomainURLs(Package pkg) {
3845        if (pkg == null || pkg.activities == null) return false;
3846        final ArrayList<Activity> activities = pkg.activities;
3847        final int countActivities = activities.size();
3848        for (int n=0; n<countActivities; n++) {
3849            Activity activity = activities.get(n);
3850            ArrayList<ActivityIntentInfo> filters = activity.intents;
3851            if (filters == null) continue;
3852            final int countFilters = filters.size();
3853            for (int m=0; m<countFilters; m++) {
3854                ActivityIntentInfo aii = filters.get(m);
3855                if (!aii.hasAction(Intent.ACTION_VIEW)) continue;
3856                if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue;
3857                if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
3858                        aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
3859                    return true;
3860                }
3861            }
3862        }
3863        return false;
3864    }
3865
3866    /**
3867     * Parse the {@code application} XML tree at the current parse location in a
3868     * <em>split APK</em> manifest.
3869     * <p>
3870     * Note that split APKs have many more restrictions on what they're capable
3871     * of doing, so many valid features of a base APK have been carefully
3872     * omitted here.
3873     */
3874    private boolean parseSplitApplication(Package owner, Resources res, XmlResourceParser parser,
3875            int flags, int splitIndex, String[] outError)
3876            throws XmlPullParserException, IOException {
3877        TypedArray sa = res.obtainAttributes(parser,
3878                com.android.internal.R.styleable.AndroidManifestApplication);
3879
3880        if (sa.getBoolean(
3881                com.android.internal.R.styleable.AndroidManifestApplication_hasCode, true)) {
3882            owner.splitFlags[splitIndex] |= ApplicationInfo.FLAG_HAS_CODE;
3883        }
3884
3885        final int innerDepth = parser.getDepth();
3886        int type;
3887        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3888                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
3889            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3890                continue;
3891            }
3892
3893            ComponentInfo parsedComponent = null;
3894
3895            String tagName = parser.getName();
3896            if (tagName.equals("activity")) {
3897                Activity a = parseActivity(owner, res, parser, flags, outError, false,
3898                        owner.baseHardwareAccelerated);
3899                if (a == null) {
3900                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3901                    return false;
3902                }
3903
3904                owner.activities.add(a);
3905                parsedComponent = a.info;
3906
3907            } else if (tagName.equals("receiver")) {
3908                Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
3909                if (a == null) {
3910                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3911                    return false;
3912                }
3913
3914                owner.receivers.add(a);
3915                parsedComponent = a.info;
3916
3917            } else if (tagName.equals("service")) {
3918                Service s = parseService(owner, res, parser, flags, outError);
3919                if (s == null) {
3920                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3921                    return false;
3922                }
3923
3924                owner.services.add(s);
3925                parsedComponent = s.info;
3926
3927            } else if (tagName.equals("provider")) {
3928                Provider p = parseProvider(owner, res, parser, flags, outError);
3929                if (p == null) {
3930                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3931                    return false;
3932                }
3933
3934                owner.providers.add(p);
3935                parsedComponent = p.info;
3936
3937            } else if (tagName.equals("activity-alias")) {
3938                Activity a = parseActivityAlias(owner, res, parser, flags, outError);
3939                if (a == null) {
3940                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3941                    return false;
3942                }
3943
3944                owner.activities.add(a);
3945                parsedComponent = a.info;
3946
3947            } else if (parser.getName().equals("meta-data")) {
3948                // note: application meta-data is stored off to the side, so it can
3949                // remain null in the primary copy (we like to avoid extra copies because
3950                // it can be large)
3951                if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
3952                        outError)) == null) {
3953                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3954                    return false;
3955                }
3956
3957            } else if (tagName.equals("uses-static-library")) {
3958                if (!parseUsesStaticLibrary(owner, res, parser, outError)) {
3959                    return false;
3960                }
3961
3962            } else if (tagName.equals("uses-library")) {
3963                sa = res.obtainAttributes(parser,
3964                        com.android.internal.R.styleable.AndroidManifestUsesLibrary);
3965
3966                // Note: don't allow this value to be a reference to a resource
3967                // that may change.
3968                String lname = sa.getNonResourceString(
3969                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
3970                boolean req = sa.getBoolean(
3971                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
3972                        true);
3973
3974                sa.recycle();
3975
3976                if (lname != null) {
3977                    lname = lname.intern();
3978                    if (req) {
3979                        // Upgrade to treat as stronger constraint
3980                        owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
3981                        owner.usesOptionalLibraries = ArrayUtils.remove(
3982                                owner.usesOptionalLibraries, lname);
3983                    } else {
3984                        // Ignore if someone already defined as required
3985                        if (!ArrayUtils.contains(owner.usesLibraries, lname)) {
3986                            owner.usesOptionalLibraries = ArrayUtils.add(
3987                                    owner.usesOptionalLibraries, lname);
3988                        }
3989                    }
3990                }
3991
3992                XmlUtils.skipCurrentTag(parser);
3993
3994            } else if (tagName.equals("uses-package")) {
3995                // Dependencies for app installers; we don't currently try to
3996                // enforce this.
3997                XmlUtils.skipCurrentTag(parser);
3998
3999            } else {
4000                if (!RIGID_PARSER) {
4001                    Slog.w(TAG, "Unknown element under <application>: " + tagName
4002                            + " at " + mArchiveSourcePath + " "
4003                            + parser.getPositionDescription());
4004                    XmlUtils.skipCurrentTag(parser);
4005                    continue;
4006                } else {
4007                    outError[0] = "Bad element under <application>: " + tagName;
4008                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
4009                    return false;
4010                }
4011            }
4012
4013            if (parsedComponent != null && parsedComponent.splitName == null) {
4014                // If the loaded component did not specify a split, inherit the split name
4015                // based on the split it is defined in.
4016                // This is used to later load the correct split when starting this
4017                // component.
4018                parsedComponent.splitName = owner.splitNames[splitIndex];
4019            }
4020        }
4021
4022        return true;
4023    }
4024
4025    private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
4026            String[] outError, String tag, TypedArray sa, boolean nameRequired,
4027            int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
4028        // This case can only happen in unit tests where we sometimes need to create fakes
4029        // of various package parser data structures.
4030        if (sa == null) {
4031            outError[0] = tag + " does not contain any attributes";
4032            return false;
4033        }
4034
4035        String name = sa.getNonConfigurationString(nameRes, 0);
4036        if (name == null) {
4037            if (nameRequired) {
4038                outError[0] = tag + " does not specify android:name";
4039                return false;
4040            }
4041        } else {
4042            outInfo.name
4043                = buildClassName(owner.applicationInfo.packageName, name, outError);
4044            if (outInfo.name == null) {
4045                return false;
4046            }
4047        }
4048
4049        final boolean useRoundIcon =
4050                Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
4051        int roundIconVal = useRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
4052        if (roundIconVal != 0) {
4053            outInfo.icon = roundIconVal;
4054            outInfo.nonLocalizedLabel = null;
4055        } else {
4056            int iconVal = sa.getResourceId(iconRes, 0);
4057            if (iconVal != 0) {
4058                outInfo.icon = iconVal;
4059                outInfo.nonLocalizedLabel = null;
4060            }
4061        }
4062
4063        int logoVal = sa.getResourceId(logoRes, 0);
4064        if (logoVal != 0) {
4065            outInfo.logo = logoVal;
4066        }
4067
4068        int bannerVal = sa.getResourceId(bannerRes, 0);
4069        if (bannerVal != 0) {
4070            outInfo.banner = bannerVal;
4071        }
4072
4073        TypedValue v = sa.peekValue(labelRes);
4074        if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
4075            outInfo.nonLocalizedLabel = v.coerceToString();
4076        }
4077
4078        outInfo.packageName = owner.packageName;
4079
4080        return true;
4081    }
4082
4083    private Activity parseActivity(Package owner, Resources res,
4084            XmlResourceParser parser, int flags, String[] outError,
4085            boolean receiver, boolean hardwareAccelerated)
4086            throws XmlPullParserException, IOException {
4087        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
4088
4089        if (mParseActivityArgs == null) {
4090            mParseActivityArgs = new ParseComponentArgs(owner, outError,
4091                    R.styleable.AndroidManifestActivity_name,
4092                    R.styleable.AndroidManifestActivity_label,
4093                    R.styleable.AndroidManifestActivity_icon,
4094                    R.styleable.AndroidManifestActivity_roundIcon,
4095                    R.styleable.AndroidManifestActivity_logo,
4096                    R.styleable.AndroidManifestActivity_banner,
4097                    mSeparateProcesses,
4098                    R.styleable.AndroidManifestActivity_process,
4099                    R.styleable.AndroidManifestActivity_description,
4100                    R.styleable.AndroidManifestActivity_enabled);
4101        }
4102
4103        mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
4104        mParseActivityArgs.sa = sa;
4105        mParseActivityArgs.flags = flags;
4106
4107        Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
4108        if (outError[0] != null) {
4109            sa.recycle();
4110            return null;
4111        }
4112
4113        boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
4114        if (setExported) {
4115            a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false);
4116        }
4117
4118        a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
4119
4120        a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
4121                a.info.applicationInfo.uiOptions);
4122
4123        String parentName = sa.getNonConfigurationString(
4124                R.styleable.AndroidManifestActivity_parentActivityName,
4125                Configuration.NATIVE_CONFIG_VERSION);
4126        if (parentName != null) {
4127            String parentClassName = buildClassName(a.info.packageName, parentName, outError);
4128            if (outError[0] == null) {
4129                a.info.parentActivityName = parentClassName;
4130            } else {
4131                Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " +
4132                        parentName);
4133                outError[0] = null;
4134            }
4135        }
4136
4137        String str;
4138        str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
4139        if (str == null) {
4140            a.info.permission = owner.applicationInfo.permission;
4141        } else {
4142            a.info.permission = str.length() > 0 ? str.toString().intern() : null;
4143        }
4144
4145        str = sa.getNonConfigurationString(
4146                R.styleable.AndroidManifestActivity_taskAffinity,
4147                Configuration.NATIVE_CONFIG_VERSION);
4148        a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
4149                owner.applicationInfo.taskAffinity, str, outError);
4150
4151        a.info.splitName =
4152                sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0);
4153
4154        a.info.flags = 0;
4155        if (sa.getBoolean(
4156                R.styleable.AndroidManifestActivity_multiprocess, false)) {
4157            a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
4158        }
4159
4160        if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
4161            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
4162        }
4163
4164        if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
4165            a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
4166        }
4167
4168        if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
4169            a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
4170        }
4171
4172        if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
4173            a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
4174        }
4175
4176        if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
4177            a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
4178        }
4179
4180        if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
4181            a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
4182        }
4183
4184        if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
4185                (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
4186            a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
4187        }
4188
4189        if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) {
4190            a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
4191        }
4192
4193        if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
4194                || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
4195            a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
4196        }
4197
4198        if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
4199            a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
4200        }
4201
4202        if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
4203            a.info.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
4204        }
4205
4206        if (!receiver) {
4207            if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
4208                    hardwareAccelerated)) {
4209                a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
4210            }
4211
4212            a.info.launchMode = sa.getInt(
4213                    R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
4214            a.info.documentLaunchMode = sa.getInt(
4215                    R.styleable.AndroidManifestActivity_documentLaunchMode,
4216                    ActivityInfo.DOCUMENT_LAUNCH_NONE);
4217            a.info.maxRecents = sa.getInt(
4218                    R.styleable.AndroidManifestActivity_maxRecents,
4219                    ActivityManager.getDefaultAppRecentsLimitStatic());
4220            a.info.configChanges = getActivityConfigChanges(
4221                    sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
4222                    sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
4223            a.info.softInputMode = sa.getInt(
4224                    R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
4225
4226            a.info.persistableMode = sa.getInteger(
4227                    R.styleable.AndroidManifestActivity_persistableMode,
4228                    ActivityInfo.PERSIST_ROOT_ONLY);
4229
4230            if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
4231                a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
4232            }
4233
4234            if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) {
4235                a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
4236            }
4237
4238            if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) {
4239                a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
4240            }
4241
4242            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
4243                a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
4244            }
4245
4246            a.info.screenOrientation = sa.getInt(
4247                    R.styleable.AndroidManifestActivity_screenOrientation,
4248                    SCREEN_ORIENTATION_UNSPECIFIED);
4249
4250            setActivityResizeMode(a.info, sa, owner);
4251
4252            if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
4253                    false)) {
4254                a.info.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE;
4255            }
4256
4257            if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
4258                a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
4259            }
4260
4261            setActivityMaxAspectRatio(a.info, sa, owner);
4262
4263            a.info.lockTaskLaunchMode =
4264                    sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
4265
4266            a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
4267                    R.styleable.AndroidManifestActivity_directBootAware,
4268                    false);
4269
4270            a.info.requestedVrComponent =
4271                sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
4272
4273            a.info.rotationAnimation =
4274                sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, ROTATION_ANIMATION_ROTATE);
4275
4276            a.info.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
4277                    ActivityInfo.COLOR_MODE_DEFAULT);
4278        } else {
4279            a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
4280            a.info.configChanges = 0;
4281
4282            if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
4283                a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
4284                if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
4285                    Slog.w(TAG, "Activity exported request ignored due to singleUser: "
4286                            + a.className + " at " + mArchiveSourcePath + " "
4287                            + parser.getPositionDescription());
4288                    a.info.exported = false;
4289                    setExported = true;
4290                }
4291            }
4292
4293            a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
4294                    R.styleable.AndroidManifestActivity_directBootAware,
4295                    false);
4296        }
4297
4298        if (a.info.directBootAware) {
4299            owner.applicationInfo.privateFlags |=
4300                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
4301        }
4302
4303        // can't make this final; we may set it later via meta-data
4304        boolean visibleToEphemeral =
4305                sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
4306        if (visibleToEphemeral) {
4307            a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4308            owner.visibleToInstantApps = true;
4309        }
4310
4311        sa.recycle();
4312
4313        if (receiver && (owner.applicationInfo.privateFlags
4314                &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
4315            // A heavy-weight application can not have receives in its main process
4316            // We can do direct compare because we intern all strings.
4317            if (a.info.processName == owner.packageName) {
4318                outError[0] = "Heavy-weight applications can not have receivers in main process";
4319            }
4320        }
4321
4322        if (outError[0] != null) {
4323            return null;
4324        }
4325
4326        int outerDepth = parser.getDepth();
4327        int type;
4328        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4329               && (type != XmlPullParser.END_TAG
4330                       || parser.getDepth() > outerDepth)) {
4331            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4332                continue;
4333            }
4334
4335            if (parser.getName().equals("intent-filter")) {
4336                ActivityIntentInfo intent = new ActivityIntentInfo(a);
4337                if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
4338                        intent, outError)) {
4339                    return null;
4340                }
4341                if (intent.countActions() == 0) {
4342                    Slog.w(TAG, "No actions in intent filter at "
4343                            + mArchiveSourcePath + " "
4344                            + parser.getPositionDescription());
4345                } else {
4346                    a.intents.add(intent);
4347                }
4348                // adjust activity flags when we implicitly expose it via a browsable filter
4349                final int visibility = visibleToEphemeral
4350                        ? IntentFilter.VISIBILITY_EXPLICIT
4351                        : !receiver && isImplicitlyExposedIntent(intent)
4352                                ? IntentFilter.VISIBILITY_IMPLICIT
4353                                : IntentFilter.VISIBILITY_NONE;
4354                intent.setVisibilityToInstantApp(visibility);
4355                if (intent.isVisibleToInstantApp()) {
4356                    a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4357                }
4358                if (intent.isImplicitlyVisibleToInstantApp()) {
4359                    a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
4360                }
4361                if (LOG_UNSAFE_BROADCASTS && receiver
4362                        && (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O)) {
4363                    for (int i = 0; i < intent.countActions(); i++) {
4364                        final String action = intent.getAction(i);
4365                        if (action == null || !action.startsWith("android.")) continue;
4366                        if (!SAFE_BROADCASTS.contains(action)) {
4367                            Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
4368                                    + owner.packageName + " as requested at: "
4369                                    + parser.getPositionDescription());
4370                        }
4371                    }
4372                }
4373            } else if (!receiver && parser.getName().equals("preferred")) {
4374                ActivityIntentInfo intent = new ActivityIntentInfo(a);
4375                if (!parseIntent(res, parser, false /*allowGlobs*/, false /*allowAutoVerify*/,
4376                        intent, outError)) {
4377                    return null;
4378                }
4379                if (intent.countActions() == 0) {
4380                    Slog.w(TAG, "No actions in preferred at "
4381                            + mArchiveSourcePath + " "
4382                            + parser.getPositionDescription());
4383                } else {
4384                    if (owner.preferredActivityFilters == null) {
4385                        owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
4386                    }
4387                    owner.preferredActivityFilters.add(intent);
4388                }
4389                // adjust activity flags when we implicitly expose it via a browsable filter
4390                final int visibility = visibleToEphemeral
4391                        ? IntentFilter.VISIBILITY_EXPLICIT
4392                        : !receiver && isImplicitlyExposedIntent(intent)
4393                                ? IntentFilter.VISIBILITY_IMPLICIT
4394                                : IntentFilter.VISIBILITY_NONE;
4395                intent.setVisibilityToInstantApp(visibility);
4396                if (intent.isVisibleToInstantApp()) {
4397                    a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4398                }
4399                if (intent.isImplicitlyVisibleToInstantApp()) {
4400                    a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
4401                }
4402            } else if (parser.getName().equals("meta-data")) {
4403                if ((a.metaData = parseMetaData(res, parser, a.metaData,
4404                        outError)) == null) {
4405                    return null;
4406                }
4407                // we don't have an attribute [or it's false], but, we have meta-data
4408                if (!visibleToEphemeral && a.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
4409                    visibleToEphemeral = true; // set in case there are more intent filters
4410                    a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4411                    a.info.flags &= ~ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
4412                    owner.visibleToInstantApps = true;
4413                    // cycle through any filters already seen
4414                    for (int i = a.intents.size() - 1; i >= 0; --i) {
4415                        a.intents.get(i)
4416                                .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
4417                    }
4418                    if (owner.preferredActivityFilters != null) {
4419                        for (int i = owner.preferredActivityFilters.size() - 1; i >= 0; --i) {
4420                            owner.preferredActivityFilters.get(i)
4421                                    .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
4422                        }
4423                    }
4424                }
4425            } else if (!receiver && parser.getName().equals("layout")) {
4426                parseLayout(res, parser, a);
4427            } else {
4428                if (!RIGID_PARSER) {
4429                    Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
4430                    if (receiver) {
4431                        Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
4432                                + " at " + mArchiveSourcePath + " "
4433                                + parser.getPositionDescription());
4434                    } else {
4435                        Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
4436                                + " at " + mArchiveSourcePath + " "
4437                                + parser.getPositionDescription());
4438                    }
4439                    XmlUtils.skipCurrentTag(parser);
4440                    continue;
4441                } else {
4442                    if (receiver) {
4443                        outError[0] = "Bad element under <receiver>: " + parser.getName();
4444                    } else {
4445                        outError[0] = "Bad element under <activity>: " + parser.getName();
4446                    }
4447                    return null;
4448                }
4449            }
4450        }
4451
4452        if (!setExported) {
4453            a.info.exported = a.intents.size() > 0;
4454        }
4455
4456        return a;
4457    }
4458
4459    private void setActivityResizeMode(ActivityInfo aInfo, TypedArray sa, Package owner) {
4460        final boolean appExplicitDefault = (owner.applicationInfo.privateFlags
4461                & (PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
4462                | PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0;
4463
4464        if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity)
4465                || appExplicitDefault) {
4466            // Activity or app explicitly set if it is resizeable or not;
4467            final boolean appResizeable = (owner.applicationInfo.privateFlags
4468                    & PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0;
4469            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
4470                    appResizeable)) {
4471                aInfo.resizeMode = RESIZE_MODE_RESIZEABLE;
4472            } else {
4473                aInfo.resizeMode = RESIZE_MODE_UNRESIZEABLE;
4474            }
4475            return;
4476        }
4477
4478        if ((owner.applicationInfo.privateFlags
4479                & PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) != 0) {
4480            // The activity or app didn't explicitly set the resizing option, however we want to
4481            // make it resize due to the sdk version it is targeting.
4482            aInfo.resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
4483            return;
4484        }
4485
4486        // resize preference isn't set and target sdk version doesn't support resizing apps by
4487        // default. For the app to be resizeable if it isn't fixed orientation or immersive.
4488        if (aInfo.isFixedOrientationPortrait()) {
4489            aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
4490        } else if (aInfo.isFixedOrientationLandscape()) {
4491            aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
4492        } else if (aInfo.isFixedOrientation()) {
4493            aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
4494        } else {
4495            aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
4496        }
4497    }
4498
4499    private void setActivityMaxAspectRatio(ActivityInfo aInfo, TypedArray sa, Package owner) {
4500        if (aInfo.resizeMode == RESIZE_MODE_RESIZEABLE
4501                || aInfo.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
4502            // Resizeable activities can be put in any aspect ratio.
4503            aInfo.maxAspectRatio = 0;
4504            return;
4505        }
4506
4507        // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater.
4508        // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD.
4509        float defaultMaxAspectRatio = owner.applicationInfo.targetSdkVersion < O
4510                ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
4511        if (owner.applicationInfo.maxAspectRatio != 0 ) {
4512            // Use the application max aspect ration as default if set.
4513            defaultMaxAspectRatio = owner.applicationInfo.maxAspectRatio;
4514        }
4515
4516        aInfo.maxAspectRatio = sa.getFloat(
4517                R.styleable.AndroidManifestActivity_maxAspectRatio, defaultMaxAspectRatio);
4518        if (aInfo.maxAspectRatio < 1.0f && aInfo.maxAspectRatio != 0) {
4519            // Ignore any value lesser than 1.0.
4520            aInfo.maxAspectRatio = 0;
4521        }
4522    }
4523
4524    /**
4525     * @param configChanges The bit mask of configChanges fetched from AndroidManifest.xml.
4526     * @param recreateOnConfigChanges The bit mask recreateOnConfigChanges fetched from
4527     *                                AndroidManifest.xml.
4528     * @hide Exposed for unit testing only.
4529     */
4530    @TestApi
4531    public static int getActivityConfigChanges(int configChanges, int recreateOnConfigChanges) {
4532        return configChanges | ((~recreateOnConfigChanges) & RECREATE_ON_CONFIG_CHANGES_MASK);
4533    }
4534
4535    private void parseLayout(Resources res, AttributeSet attrs, Activity a) {
4536        TypedArray sw = res.obtainAttributes(attrs,
4537                com.android.internal.R.styleable.AndroidManifestLayout);
4538        int width = -1;
4539        float widthFraction = -1f;
4540        int height = -1;
4541        float heightFraction = -1f;
4542        final int widthType = sw.getType(
4543                com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth);
4544        if (widthType == TypedValue.TYPE_FRACTION) {
4545            widthFraction = sw.getFraction(
4546                    com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth,
4547                    1, 1, -1);
4548        } else if (widthType == TypedValue.TYPE_DIMENSION) {
4549            width = sw.getDimensionPixelSize(
4550                    com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth,
4551                    -1);
4552        }
4553        final int heightType = sw.getType(
4554                com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight);
4555        if (heightType == TypedValue.TYPE_FRACTION) {
4556            heightFraction = sw.getFraction(
4557                    com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight,
4558                    1, 1, -1);
4559        } else if (heightType == TypedValue.TYPE_DIMENSION) {
4560            height = sw.getDimensionPixelSize(
4561                    com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight,
4562                    -1);
4563        }
4564        int gravity = sw.getInt(
4565                com.android.internal.R.styleable.AndroidManifestLayout_gravity,
4566                Gravity.CENTER);
4567        int minWidth = sw.getDimensionPixelSize(
4568                com.android.internal.R.styleable.AndroidManifestLayout_minWidth,
4569                -1);
4570        int minHeight = sw.getDimensionPixelSize(
4571                com.android.internal.R.styleable.AndroidManifestLayout_minHeight,
4572                -1);
4573        sw.recycle();
4574        a.info.windowLayout = new ActivityInfo.WindowLayout(width, widthFraction,
4575                height, heightFraction, gravity, minWidth, minHeight);
4576    }
4577
4578    private Activity parseActivityAlias(Package owner, Resources res,
4579            XmlResourceParser parser, int flags, String[] outError)
4580            throws XmlPullParserException, IOException {
4581        TypedArray sa = res.obtainAttributes(parser,
4582                com.android.internal.R.styleable.AndroidManifestActivityAlias);
4583
4584        String targetActivity = sa.getNonConfigurationString(
4585                com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity,
4586                Configuration.NATIVE_CONFIG_VERSION);
4587        if (targetActivity == null) {
4588            outError[0] = "<activity-alias> does not specify android:targetActivity";
4589            sa.recycle();
4590            return null;
4591        }
4592
4593        targetActivity = buildClassName(owner.applicationInfo.packageName,
4594                targetActivity, outError);
4595        if (targetActivity == null) {
4596            sa.recycle();
4597            return null;
4598        }
4599
4600        if (mParseActivityAliasArgs == null) {
4601            mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
4602                    com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
4603                    com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
4604                    com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
4605                    com.android.internal.R.styleable.AndroidManifestActivityAlias_roundIcon,
4606                    com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
4607                    com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
4608                    mSeparateProcesses,
4609                    0,
4610                    com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
4611                    com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
4612            mParseActivityAliasArgs.tag = "<activity-alias>";
4613        }
4614
4615        mParseActivityAliasArgs.sa = sa;
4616        mParseActivityAliasArgs.flags = flags;
4617
4618        Activity target = null;
4619
4620        final int NA = owner.activities.size();
4621        for (int i=0; i<NA; i++) {
4622            Activity t = owner.activities.get(i);
4623            if (targetActivity.equals(t.info.name)) {
4624                target = t;
4625                break;
4626            }
4627        }
4628
4629        if (target == null) {
4630            outError[0] = "<activity-alias> target activity " + targetActivity
4631                    + " not found in manifest";
4632            sa.recycle();
4633            return null;
4634        }
4635
4636        ActivityInfo info = new ActivityInfo();
4637        info.targetActivity = targetActivity;
4638        info.configChanges = target.info.configChanges;
4639        info.flags = target.info.flags;
4640        info.icon = target.info.icon;
4641        info.logo = target.info.logo;
4642        info.banner = target.info.banner;
4643        info.labelRes = target.info.labelRes;
4644        info.nonLocalizedLabel = target.info.nonLocalizedLabel;
4645        info.launchMode = target.info.launchMode;
4646        info.lockTaskLaunchMode = target.info.lockTaskLaunchMode;
4647        info.processName = target.info.processName;
4648        if (info.descriptionRes == 0) {
4649            info.descriptionRes = target.info.descriptionRes;
4650        }
4651        info.screenOrientation = target.info.screenOrientation;
4652        info.taskAffinity = target.info.taskAffinity;
4653        info.theme = target.info.theme;
4654        info.softInputMode = target.info.softInputMode;
4655        info.uiOptions = target.info.uiOptions;
4656        info.parentActivityName = target.info.parentActivityName;
4657        info.maxRecents = target.info.maxRecents;
4658        info.windowLayout = target.info.windowLayout;
4659        info.resizeMode = target.info.resizeMode;
4660        info.maxAspectRatio = target.info.maxAspectRatio;
4661        info.encryptionAware = info.directBootAware = target.info.directBootAware;
4662
4663        Activity a = new Activity(mParseActivityAliasArgs, info);
4664        if (outError[0] != null) {
4665            sa.recycle();
4666            return null;
4667        }
4668
4669        final boolean setExported = sa.hasValue(
4670                com.android.internal.R.styleable.AndroidManifestActivityAlias_exported);
4671        if (setExported) {
4672            a.info.exported = sa.getBoolean(
4673                    com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false);
4674        }
4675
4676        String str;
4677        str = sa.getNonConfigurationString(
4678                com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0);
4679        if (str != null) {
4680            a.info.permission = str.length() > 0 ? str.toString().intern() : null;
4681        }
4682
4683        String parentName = sa.getNonConfigurationString(
4684                com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName,
4685                Configuration.NATIVE_CONFIG_VERSION);
4686        if (parentName != null) {
4687            String parentClassName = buildClassName(a.info.packageName, parentName, outError);
4688            if (outError[0] == null) {
4689                a.info.parentActivityName = parentClassName;
4690            } else {
4691                Log.e(TAG, "Activity alias " + a.info.name +
4692                        " specified invalid parentActivityName " + parentName);
4693                outError[0] = null;
4694            }
4695        }
4696
4697        // TODO add visibleToInstantApps attribute to activity alias
4698        final boolean visibleToEphemeral =
4699                ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0);
4700
4701        sa.recycle();
4702
4703        if (outError[0] != null) {
4704            return null;
4705        }
4706
4707        int outerDepth = parser.getDepth();
4708        int type;
4709        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4710               && (type != XmlPullParser.END_TAG
4711                       || parser.getDepth() > outerDepth)) {
4712            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4713                continue;
4714            }
4715
4716            if (parser.getName().equals("intent-filter")) {
4717                ActivityIntentInfo intent = new ActivityIntentInfo(a);
4718                if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
4719                        intent, outError)) {
4720                    return null;
4721                }
4722                if (intent.countActions() == 0) {
4723                    Slog.w(TAG, "No actions in intent filter at "
4724                            + mArchiveSourcePath + " "
4725                            + parser.getPositionDescription());
4726                } else {
4727                    a.intents.add(intent);
4728                }
4729                // adjust activity flags when we implicitly expose it via a browsable filter
4730                final int visibility = visibleToEphemeral
4731                        ? IntentFilter.VISIBILITY_EXPLICIT
4732                        : isImplicitlyExposedIntent(intent)
4733                                ? IntentFilter.VISIBILITY_IMPLICIT
4734                                : IntentFilter.VISIBILITY_NONE;
4735                intent.setVisibilityToInstantApp(visibility);
4736                if (intent.isVisibleToInstantApp()) {
4737                    a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4738                }
4739                if (intent.isImplicitlyVisibleToInstantApp()) {
4740                    a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
4741                }
4742            } else if (parser.getName().equals("meta-data")) {
4743                if ((a.metaData=parseMetaData(res, parser, a.metaData,
4744                        outError)) == null) {
4745                    return null;
4746                }
4747            } else {
4748                if (!RIGID_PARSER) {
4749                    Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName()
4750                            + " at " + mArchiveSourcePath + " "
4751                            + parser.getPositionDescription());
4752                    XmlUtils.skipCurrentTag(parser);
4753                    continue;
4754                } else {
4755                    outError[0] = "Bad element under <activity-alias>: " + parser.getName();
4756                    return null;
4757                }
4758            }
4759        }
4760
4761        if (!setExported) {
4762            a.info.exported = a.intents.size() > 0;
4763        }
4764
4765        return a;
4766    }
4767
4768    private Provider parseProvider(Package owner, Resources res,
4769            XmlResourceParser parser, int flags, String[] outError)
4770            throws XmlPullParserException, IOException {
4771        TypedArray sa = res.obtainAttributes(parser,
4772                com.android.internal.R.styleable.AndroidManifestProvider);
4773
4774        if (mParseProviderArgs == null) {
4775            mParseProviderArgs = new ParseComponentArgs(owner, outError,
4776                    com.android.internal.R.styleable.AndroidManifestProvider_name,
4777                    com.android.internal.R.styleable.AndroidManifestProvider_label,
4778                    com.android.internal.R.styleable.AndroidManifestProvider_icon,
4779                    com.android.internal.R.styleable.AndroidManifestProvider_roundIcon,
4780                    com.android.internal.R.styleable.AndroidManifestProvider_logo,
4781                    com.android.internal.R.styleable.AndroidManifestProvider_banner,
4782                    mSeparateProcesses,
4783                    com.android.internal.R.styleable.AndroidManifestProvider_process,
4784                    com.android.internal.R.styleable.AndroidManifestProvider_description,
4785                    com.android.internal.R.styleable.AndroidManifestProvider_enabled);
4786            mParseProviderArgs.tag = "<provider>";
4787        }
4788
4789        mParseProviderArgs.sa = sa;
4790        mParseProviderArgs.flags = flags;
4791
4792        Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
4793        if (outError[0] != null) {
4794            sa.recycle();
4795            return null;
4796        }
4797
4798        boolean providerExportedDefault = false;
4799
4800        if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
4801            // For compatibility, applications targeting API level 16 or lower
4802            // should have their content providers exported by default, unless they
4803            // specify otherwise.
4804            providerExportedDefault = true;
4805        }
4806
4807        p.info.exported = sa.getBoolean(
4808                com.android.internal.R.styleable.AndroidManifestProvider_exported,
4809                providerExportedDefault);
4810
4811        String cpname = sa.getNonConfigurationString(
4812                com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0);
4813
4814        p.info.isSyncable = sa.getBoolean(
4815                com.android.internal.R.styleable.AndroidManifestProvider_syncable,
4816                false);
4817
4818        String permission = sa.getNonConfigurationString(
4819                com.android.internal.R.styleable.AndroidManifestProvider_permission, 0);
4820        String str = sa.getNonConfigurationString(
4821                com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0);
4822        if (str == null) {
4823            str = permission;
4824        }
4825        if (str == null) {
4826            p.info.readPermission = owner.applicationInfo.permission;
4827        } else {
4828            p.info.readPermission =
4829                str.length() > 0 ? str.toString().intern() : null;
4830        }
4831        str = sa.getNonConfigurationString(
4832                com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0);
4833        if (str == null) {
4834            str = permission;
4835        }
4836        if (str == null) {
4837            p.info.writePermission = owner.applicationInfo.permission;
4838        } else {
4839            p.info.writePermission =
4840                str.length() > 0 ? str.toString().intern() : null;
4841        }
4842
4843        p.info.grantUriPermissions = sa.getBoolean(
4844                com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
4845                false);
4846
4847        p.info.multiprocess = sa.getBoolean(
4848                com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
4849                false);
4850
4851        p.info.initOrder = sa.getInt(
4852                com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
4853                0);
4854
4855        p.info.splitName =
4856                sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0);
4857
4858        p.info.flags = 0;
4859
4860        if (sa.getBoolean(
4861                com.android.internal.R.styleable.AndroidManifestProvider_singleUser,
4862                false)) {
4863            p.info.flags |= ProviderInfo.FLAG_SINGLE_USER;
4864            if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
4865                Slog.w(TAG, "Provider exported request ignored due to singleUser: "
4866                        + p.className + " at " + mArchiveSourcePath + " "
4867                        + parser.getPositionDescription());
4868                p.info.exported = false;
4869            }
4870        }
4871
4872        p.info.encryptionAware = p.info.directBootAware = sa.getBoolean(
4873                R.styleable.AndroidManifestProvider_directBootAware,
4874                false);
4875        if (p.info.directBootAware) {
4876            owner.applicationInfo.privateFlags |=
4877                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
4878        }
4879
4880        final boolean visibleToEphemeral =
4881                sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
4882        if (visibleToEphemeral) {
4883            p.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4884            owner.visibleToInstantApps = true;
4885        }
4886
4887        sa.recycle();
4888
4889        if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
4890                != 0) {
4891            // A heavy-weight application can not have providers in its main process
4892            // We can do direct compare because we intern all strings.
4893            if (p.info.processName == owner.packageName) {
4894                outError[0] = "Heavy-weight applications can not have providers in main process";
4895                return null;
4896            }
4897        }
4898
4899        if (cpname == null) {
4900            outError[0] = "<provider> does not include authorities attribute";
4901            return null;
4902        }
4903        if (cpname.length() <= 0) {
4904            outError[0] = "<provider> has empty authorities attribute";
4905            return null;
4906        }
4907        p.info.authority = cpname.intern();
4908
4909        if (!parseProviderTags(
4910                res, parser, visibleToEphemeral, owner, p, outError)) {
4911            return null;
4912        }
4913
4914        return p;
4915    }
4916
4917    private boolean parseProviderTags(Resources res, XmlResourceParser parser,
4918            boolean visibleToEphemeral, Package owner, Provider outInfo, String[] outError)
4919                    throws XmlPullParserException, IOException {
4920        int outerDepth = parser.getDepth();
4921        int type;
4922        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4923               && (type != XmlPullParser.END_TAG
4924                       || parser.getDepth() > outerDepth)) {
4925            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4926                continue;
4927            }
4928
4929            if (parser.getName().equals("intent-filter")) {
4930                ProviderIntentInfo intent = new ProviderIntentInfo(outInfo);
4931                if (!parseIntent(res, parser, true /*allowGlobs*/, false /*allowAutoVerify*/,
4932                        intent, outError)) {
4933                    return false;
4934                }
4935                if (visibleToEphemeral) {
4936                    intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
4937                    outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4938                }
4939                outInfo.intents.add(intent);
4940
4941            } else if (parser.getName().equals("meta-data")) {
4942                if ((outInfo.metaData=parseMetaData(res, parser,
4943                        outInfo.metaData, outError)) == null) {
4944                    return false;
4945                }
4946                // we don't have an attribute [or it's false], but, we have meta-data
4947                if (!visibleToEphemeral && outInfo.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
4948                    visibleToEphemeral = true; // set in case there are more intent filters
4949                    outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
4950                    owner.visibleToInstantApps = true;
4951                    // cycle through any filters already seen
4952                    for (int i = outInfo.intents.size() - 1; i >= 0; --i) {
4953                        outInfo.intents.get(i)
4954                                .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
4955                    }
4956                }
4957
4958            } else if (parser.getName().equals("grant-uri-permission")) {
4959                TypedArray sa = res.obtainAttributes(parser,
4960                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
4961
4962                PatternMatcher pa = null;
4963
4964                String str = sa.getNonConfigurationString(
4965                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0);
4966                if (str != null) {
4967                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
4968                }
4969
4970                str = sa.getNonConfigurationString(
4971                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
4972                if (str != null) {
4973                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
4974                }
4975
4976                str = sa.getNonConfigurationString(
4977                        com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
4978                if (str != null) {
4979                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
4980                }
4981
4982                sa.recycle();
4983
4984                if (pa != null) {
4985                    if (outInfo.info.uriPermissionPatterns == null) {
4986                        outInfo.info.uriPermissionPatterns = new PatternMatcher[1];
4987                        outInfo.info.uriPermissionPatterns[0] = pa;
4988                    } else {
4989                        final int N = outInfo.info.uriPermissionPatterns.length;
4990                        PatternMatcher[] newp = new PatternMatcher[N+1];
4991                        System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N);
4992                        newp[N] = pa;
4993                        outInfo.info.uriPermissionPatterns = newp;
4994                    }
4995                    outInfo.info.grantUriPermissions = true;
4996                } else {
4997                    if (!RIGID_PARSER) {
4998                        Slog.w(TAG, "Unknown element under <path-permission>: "
4999                                + parser.getName() + " at " + mArchiveSourcePath + " "
5000                                + parser.getPositionDescription());
5001                        XmlUtils.skipCurrentTag(parser);
5002                        continue;
5003                    } else {
5004                        outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
5005                        return false;
5006                    }
5007                }
5008                XmlUtils.skipCurrentTag(parser);
5009
5010            } else if (parser.getName().equals("path-permission")) {
5011                TypedArray sa = res.obtainAttributes(parser,
5012                        com.android.internal.R.styleable.AndroidManifestPathPermission);
5013
5014                PathPermission pa = null;
5015
5016                String permission = sa.getNonConfigurationString(
5017                        com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0);
5018                String readPermission = sa.getNonConfigurationString(
5019                        com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0);
5020                if (readPermission == null) {
5021                    readPermission = permission;
5022                }
5023                String writePermission = sa.getNonConfigurationString(
5024                        com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0);
5025                if (writePermission == null) {
5026                    writePermission = permission;
5027                }
5028
5029                boolean havePerm = false;
5030                if (readPermission != null) {
5031                    readPermission = readPermission.intern();
5032                    havePerm = true;
5033                }
5034                if (writePermission != null) {
5035                    writePermission = writePermission.intern();
5036                    havePerm = true;
5037                }
5038
5039                if (!havePerm) {
5040                    if (!RIGID_PARSER) {
5041                        Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
5042                                + parser.getName() + " at " + mArchiveSourcePath + " "
5043                                + parser.getPositionDescription());
5044                        XmlUtils.skipCurrentTag(parser);
5045                        continue;
5046                    } else {
5047                        outError[0] = "No readPermission or writePermssion for <path-permission>";
5048                        return false;
5049                    }
5050                }
5051
5052                String path = sa.getNonConfigurationString(
5053                        com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0);
5054                if (path != null) {
5055                    pa = new PathPermission(path,
5056                            PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
5057                }
5058
5059                path = sa.getNonConfigurationString(
5060                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
5061                if (path != null) {
5062                    pa = new PathPermission(path,
5063                            PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
5064                }
5065
5066                path = sa.getNonConfigurationString(
5067                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0);
5068                if (path != null) {
5069                    pa = new PathPermission(path,
5070                            PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
5071                }
5072
5073                path = sa.getNonConfigurationString(
5074                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0);
5075                if (path != null) {
5076                    pa = new PathPermission(path,
5077                            PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission);
5078                }
5079
5080                sa.recycle();
5081
5082                if (pa != null) {
5083                    if (outInfo.info.pathPermissions == null) {
5084                        outInfo.info.pathPermissions = new PathPermission[1];
5085                        outInfo.info.pathPermissions[0] = pa;
5086                    } else {
5087                        final int N = outInfo.info.pathPermissions.length;
5088                        PathPermission[] newp = new PathPermission[N+1];
5089                        System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
5090                        newp[N] = pa;
5091                        outInfo.info.pathPermissions = newp;
5092                    }
5093                } else {
5094                    if (!RIGID_PARSER) {
5095                        Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
5096                                + parser.getName() + " at " + mArchiveSourcePath + " "
5097                                + parser.getPositionDescription());
5098                        XmlUtils.skipCurrentTag(parser);
5099                        continue;
5100                    }
5101                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
5102                    return false;
5103                }
5104                XmlUtils.skipCurrentTag(parser);
5105
5106            } else {
5107                if (!RIGID_PARSER) {
5108                    Slog.w(TAG, "Unknown element under <provider>: "
5109                            + parser.getName() + " at " + mArchiveSourcePath + " "
5110                            + parser.getPositionDescription());
5111                    XmlUtils.skipCurrentTag(parser);
5112                    continue;
5113                } else {
5114                    outError[0] = "Bad element under <provider>: " + parser.getName();
5115                    return false;
5116                }
5117            }
5118        }
5119        return true;
5120    }
5121
5122    private Service parseService(Package owner, Resources res,
5123            XmlResourceParser parser, int flags, String[] outError)
5124            throws XmlPullParserException, IOException {
5125        TypedArray sa = res.obtainAttributes(parser,
5126                com.android.internal.R.styleable.AndroidManifestService);
5127
5128        if (mParseServiceArgs == null) {
5129            mParseServiceArgs = new ParseComponentArgs(owner, outError,
5130                    com.android.internal.R.styleable.AndroidManifestService_name,
5131                    com.android.internal.R.styleable.AndroidManifestService_label,
5132                    com.android.internal.R.styleable.AndroidManifestService_icon,
5133                    com.android.internal.R.styleable.AndroidManifestService_roundIcon,
5134                    com.android.internal.R.styleable.AndroidManifestService_logo,
5135                    com.android.internal.R.styleable.AndroidManifestService_banner,
5136                    mSeparateProcesses,
5137                    com.android.internal.R.styleable.AndroidManifestService_process,
5138                    com.android.internal.R.styleable.AndroidManifestService_description,
5139                    com.android.internal.R.styleable.AndroidManifestService_enabled);
5140            mParseServiceArgs.tag = "<service>";
5141        }
5142
5143        mParseServiceArgs.sa = sa;
5144        mParseServiceArgs.flags = flags;
5145
5146        Service s = new Service(mParseServiceArgs, new ServiceInfo());
5147        if (outError[0] != null) {
5148            sa.recycle();
5149            return null;
5150        }
5151
5152        boolean setExported = sa.hasValue(
5153                com.android.internal.R.styleable.AndroidManifestService_exported);
5154        if (setExported) {
5155            s.info.exported = sa.getBoolean(
5156                    com.android.internal.R.styleable.AndroidManifestService_exported, false);
5157        }
5158
5159        String str = sa.getNonConfigurationString(
5160                com.android.internal.R.styleable.AndroidManifestService_permission, 0);
5161        if (str == null) {
5162            s.info.permission = owner.applicationInfo.permission;
5163        } else {
5164            s.info.permission = str.length() > 0 ? str.toString().intern() : null;
5165        }
5166
5167        s.info.splitName =
5168                sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0);
5169
5170        s.info.flags = 0;
5171        if (sa.getBoolean(
5172                com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
5173                false)) {
5174            s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
5175        }
5176        if (sa.getBoolean(
5177                com.android.internal.R.styleable.AndroidManifestService_isolatedProcess,
5178                false)) {
5179            s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
5180        }
5181        if (sa.getBoolean(
5182                com.android.internal.R.styleable.AndroidManifestService_externalService,
5183                false)) {
5184            s.info.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
5185        }
5186        if (sa.getBoolean(
5187                com.android.internal.R.styleable.AndroidManifestService_singleUser,
5188                false)) {
5189            s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
5190            if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
5191                Slog.w(TAG, "Service exported request ignored due to singleUser: "
5192                        + s.className + " at " + mArchiveSourcePath + " "
5193                        + parser.getPositionDescription());
5194                s.info.exported = false;
5195                setExported = true;
5196            }
5197        }
5198
5199        s.info.encryptionAware = s.info.directBootAware = sa.getBoolean(
5200                R.styleable.AndroidManifestService_directBootAware,
5201                false);
5202        if (s.info.directBootAware) {
5203            owner.applicationInfo.privateFlags |=
5204                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
5205        }
5206
5207        boolean visibleToEphemeral =
5208                sa.getBoolean(R.styleable.AndroidManifestService_visibleToInstantApps, false);
5209        if (visibleToEphemeral) {
5210            s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
5211            owner.visibleToInstantApps = true;
5212        }
5213
5214        sa.recycle();
5215
5216        if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
5217                != 0) {
5218            // A heavy-weight application can not have services in its main process
5219            // We can do direct compare because we intern all strings.
5220            if (s.info.processName == owner.packageName) {
5221                outError[0] = "Heavy-weight applications can not have services in main process";
5222                return null;
5223            }
5224        }
5225
5226        int outerDepth = parser.getDepth();
5227        int type;
5228        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
5229               && (type != XmlPullParser.END_TAG
5230                       || parser.getDepth() > outerDepth)) {
5231            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
5232                continue;
5233            }
5234
5235            if (parser.getName().equals("intent-filter")) {
5236                ServiceIntentInfo intent = new ServiceIntentInfo(s);
5237                if (!parseIntent(res, parser, true /*allowGlobs*/, false /*allowAutoVerify*/,
5238                        intent, outError)) {
5239                    return null;
5240                }
5241                if (visibleToEphemeral) {
5242                    intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
5243                    s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
5244                }
5245                s.intents.add(intent);
5246            } else if (parser.getName().equals("meta-data")) {
5247                if ((s.metaData=parseMetaData(res, parser, s.metaData,
5248                        outError)) == null) {
5249                    return null;
5250                }
5251                // we don't have an attribute [or it's false], but, we have meta-data
5252                if (!visibleToEphemeral && s.metaData.getBoolean(META_DATA_INSTANT_APPS)) {
5253                    visibleToEphemeral = true; // set in case there are more intent filters
5254                    s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
5255                    owner.visibleToInstantApps = true;
5256                    // cycle through any filters already seen
5257                    for (int i = s.intents.size() - 1; i >= 0; --i) {
5258                        s.intents.get(i)
5259                                .setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
5260                    }
5261                }
5262            } else {
5263                if (!RIGID_PARSER) {
5264                    Slog.w(TAG, "Unknown element under <service>: "
5265                            + parser.getName() + " at " + mArchiveSourcePath + " "
5266                            + parser.getPositionDescription());
5267                    XmlUtils.skipCurrentTag(parser);
5268                    continue;
5269                } else {
5270                    outError[0] = "Bad element under <service>: " + parser.getName();
5271                    return null;
5272                }
5273            }
5274        }
5275
5276        if (!setExported) {
5277            s.info.exported = s.intents.size() > 0;
5278        }
5279
5280        return s;
5281    }
5282
5283    private boolean isImplicitlyExposedIntent(IntentInfo intent) {
5284        return intent.hasCategory(Intent.CATEGORY_BROWSABLE)
5285                || intent.hasAction(Intent.ACTION_SEND)
5286                || intent.hasAction(Intent.ACTION_SENDTO)
5287                || intent.hasAction(Intent.ACTION_SEND_MULTIPLE);
5288    }
5289
5290    private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag,
5291            Component<?> outInfo, String[] outError) throws XmlPullParserException, IOException {
5292        int outerDepth = parser.getDepth();
5293        int type;
5294        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
5295               && (type != XmlPullParser.END_TAG
5296                       || parser.getDepth() > outerDepth)) {
5297            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
5298                continue;
5299            }
5300
5301            if (parser.getName().equals("meta-data")) {
5302                if ((outInfo.metaData=parseMetaData(res, parser,
5303                        outInfo.metaData, outError)) == null) {
5304                    return false;
5305                }
5306            } else {
5307                if (!RIGID_PARSER) {
5308                    Slog.w(TAG, "Unknown element under " + tag + ": "
5309                            + parser.getName() + " at " + mArchiveSourcePath + " "
5310                            + parser.getPositionDescription());
5311                    XmlUtils.skipCurrentTag(parser);
5312                    continue;
5313                } else {
5314                    outError[0] = "Bad element under " + tag + ": " + parser.getName();
5315                    return false;
5316                }
5317            }
5318        }
5319        return true;
5320    }
5321
5322    private Bundle parseMetaData(Resources res,
5323            XmlResourceParser parser, Bundle data, String[] outError)
5324            throws XmlPullParserException, IOException {
5325
5326        TypedArray sa = res.obtainAttributes(parser,
5327                com.android.internal.R.styleable.AndroidManifestMetaData);
5328
5329        if (data == null) {
5330            data = new Bundle();
5331        }
5332
5333        String name = sa.getNonConfigurationString(
5334                com.android.internal.R.styleable.AndroidManifestMetaData_name, 0);
5335        if (name == null) {
5336            outError[0] = "<meta-data> requires an android:name attribute";
5337            sa.recycle();
5338            return null;
5339        }
5340
5341        name = name.intern();
5342
5343        TypedValue v = sa.peekValue(
5344                com.android.internal.R.styleable.AndroidManifestMetaData_resource);
5345        if (v != null && v.resourceId != 0) {
5346            //Slog.i(TAG, "Meta data ref " + name + ": " + v);
5347            data.putInt(name, v.resourceId);
5348        } else {
5349            v = sa.peekValue(
5350                    com.android.internal.R.styleable.AndroidManifestMetaData_value);
5351            //Slog.i(TAG, "Meta data " + name + ": " + v);
5352            if (v != null) {
5353                if (v.type == TypedValue.TYPE_STRING) {
5354                    CharSequence cs = v.coerceToString();
5355                    data.putString(name, cs != null ? cs.toString() : null);
5356                } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
5357                    data.putBoolean(name, v.data != 0);
5358                } else if (v.type >= TypedValue.TYPE_FIRST_INT
5359                        && v.type <= TypedValue.TYPE_LAST_INT) {
5360                    data.putInt(name, v.data);
5361                } else if (v.type == TypedValue.TYPE_FLOAT) {
5362                    data.putFloat(name, v.getFloat());
5363                } else {
5364                    if (!RIGID_PARSER) {
5365                        Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: "
5366                                + parser.getName() + " at " + mArchiveSourcePath + " "
5367                                + parser.getPositionDescription());
5368                    } else {
5369                        outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types";
5370                        data = null;
5371                    }
5372                }
5373            } else {
5374                outError[0] = "<meta-data> requires an android:value or android:resource attribute";
5375                data = null;
5376            }
5377        }
5378
5379        sa.recycle();
5380
5381        XmlUtils.skipCurrentTag(parser);
5382
5383        return data;
5384    }
5385
5386    private static VerifierInfo parseVerifier(AttributeSet attrs) {
5387        String packageName = null;
5388        String encodedPublicKey = null;
5389
5390        final int attrCount = attrs.getAttributeCount();
5391        for (int i = 0; i < attrCount; i++) {
5392            final int attrResId = attrs.getAttributeNameResource(i);
5393            switch (attrResId) {
5394                case com.android.internal.R.attr.name:
5395                    packageName = attrs.getAttributeValue(i);
5396                    break;
5397
5398                case com.android.internal.R.attr.publicKey:
5399                    encodedPublicKey = attrs.getAttributeValue(i);
5400                    break;
5401            }
5402        }
5403
5404        if (packageName == null || packageName.length() == 0) {
5405            Slog.i(TAG, "verifier package name was null; skipping");
5406            return null;
5407        }
5408
5409        final PublicKey publicKey = parsePublicKey(encodedPublicKey);
5410        if (publicKey == null) {
5411            Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
5412            return null;
5413        }
5414
5415        return new VerifierInfo(packageName, publicKey);
5416    }
5417
5418    public static final PublicKey parsePublicKey(final String encodedPublicKey) {
5419        if (encodedPublicKey == null) {
5420            Slog.w(TAG, "Could not parse null public key");
5421            return null;
5422        }
5423
5424        EncodedKeySpec keySpec;
5425        try {
5426            final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT);
5427            keySpec = new X509EncodedKeySpec(encoded);
5428        } catch (IllegalArgumentException e) {
5429            Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
5430            return null;
5431        }
5432
5433        /* First try the key as an RSA key. */
5434        try {
5435            final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
5436            return keyFactory.generatePublic(keySpec);
5437        } catch (NoSuchAlgorithmException e) {
5438            Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build");
5439        } catch (InvalidKeySpecException e) {
5440            // Not a RSA public key.
5441        }
5442
5443        /* Now try it as a ECDSA key. */
5444        try {
5445            final KeyFactory keyFactory = KeyFactory.getInstance("EC");
5446            return keyFactory.generatePublic(keySpec);
5447        } catch (NoSuchAlgorithmException e) {
5448            Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build");
5449        } catch (InvalidKeySpecException e) {
5450            // Not a ECDSA public key.
5451        }
5452
5453        /* Now try it as a DSA key. */
5454        try {
5455            final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
5456            return keyFactory.generatePublic(keySpec);
5457        } catch (NoSuchAlgorithmException e) {
5458            Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build");
5459        } catch (InvalidKeySpecException e) {
5460            // Not a DSA public key.
5461        }
5462
5463        /* Not a supported key type */
5464        return null;
5465    }
5466
5467    private static final String ANDROID_RESOURCES
5468            = "http://schemas.android.com/apk/res/android";
5469
5470    private boolean parseIntent(Resources res, XmlResourceParser parser, boolean allowGlobs,
5471            boolean allowAutoVerify, IntentInfo outInfo, String[] outError)
5472                    throws XmlPullParserException, IOException {
5473
5474        TypedArray sa = res.obtainAttributes(parser,
5475                com.android.internal.R.styleable.AndroidManifestIntentFilter);
5476
5477        int priority = sa.getInt(
5478                com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
5479        outInfo.setPriority(priority);
5480
5481        TypedValue v = sa.peekValue(
5482                com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
5483        if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
5484            outInfo.nonLocalizedLabel = v.coerceToString();
5485        }
5486
5487        final boolean useRoundIcon =
5488                Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
5489        int roundIconVal = useRoundIcon ? sa.getResourceId(
5490                com.android.internal.R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0;
5491        if (roundIconVal != 0) {
5492            outInfo.icon = roundIconVal;
5493        } else {
5494            outInfo.icon = sa.getResourceId(
5495                    com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
5496        }
5497
5498        outInfo.logo = sa.getResourceId(
5499                com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
5500
5501        outInfo.banner = sa.getResourceId(
5502                com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0);
5503
5504        if (allowAutoVerify) {
5505            outInfo.setAutoVerify(sa.getBoolean(
5506                    com.android.internal.R.styleable.AndroidManifestIntentFilter_autoVerify,
5507                    false));
5508        }
5509
5510        sa.recycle();
5511
5512        int outerDepth = parser.getDepth();
5513        int type;
5514        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
5515                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
5516            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
5517                continue;
5518            }
5519
5520            String nodeName = parser.getName();
5521            if (nodeName.equals("action")) {
5522                String value = parser.getAttributeValue(
5523                        ANDROID_RESOURCES, "name");
5524                if (value == null || value == "") {
5525                    outError[0] = "No value supplied for <android:name>";
5526                    return false;
5527                }
5528                XmlUtils.skipCurrentTag(parser);
5529
5530                outInfo.addAction(value);
5531            } else if (nodeName.equals("category")) {
5532                String value = parser.getAttributeValue(
5533                        ANDROID_RESOURCES, "name");
5534                if (value == null || value == "") {
5535                    outError[0] = "No value supplied for <android:name>";
5536                    return false;
5537                }
5538                XmlUtils.skipCurrentTag(parser);
5539
5540                outInfo.addCategory(value);
5541
5542            } else if (nodeName.equals("data")) {
5543                sa = res.obtainAttributes(parser,
5544                        com.android.internal.R.styleable.AndroidManifestData);
5545
5546                String str = sa.getNonConfigurationString(
5547                        com.android.internal.R.styleable.AndroidManifestData_mimeType, 0);
5548                if (str != null) {
5549                    try {
5550                        outInfo.addDataType(str);
5551                    } catch (IntentFilter.MalformedMimeTypeException e) {
5552                        outError[0] = e.toString();
5553                        sa.recycle();
5554                        return false;
5555                    }
5556                }
5557
5558                str = sa.getNonConfigurationString(
5559                        com.android.internal.R.styleable.AndroidManifestData_scheme, 0);
5560                if (str != null) {
5561                    outInfo.addDataScheme(str);
5562                }
5563
5564                str = sa.getNonConfigurationString(
5565                        com.android.internal.R.styleable.AndroidManifestData_ssp, 0);
5566                if (str != null) {
5567                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
5568                }
5569
5570                str = sa.getNonConfigurationString(
5571                        com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0);
5572                if (str != null) {
5573                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
5574                }
5575
5576                str = sa.getNonConfigurationString(
5577                        com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0);
5578                if (str != null) {
5579                    if (!allowGlobs) {
5580                        outError[0] = "sspPattern not allowed here; ssp must be literal";
5581                        return false;
5582                    }
5583                    outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
5584                }
5585
5586                String host = sa.getNonConfigurationString(
5587                        com.android.internal.R.styleable.AndroidManifestData_host, 0);
5588                String port = sa.getNonConfigurationString(
5589                        com.android.internal.R.styleable.AndroidManifestData_port, 0);
5590                if (host != null) {
5591                    outInfo.addDataAuthority(host, port);
5592                }
5593
5594                str = sa.getNonConfigurationString(
5595                        com.android.internal.R.styleable.AndroidManifestData_path, 0);
5596                if (str != null) {
5597                    outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
5598                }
5599
5600                str = sa.getNonConfigurationString(
5601                        com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0);
5602                if (str != null) {
5603                    outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
5604                }
5605
5606                str = sa.getNonConfigurationString(
5607                        com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
5608                if (str != null) {
5609                    if (!allowGlobs) {
5610                        outError[0] = "pathPattern not allowed here; path must be literal";
5611                        return false;
5612                    }
5613                    outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
5614                }
5615
5616                str = sa.getNonConfigurationString(
5617                        com.android.internal.R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
5618                if (str != null) {
5619                    if (!allowGlobs) {
5620                        outError[0] = "pathAdvancedPattern not allowed here; path must be literal";
5621                        return false;
5622                    }
5623                    outInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB);
5624                }
5625
5626                sa.recycle();
5627                XmlUtils.skipCurrentTag(parser);
5628            } else if (!RIGID_PARSER) {
5629                Slog.w(TAG, "Unknown element under <intent-filter>: "
5630                        + parser.getName() + " at " + mArchiveSourcePath + " "
5631                        + parser.getPositionDescription());
5632                XmlUtils.skipCurrentTag(parser);
5633            } else {
5634                outError[0] = "Bad element under <intent-filter>: " + parser.getName();
5635                return false;
5636            }
5637        }
5638
5639        outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
5640
5641        if (DEBUG_PARSER) {
5642            final StringBuilder cats = new StringBuilder("Intent d=");
5643            cats.append(outInfo.hasDefault);
5644            cats.append(", cat=");
5645
5646            final Iterator<String> it = outInfo.categoriesIterator();
5647            if (it != null) {
5648                while (it.hasNext()) {
5649                    cats.append(' ');
5650                    cats.append(it.next());
5651                }
5652            }
5653            Slog.d(TAG, cats.toString());
5654        }
5655
5656        return true;
5657    }
5658
5659    /**
5660     * Representation of a full package parsed from APK files on disk. A package
5661     * consists of a single base APK, and zero or more split APKs.
5662     */
5663    public final static class Package implements Parcelable {
5664
5665        public String packageName;
5666
5667        // The package name declared in the manifest as the package can be
5668        // renamed, for example static shared libs use synthetic package names.
5669        public String manifestPackageName;
5670
5671        /** Names of any split APKs, ordered by parsed splitName */
5672        public String[] splitNames;
5673
5674        // TODO: work towards making these paths invariant
5675
5676        public String volumeUuid;
5677
5678        /**
5679         * Path where this package was found on disk. For monolithic packages
5680         * this is path to single base APK file; for cluster packages this is
5681         * path to the cluster directory.
5682         */
5683        public String codePath;
5684
5685        /** Path of base APK */
5686        public String baseCodePath;
5687        /** Paths of any split APKs, ordered by parsed splitName */
5688        public String[] splitCodePaths;
5689
5690        /** Revision code of base APK */
5691        public int baseRevisionCode;
5692        /** Revision codes of any split APKs, ordered by parsed splitName */
5693        public int[] splitRevisionCodes;
5694
5695        /** Flags of any split APKs; ordered by parsed splitName */
5696        public int[] splitFlags;
5697
5698        /**
5699         * Private flags of any split APKs; ordered by parsed splitName.
5700         *
5701         * {@hide}
5702         */
5703        public int[] splitPrivateFlags;
5704
5705        public boolean baseHardwareAccelerated;
5706
5707        // For now we only support one application per package.
5708        public ApplicationInfo applicationInfo = new ApplicationInfo();
5709
5710        public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
5711        public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
5712        public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
5713        public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
5714        public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
5715        public final ArrayList<Service> services = new ArrayList<Service>(0);
5716        public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
5717
5718        public final ArrayList<String> requestedPermissions = new ArrayList<String>();
5719
5720        public ArrayList<String> protectedBroadcasts;
5721
5722        public Package parentPackage;
5723        public ArrayList<Package> childPackages;
5724
5725        public String staticSharedLibName = null;
5726        public int staticSharedLibVersion = 0;
5727        public ArrayList<String> libraryNames = null;
5728        public ArrayList<String> usesLibraries = null;
5729        public ArrayList<String> usesStaticLibraries = null;
5730        public int[] usesStaticLibrariesVersions = null;
5731        public String[] usesStaticLibrariesCertDigests = null;
5732        public ArrayList<String> usesOptionalLibraries = null;
5733        public String[] usesLibraryFiles = null;
5734
5735        public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
5736
5737        public ArrayList<String> mOriginalPackages = null;
5738        public String mRealPackage = null;
5739        public ArrayList<String> mAdoptPermissions = null;
5740
5741        // We store the application meta-data independently to avoid multiple unwanted references
5742        public Bundle mAppMetaData = null;
5743
5744        // The version code declared for this package.
5745        public int mVersionCode;
5746
5747        // The version name declared for this package.
5748        public String mVersionName;
5749
5750        // The shared user id that this package wants to use.
5751        public String mSharedUserId;
5752
5753        // The shared user label that this package wants to use.
5754        public int mSharedUserLabel;
5755
5756        // Signatures that were read from the package.
5757        public Signature[] mSignatures;
5758        public Certificate[][] mCertificates;
5759
5760        // For use by package manager service for quick lookup of
5761        // preferred up order.
5762        public int mPreferredOrder = 0;
5763
5764        // For use by package manager to keep track of when a package was last used.
5765        public long[] mLastPackageUsageTimeInMills =
5766                new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];
5767
5768        // // User set enabled state.
5769        // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
5770        //
5771        // // Whether the package has been stopped.
5772        // public boolean mSetStopped = false;
5773
5774        // Additional data supplied by callers.
5775        public Object mExtras;
5776
5777        // Applications hardware preferences
5778        public ArrayList<ConfigurationInfo> configPreferences = null;
5779
5780        // Applications requested features
5781        public ArrayList<FeatureInfo> reqFeatures = null;
5782
5783        // Applications requested feature groups
5784        public ArrayList<FeatureGroupInfo> featureGroups = null;
5785
5786        public int installLocation;
5787
5788        public boolean coreApp;
5789
5790        /* An app that's required for all users and cannot be uninstalled for a user */
5791        public boolean mRequiredForAllUsers;
5792
5793        /* The restricted account authenticator type that is used by this application */
5794        public String mRestrictedAccountType;
5795
5796        /* The required account type without which this application will not function */
5797        public String mRequiredAccountType;
5798
5799        public String mOverlayTarget;
5800        public int mOverlayPriority;
5801        public boolean mIsStaticOverlay;
5802        public boolean mTrustedOverlay;
5803
5804        /**
5805         * Data used to feed the KeySetManagerService
5806         */
5807        public ArraySet<PublicKey> mSigningKeys;
5808        public ArraySet<String> mUpgradeKeySets;
5809        public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
5810
5811        /**
5812         * The install time abi override for this package, if any.
5813         *
5814         * TODO: This seems like a horrible place to put the abiOverride because
5815         * this isn't something the packageParser parsers. However, this fits in with
5816         * the rest of the PackageManager where package scanning randomly pushes
5817         * and prods fields out of {@code this.applicationInfo}.
5818         */
5819        public String cpuAbiOverride;
5820        /**
5821         * The install time abi override to choose 32bit abi's when multiple abi's
5822         * are present. This is only meaningfull for multiarch applications.
5823         * The use32bitAbi attribute is ignored if cpuAbiOverride is also set.
5824         */
5825        public boolean use32bitAbi;
5826
5827        public byte[] restrictUpdateHash;
5828
5829        /**
5830         * Set if the app or any of its components are visible to Instant Apps.
5831         */
5832        public boolean visibleToInstantApps;
5833
5834        public Package(String packageName) {
5835            this.packageName = packageName;
5836            this.manifestPackageName = packageName;
5837            applicationInfo.packageName = packageName;
5838            applicationInfo.uid = -1;
5839        }
5840
5841        public void setApplicationVolumeUuid(String volumeUuid) {
5842            final UUID storageUuid = StorageManager.convert(volumeUuid);
5843            this.applicationInfo.volumeUuid = volumeUuid;
5844            this.applicationInfo.storageUuid = storageUuid;
5845            if (childPackages != null) {
5846                final int packageCount = childPackages.size();
5847                for (int i = 0; i < packageCount; i++) {
5848                    childPackages.get(i).applicationInfo.volumeUuid = volumeUuid;
5849                    childPackages.get(i).applicationInfo.storageUuid = storageUuid;
5850                }
5851            }
5852        }
5853
5854        public void setApplicationInfoCodePath(String codePath) {
5855            this.applicationInfo.setCodePath(codePath);
5856            if (childPackages != null) {
5857                final int packageCount = childPackages.size();
5858                for (int i = 0; i < packageCount; i++) {
5859                    childPackages.get(i).applicationInfo.setCodePath(codePath);
5860                }
5861            }
5862        }
5863
5864        public void setApplicationInfoResourcePath(String resourcePath) {
5865            this.applicationInfo.setResourcePath(resourcePath);
5866            if (childPackages != null) {
5867                final int packageCount = childPackages.size();
5868                for (int i = 0; i < packageCount; i++) {
5869                    childPackages.get(i).applicationInfo.setResourcePath(resourcePath);
5870                }
5871            }
5872        }
5873
5874        public void setApplicationInfoBaseResourcePath(String resourcePath) {
5875            this.applicationInfo.setBaseResourcePath(resourcePath);
5876            if (childPackages != null) {
5877                final int packageCount = childPackages.size();
5878                for (int i = 0; i < packageCount; i++) {
5879                    childPackages.get(i).applicationInfo.setBaseResourcePath(resourcePath);
5880                }
5881            }
5882        }
5883
5884        public void setApplicationInfoBaseCodePath(String baseCodePath) {
5885            this.applicationInfo.setBaseCodePath(baseCodePath);
5886            if (childPackages != null) {
5887                final int packageCount = childPackages.size();
5888                for (int i = 0; i < packageCount; i++) {
5889                    childPackages.get(i).applicationInfo.setBaseCodePath(baseCodePath);
5890                }
5891            }
5892        }
5893
5894        public List<String> getChildPackageNames() {
5895            if (childPackages == null) {
5896                return null;
5897            }
5898            final int childCount = childPackages.size();
5899            final List<String> childPackageNames = new ArrayList<>(childCount);
5900            for (int i = 0; i < childCount; i++) {
5901                String childPackageName = childPackages.get(i).packageName;
5902                childPackageNames.add(childPackageName);
5903            }
5904            return childPackageNames;
5905        }
5906
5907        public boolean hasChildPackage(String packageName) {
5908            final int childCount = (childPackages != null) ? childPackages.size() : 0;
5909            for (int i = 0; i < childCount; i++) {
5910                if (childPackages.get(i).packageName.equals(packageName)) {
5911                    return true;
5912                }
5913            }
5914            return false;
5915        }
5916
5917        public void setApplicationInfoSplitCodePaths(String[] splitCodePaths) {
5918            this.applicationInfo.setSplitCodePaths(splitCodePaths);
5919            // Children have no splits
5920        }
5921
5922        public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) {
5923            this.applicationInfo.setSplitResourcePaths(resroucePaths);
5924            // Children have no splits
5925        }
5926
5927        public void setSplitCodePaths(String[] codePaths) {
5928            this.splitCodePaths = codePaths;
5929        }
5930
5931        public void setCodePath(String codePath) {
5932            this.codePath = codePath;
5933            if (childPackages != null) {
5934                final int packageCount = childPackages.size();
5935                for (int i = 0; i < packageCount; i++) {
5936                    childPackages.get(i).codePath = codePath;
5937                }
5938            }
5939        }
5940
5941        public void setBaseCodePath(String baseCodePath) {
5942            this.baseCodePath = baseCodePath;
5943            if (childPackages != null) {
5944                final int packageCount = childPackages.size();
5945                for (int i = 0; i < packageCount; i++) {
5946                    childPackages.get(i).baseCodePath = baseCodePath;
5947                }
5948            }
5949        }
5950
5951        public void setSignatures(Signature[] signatures) {
5952            this.mSignatures = signatures;
5953            if (childPackages != null) {
5954                final int packageCount = childPackages.size();
5955                for (int i = 0; i < packageCount; i++) {
5956                    childPackages.get(i).mSignatures = signatures;
5957                }
5958            }
5959        }
5960
5961        public void setVolumeUuid(String volumeUuid) {
5962            this.volumeUuid = volumeUuid;
5963            if (childPackages != null) {
5964                final int packageCount = childPackages.size();
5965                for (int i = 0; i < packageCount; i++) {
5966                    childPackages.get(i).volumeUuid = volumeUuid;
5967                }
5968            }
5969        }
5970
5971        public void setApplicationInfoFlags(int mask, int flags) {
5972            applicationInfo.flags = (applicationInfo.flags & ~mask) | (mask & flags);
5973            if (childPackages != null) {
5974                final int packageCount = childPackages.size();
5975                for (int i = 0; i < packageCount; i++) {
5976                    childPackages.get(i).applicationInfo.flags =
5977                            (applicationInfo.flags & ~mask) | (mask & flags);
5978                }
5979            }
5980        }
5981
5982        public void setUse32bitAbi(boolean use32bitAbi) {
5983            this.use32bitAbi = use32bitAbi;
5984            if (childPackages != null) {
5985                final int packageCount = childPackages.size();
5986                for (int i = 0; i < packageCount; i++) {
5987                    childPackages.get(i).use32bitAbi = use32bitAbi;
5988                }
5989            }
5990        }
5991
5992        public boolean isLibrary() {
5993            return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames);
5994        }
5995
5996        public List<String> getAllCodePaths() {
5997            ArrayList<String> paths = new ArrayList<>();
5998            paths.add(baseCodePath);
5999            if (!ArrayUtils.isEmpty(splitCodePaths)) {
6000                Collections.addAll(paths, splitCodePaths);
6001            }
6002            return paths;
6003        }
6004
6005        /**
6006         * Filtered set of {@link #getAllCodePaths()} that excludes
6007         * resource-only APKs.
6008         */
6009        public List<String> getAllCodePathsExcludingResourceOnly() {
6010            ArrayList<String> paths = new ArrayList<>();
6011            if ((applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
6012                paths.add(baseCodePath);
6013            }
6014            if (!ArrayUtils.isEmpty(splitCodePaths)) {
6015                for (int i = 0; i < splitCodePaths.length; i++) {
6016                    if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
6017                        paths.add(splitCodePaths[i]);
6018                    }
6019                }
6020            }
6021            return paths;
6022        }
6023
6024        public void setPackageName(String newName) {
6025            packageName = newName;
6026            applicationInfo.packageName = newName;
6027            for (int i=permissions.size()-1; i>=0; i--) {
6028                permissions.get(i).setPackageName(newName);
6029            }
6030            for (int i=permissionGroups.size()-1; i>=0; i--) {
6031                permissionGroups.get(i).setPackageName(newName);
6032            }
6033            for (int i=activities.size()-1; i>=0; i--) {
6034                activities.get(i).setPackageName(newName);
6035            }
6036            for (int i=receivers.size()-1; i>=0; i--) {
6037                receivers.get(i).setPackageName(newName);
6038            }
6039            for (int i=providers.size()-1; i>=0; i--) {
6040                providers.get(i).setPackageName(newName);
6041            }
6042            for (int i=services.size()-1; i>=0; i--) {
6043                services.get(i).setPackageName(newName);
6044            }
6045            for (int i=instrumentation.size()-1; i>=0; i--) {
6046                instrumentation.get(i).setPackageName(newName);
6047            }
6048        }
6049
6050        public boolean hasComponentClassName(String name) {
6051            for (int i=activities.size()-1; i>=0; i--) {
6052                if (name.equals(activities.get(i).className)) {
6053                    return true;
6054                }
6055            }
6056            for (int i=receivers.size()-1; i>=0; i--) {
6057                if (name.equals(receivers.get(i).className)) {
6058                    return true;
6059                }
6060            }
6061            for (int i=providers.size()-1; i>=0; i--) {
6062                if (name.equals(providers.get(i).className)) {
6063                    return true;
6064                }
6065            }
6066            for (int i=services.size()-1; i>=0; i--) {
6067                if (name.equals(services.get(i).className)) {
6068                    return true;
6069                }
6070            }
6071            for (int i=instrumentation.size()-1; i>=0; i--) {
6072                if (name.equals(instrumentation.get(i).className)) {
6073                    return true;
6074                }
6075            }
6076            return false;
6077        }
6078
6079        /**
6080         * @hide
6081         */
6082        public boolean isForwardLocked() {
6083            return applicationInfo.isForwardLocked();
6084        }
6085
6086        /**
6087         * @hide
6088         */
6089        public boolean isSystemApp() {
6090            return applicationInfo.isSystemApp();
6091        }
6092
6093        /**
6094         * @hide
6095         */
6096        public boolean isPrivilegedApp() {
6097            return applicationInfo.isPrivilegedApp();
6098        }
6099
6100        /**
6101         * @hide
6102         */
6103        public boolean isUpdatedSystemApp() {
6104            return applicationInfo.isUpdatedSystemApp();
6105        }
6106
6107        /**
6108         * @hide
6109         */
6110        public boolean canHaveOatDir() {
6111            // The following app types CANNOT have oat directory
6112            // - non-updated system apps
6113            // - forward-locked apps or apps installed in ASEC containers
6114            return (!isSystemApp() || isUpdatedSystemApp())
6115                    && !isForwardLocked() && !applicationInfo.isExternalAsec();
6116        }
6117
6118        public boolean isMatch(int flags) {
6119            if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
6120                return isSystemApp();
6121            }
6122            return true;
6123        }
6124
6125        public long getLatestPackageUseTimeInMills() {
6126            long latestUse = 0L;
6127            for (long use : mLastPackageUsageTimeInMills) {
6128                latestUse = Math.max(latestUse, use);
6129            }
6130            return latestUse;
6131        }
6132
6133        public long getLatestForegroundPackageUseTimeInMills() {
6134            int[] foregroundReasons = {
6135                PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY,
6136                PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE
6137            };
6138
6139            long latestUse = 0L;
6140            for (int reason : foregroundReasons) {
6141                latestUse = Math.max(latestUse, mLastPackageUsageTimeInMills[reason]);
6142            }
6143            return latestUse;
6144        }
6145
6146        public String toString() {
6147            return "Package{"
6148                + Integer.toHexString(System.identityHashCode(this))
6149                + " " + packageName + "}";
6150        }
6151
6152        @Override
6153        public int describeContents() {
6154            return 0;
6155        }
6156
6157        public Package(Parcel dest) {
6158            // We use the boot classloader for all classes that we load.
6159            final ClassLoader boot = Object.class.getClassLoader();
6160
6161            packageName = dest.readString().intern();
6162            manifestPackageName = dest.readString();
6163            splitNames = dest.readStringArray();
6164            volumeUuid = dest.readString();
6165            codePath = dest.readString();
6166            baseCodePath = dest.readString();
6167            splitCodePaths = dest.readStringArray();
6168            baseRevisionCode = dest.readInt();
6169            splitRevisionCodes = dest.createIntArray();
6170            splitFlags = dest.createIntArray();
6171            splitPrivateFlags = dest.createIntArray();
6172            baseHardwareAccelerated = (dest.readInt() == 1);
6173            applicationInfo = dest.readParcelable(boot);
6174            if (applicationInfo.permission != null) {
6175                applicationInfo.permission = applicationInfo.permission.intern();
6176            }
6177
6178            // We don't serialize the "owner" package and the application info object for each of
6179            // these components, in order to save space and to avoid circular dependencies while
6180            // serialization. We need to fix them all up here.
6181            dest.readParcelableList(permissions, boot);
6182            fixupOwner(permissions);
6183            dest.readParcelableList(permissionGroups, boot);
6184            fixupOwner(permissionGroups);
6185            dest.readParcelableList(activities, boot);
6186            fixupOwner(activities);
6187            dest.readParcelableList(receivers, boot);
6188            fixupOwner(receivers);
6189            dest.readParcelableList(providers, boot);
6190            fixupOwner(providers);
6191            dest.readParcelableList(services, boot);
6192            fixupOwner(services);
6193            dest.readParcelableList(instrumentation, boot);
6194            fixupOwner(instrumentation);
6195
6196            dest.readStringList(requestedPermissions);
6197            internStringArrayList(requestedPermissions);
6198            protectedBroadcasts = dest.createStringArrayList();
6199            internStringArrayList(protectedBroadcasts);
6200
6201            parentPackage = dest.readParcelable(boot);
6202
6203            childPackages = new ArrayList<>();
6204            dest.readParcelableList(childPackages, boot);
6205            if (childPackages.size() == 0) {
6206                childPackages = null;
6207            }
6208
6209            staticSharedLibName = dest.readString();
6210            if (staticSharedLibName != null) {
6211                staticSharedLibName = staticSharedLibName.intern();
6212            }
6213            staticSharedLibVersion = dest.readInt();
6214            libraryNames = dest.createStringArrayList();
6215            internStringArrayList(libraryNames);
6216            usesLibraries = dest.createStringArrayList();
6217            internStringArrayList(usesLibraries);
6218            usesOptionalLibraries = dest.createStringArrayList();
6219            internStringArrayList(usesOptionalLibraries);
6220            usesLibraryFiles = dest.readStringArray();
6221
6222            final int libCount = dest.readInt();
6223            if (libCount > 0) {
6224                usesStaticLibraries = new ArrayList<>(libCount);
6225                dest.readStringList(usesStaticLibraries);
6226                internStringArrayList(usesStaticLibraries);
6227                usesStaticLibrariesVersions = new int[libCount];
6228                dest.readIntArray(usesStaticLibrariesVersions);
6229                usesStaticLibrariesCertDigests = new String[libCount];
6230                dest.readStringArray(usesStaticLibrariesCertDigests);
6231            }
6232
6233            preferredActivityFilters = new ArrayList<>();
6234            dest.readParcelableList(preferredActivityFilters, boot);
6235            if (preferredActivityFilters.size() == 0) {
6236                preferredActivityFilters = null;
6237            }
6238
6239            mOriginalPackages = dest.createStringArrayList();
6240            mRealPackage = dest.readString();
6241            mAdoptPermissions = dest.createStringArrayList();
6242            mAppMetaData = dest.readBundle();
6243            mVersionCode = dest.readInt();
6244            mVersionName = dest.readString();
6245            if (mVersionName != null) {
6246                mVersionName = mVersionName.intern();
6247            }
6248            mSharedUserId = dest.readString();
6249            if (mSharedUserId != null) {
6250                mSharedUserId = mSharedUserId.intern();
6251            }
6252            mSharedUserLabel = dest.readInt();
6253
6254            mSignatures = (Signature[]) dest.readParcelableArray(boot, Signature.class);
6255            mCertificates = (Certificate[][]) dest.readSerializable();
6256
6257            mPreferredOrder = dest.readInt();
6258
6259            // long[] packageUsageTimeMillis is not persisted because it isn't information that
6260            // is parsed from the APK.
6261
6262            // Object mExtras is not persisted because it is not information that is read from
6263            // the APK, rather, it is supplied by callers.
6264
6265
6266            configPreferences = new ArrayList<>();
6267            dest.readParcelableList(configPreferences, boot);
6268            if (configPreferences.size() == 0) {
6269                configPreferences = null;
6270            }
6271
6272            reqFeatures = new ArrayList<>();
6273            dest.readParcelableList(reqFeatures, boot);
6274            if (reqFeatures.size() == 0) {
6275                reqFeatures = null;
6276            }
6277
6278            featureGroups = new ArrayList<>();
6279            dest.readParcelableList(featureGroups, boot);
6280            if (featureGroups.size() == 0) {
6281                featureGroups = null;
6282            }
6283
6284            installLocation = dest.readInt();
6285            coreApp = (dest.readInt() == 1);
6286            mRequiredForAllUsers = (dest.readInt() == 1);
6287            mRestrictedAccountType = dest.readString();
6288            mRequiredAccountType = dest.readString();
6289            mOverlayTarget = dest.readString();
6290            mOverlayPriority = dest.readInt();
6291            mIsStaticOverlay = (dest.readInt() == 1);
6292            mTrustedOverlay = (dest.readInt() == 1);
6293            mSigningKeys = (ArraySet<PublicKey>) dest.readArraySet(boot);
6294            mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);
6295
6296            mKeySetMapping = readKeySetMapping(dest);
6297
6298            cpuAbiOverride = dest.readString();
6299            use32bitAbi = (dest.readInt() == 1);
6300            restrictUpdateHash = dest.createByteArray();
6301            visibleToInstantApps = dest.readInt() == 1;
6302        }
6303
6304        private static void internStringArrayList(List<String> list) {
6305            if (list != null) {
6306                final int N = list.size();
6307                for (int i = 0; i < N; ++i) {
6308                    list.set(i, list.get(i).intern());
6309                }
6310            }
6311        }
6312
6313        /**
6314         * Sets the package owner and the the {@code applicationInfo} for every component
6315         * owner by this package.
6316         */
6317        private void fixupOwner(List<? extends Component<?>> list) {
6318            if (list != null) {
6319                for (Component<?> c : list) {
6320                    c.owner = this;
6321                    if (c instanceof Activity) {
6322                        ((Activity) c).info.applicationInfo = this.applicationInfo;
6323                    } else if (c instanceof Service) {
6324                        ((Service) c).info.applicationInfo = this.applicationInfo;
6325                    } else if (c instanceof Provider) {
6326                        ((Provider) c).info.applicationInfo = this.applicationInfo;
6327                    }
6328                }
6329            }
6330        }
6331
6332        @Override
6333        public void writeToParcel(Parcel dest, int flags) {
6334            dest.writeString(packageName);
6335            dest.writeString(manifestPackageName);
6336            dest.writeStringArray(splitNames);
6337            dest.writeString(volumeUuid);
6338            dest.writeString(codePath);
6339            dest.writeString(baseCodePath);
6340            dest.writeStringArray(splitCodePaths);
6341            dest.writeInt(baseRevisionCode);
6342            dest.writeIntArray(splitRevisionCodes);
6343            dest.writeIntArray(splitFlags);
6344            dest.writeIntArray(splitPrivateFlags);
6345            dest.writeInt(baseHardwareAccelerated ? 1 : 0);
6346            dest.writeParcelable(applicationInfo, flags);
6347
6348            dest.writeParcelableList(permissions, flags);
6349            dest.writeParcelableList(permissionGroups, flags);
6350            dest.writeParcelableList(activities, flags);
6351            dest.writeParcelableList(receivers, flags);
6352            dest.writeParcelableList(providers, flags);
6353            dest.writeParcelableList(services, flags);
6354            dest.writeParcelableList(instrumentation, flags);
6355
6356            dest.writeStringList(requestedPermissions);
6357            dest.writeStringList(protectedBroadcasts);
6358            dest.writeParcelable(parentPackage, flags);
6359            dest.writeParcelableList(childPackages, flags);
6360            dest.writeString(staticSharedLibName);
6361            dest.writeInt(staticSharedLibVersion);
6362            dest.writeStringList(libraryNames);
6363            dest.writeStringList(usesLibraries);
6364            dest.writeStringList(usesOptionalLibraries);
6365            dest.writeStringArray(usesLibraryFiles);
6366
6367            if (ArrayUtils.isEmpty(usesStaticLibraries)) {
6368                dest.writeInt(-1);
6369            } else {
6370                dest.writeInt(usesStaticLibraries.size());
6371                dest.writeStringList(usesStaticLibraries);
6372                dest.writeIntArray(usesStaticLibrariesVersions);
6373                dest.writeStringArray(usesStaticLibrariesCertDigests);
6374            }
6375
6376            dest.writeParcelableList(preferredActivityFilters, flags);
6377
6378            dest.writeStringList(mOriginalPackages);
6379            dest.writeString(mRealPackage);
6380            dest.writeStringList(mAdoptPermissions);
6381            dest.writeBundle(mAppMetaData);
6382            dest.writeInt(mVersionCode);
6383            dest.writeString(mVersionName);
6384            dest.writeString(mSharedUserId);
6385            dest.writeInt(mSharedUserLabel);
6386
6387            dest.writeParcelableArray(mSignatures, flags);
6388            dest.writeSerializable(mCertificates);
6389
6390            dest.writeInt(mPreferredOrder);
6391
6392            // long[] packageUsageTimeMillis is not persisted because it isn't information that
6393            // is parsed from the APK.
6394
6395            // Object mExtras is not persisted because it is not information that is read from
6396            // the APK, rather, it is supplied by callers.
6397
6398            dest.writeParcelableList(configPreferences, flags);
6399            dest.writeParcelableList(reqFeatures, flags);
6400            dest.writeParcelableList(featureGroups, flags);
6401
6402            dest.writeInt(installLocation);
6403            dest.writeInt(coreApp ? 1 : 0);
6404            dest.writeInt(mRequiredForAllUsers ? 1 : 0);
6405            dest.writeString(mRestrictedAccountType);
6406            dest.writeString(mRequiredAccountType);
6407            dest.writeString(mOverlayTarget);
6408            dest.writeInt(mOverlayPriority);
6409            dest.writeInt(mIsStaticOverlay ? 1 : 0);
6410            dest.writeInt(mTrustedOverlay ? 1 : 0);
6411            dest.writeArraySet(mSigningKeys);
6412            dest.writeArraySet(mUpgradeKeySets);
6413            writeKeySetMapping(dest, mKeySetMapping);
6414            dest.writeString(cpuAbiOverride);
6415            dest.writeInt(use32bitAbi ? 1 : 0);
6416            dest.writeByteArray(restrictUpdateHash);
6417            dest.writeInt(visibleToInstantApps ? 1 : 0);
6418        }
6419
6420
6421        /**
6422         * Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
6423         */
6424        private static void writeKeySetMapping(
6425                Parcel dest, ArrayMap<String, ArraySet<PublicKey>> keySetMapping) {
6426            if (keySetMapping == null) {
6427                dest.writeInt(-1);
6428                return;
6429            }
6430
6431            final int N = keySetMapping.size();
6432            dest.writeInt(N);
6433
6434            for (int i = 0; i < N; i++) {
6435                dest.writeString(keySetMapping.keyAt(i));
6436                ArraySet<PublicKey> keys = keySetMapping.valueAt(i);
6437                if (keys == null) {
6438                    dest.writeInt(-1);
6439                    continue;
6440                }
6441
6442                final int M = keys.size();
6443                dest.writeInt(M);
6444                for (int j = 0; j < M; j++) {
6445                    dest.writeSerializable(keys.valueAt(j));
6446                }
6447            }
6448        }
6449
6450        /**
6451         * Reads a keyset mapping from the given parcel at the given data position. May return
6452         * {@code null} if the serialized mapping was {@code null}.
6453         */
6454        private static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(Parcel in) {
6455            final int N = in.readInt();
6456            if (N == -1) {
6457                return null;
6458            }
6459
6460            ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>();
6461            for (int i = 0; i < N; ++i) {
6462                String key = in.readString();
6463                final int M = in.readInt();
6464                if (M == -1) {
6465                    keySetMapping.put(key, null);
6466                    continue;
6467                }
6468
6469                ArraySet<PublicKey> keys = new ArraySet<>(M);
6470                for (int j = 0; j < M; ++j) {
6471                    PublicKey pk = (PublicKey) in.readSerializable();
6472                    keys.add(pk);
6473                }
6474
6475                keySetMapping.put(key, keys);
6476            }
6477
6478            return keySetMapping;
6479        }
6480
6481        public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Package>() {
6482            public Package createFromParcel(Parcel in) {
6483                return new Package(in);
6484            }
6485
6486            public Package[] newArray(int size) {
6487                return new Package[size];
6488            }
6489        };
6490    }
6491
6492    public static abstract class Component<II extends IntentInfo> {
6493        public final ArrayList<II> intents;
6494        public final String className;
6495
6496        public Bundle metaData;
6497        public Package owner;
6498
6499        ComponentName componentName;
6500        String componentShortName;
6501
6502        public Component(Package _owner) {
6503            owner = _owner;
6504            intents = null;
6505            className = null;
6506        }
6507
6508        public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
6509            owner = args.owner;
6510            intents = new ArrayList<II>(0);
6511            if (parsePackageItemInfo(args.owner, outInfo, args.outError, args.tag, args.sa,
6512                    true /*nameRequired*/, args.nameRes, args.labelRes, args.iconRes,
6513                    args.roundIconRes, args.logoRes, args.bannerRes)) {
6514                className = outInfo.name;
6515            } else {
6516                className = null;
6517            }
6518        }
6519
6520        public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
6521            this(args, (PackageItemInfo)outInfo);
6522            if (args.outError[0] != null) {
6523                return;
6524            }
6525
6526            if (args.processRes != 0) {
6527                CharSequence pname;
6528                if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
6529                    pname = args.sa.getNonConfigurationString(args.processRes,
6530                            Configuration.NATIVE_CONFIG_VERSION);
6531                } else {
6532                    // Some older apps have been seen to use a resource reference
6533                    // here that on older builds was ignored (with a warning).  We
6534                    // need to continue to do this for them so they don't break.
6535                    pname = args.sa.getNonResourceString(args.processRes);
6536                }
6537                outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
6538                        owner.applicationInfo.processName, pname,
6539                        args.flags, args.sepProcesses, args.outError);
6540            }
6541
6542            if (args.descriptionRes != 0) {
6543                outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
6544            }
6545
6546            outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
6547        }
6548
6549        public Component(Component<II> clone) {
6550            owner = clone.owner;
6551            intents = clone.intents;
6552            className = clone.className;
6553            componentName = clone.componentName;
6554            componentShortName = clone.componentShortName;
6555        }
6556
6557        public ComponentName getComponentName() {
6558            if (componentName != null) {
6559                return componentName;
6560            }
6561            if (className != null) {
6562                componentName = new ComponentName(owner.applicationInfo.packageName,
6563                        className);
6564            }
6565            return componentName;
6566        }
6567
6568        protected Component(Parcel in) {
6569            className = in.readString();
6570            metaData = in.readBundle();
6571            intents = createIntentsList(in);
6572
6573            owner = null;
6574        }
6575
6576        protected void writeToParcel(Parcel dest, int flags) {
6577            dest.writeString(className);
6578            dest.writeBundle(metaData);
6579
6580            writeIntentsList(intents, dest, flags);
6581        }
6582
6583        /**
6584         * <p>
6585         * Implementation note: The serialized form for the intent list also contains the name
6586         * of the concrete class that's stored in the list, and assumes that every element of the
6587         * list is of the same type. This is very similar to the original parcelable mechanism.
6588         * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable
6589         * and is public API. It also declares Parcelable related methods as final which means
6590         * we can't extend them. The approach of using composition instead of inheritance leads to
6591         * a large set of cascading changes in the PackageManagerService, which seem undesirable.
6592         *
6593         * <p>
6594         * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up
6595         * to make sure their owner fields are consistent. See {@code fixupOwner}.
6596         */
6597        private static void writeIntentsList(ArrayList<? extends IntentInfo> list, Parcel out,
6598                                             int flags) {
6599            if (list == null) {
6600                out.writeInt(-1);
6601                return;
6602            }
6603
6604            final int N = list.size();
6605            out.writeInt(N);
6606
6607            // Don't bother writing the component name if the list is empty.
6608            if (N > 0) {
6609                IntentInfo info = list.get(0);
6610                out.writeString(info.getClass().getName());
6611
6612                for (int i = 0; i < N;i++) {
6613                    list.get(i).writeIntentInfoToParcel(out, flags);
6614                }
6615            }
6616        }
6617
6618        private static <T extends IntentInfo> ArrayList<T> createIntentsList(Parcel in) {
6619            int N = in.readInt();
6620            if (N == -1) {
6621                return null;
6622            }
6623
6624            if (N == 0) {
6625                return new ArrayList<>(0);
6626            }
6627
6628            String componentName = in.readString();
6629            final ArrayList<T> intentsList;
6630            try {
6631                final Class<T> cls = (Class<T>) Class.forName(componentName);
6632                final Constructor<T> cons = cls.getConstructor(Parcel.class);
6633
6634                intentsList = new ArrayList<>(N);
6635                for (int i = 0; i < N; ++i) {
6636                    intentsList.add(cons.newInstance(in));
6637                }
6638            } catch (ReflectiveOperationException ree) {
6639                throw new AssertionError("Unable to construct intent list for: " + componentName);
6640            }
6641
6642            return intentsList;
6643        }
6644
6645        public void appendComponentShortName(StringBuilder sb) {
6646            ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className);
6647        }
6648
6649        public void printComponentShortName(PrintWriter pw) {
6650            ComponentName.printShortString(pw, owner.applicationInfo.packageName, className);
6651        }
6652
6653        public void setPackageName(String packageName) {
6654            componentName = null;
6655            componentShortName = null;
6656        }
6657    }
6658
6659    public final static class Permission extends Component<IntentInfo> implements Parcelable {
6660        public final PermissionInfo info;
6661        public boolean tree;
6662        public PermissionGroup group;
6663
6664        public Permission(Package _owner) {
6665            super(_owner);
6666            info = new PermissionInfo();
6667        }
6668
6669        public Permission(Package _owner, PermissionInfo _info) {
6670            super(_owner);
6671            info = _info;
6672        }
6673
6674        public void setPackageName(String packageName) {
6675            super.setPackageName(packageName);
6676            info.packageName = packageName;
6677        }
6678
6679        public String toString() {
6680            return "Permission{"
6681                + Integer.toHexString(System.identityHashCode(this))
6682                + " " + info.name + "}";
6683        }
6684
6685        @Override
6686        public int describeContents() {
6687            return 0;
6688        }
6689
6690        @Override
6691        public void writeToParcel(Parcel dest, int flags) {
6692            super.writeToParcel(dest, flags);
6693            dest.writeParcelable(info, flags);
6694            dest.writeInt(tree ? 1 : 0);
6695            dest.writeParcelable(group, flags);
6696        }
6697
6698        private Permission(Parcel in) {
6699            super(in);
6700            final ClassLoader boot = Object.class.getClassLoader();
6701            info = in.readParcelable(boot);
6702            if (info.group != null) {
6703                info.group = info.group.intern();
6704            }
6705
6706            tree = (in.readInt() == 1);
6707            group = in.readParcelable(boot);
6708        }
6709
6710        public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Permission>() {
6711            public Permission createFromParcel(Parcel in) {
6712                return new Permission(in);
6713            }
6714
6715            public Permission[] newArray(int size) {
6716                return new Permission[size];
6717            }
6718        };
6719    }
6720
6721    public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable {
6722        public final PermissionGroupInfo info;
6723
6724        public PermissionGroup(Package _owner) {
6725            super(_owner);
6726            info = new PermissionGroupInfo();
6727        }
6728
6729        public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
6730            super(_owner);
6731            info = _info;
6732        }
6733
6734        public void setPackageName(String packageName) {
6735            super.setPackageName(packageName);
6736            info.packageName = packageName;
6737        }
6738
6739        public String toString() {
6740            return "PermissionGroup{"
6741                + Integer.toHexString(System.identityHashCode(this))
6742                + " " + info.name + "}";
6743        }
6744
6745        @Override
6746        public int describeContents() {
6747            return 0;
6748        }
6749
6750        @Override
6751        public void writeToParcel(Parcel dest, int flags) {
6752            super.writeToParcel(dest, flags);
6753            dest.writeParcelable(info, flags);
6754        }
6755
6756        private PermissionGroup(Parcel in) {
6757            super(in);
6758            info = in.readParcelable(Object.class.getClassLoader());
6759        }
6760
6761        public static final Parcelable.Creator CREATOR = new Parcelable.Creator<PermissionGroup>() {
6762            public PermissionGroup createFromParcel(Parcel in) {
6763                return new PermissionGroup(in);
6764            }
6765
6766            public PermissionGroup[] newArray(int size) {
6767                return new PermissionGroup[size];
6768            }
6769        };
6770    }
6771
6772    private static boolean copyNeeded(int flags, Package p,
6773            PackageUserState state, Bundle metaData, int userId) {
6774        if (userId != UserHandle.USER_SYSTEM) {
6775            // We always need to copy for other users, since we need
6776            // to fix up the uid.
6777            return true;
6778        }
6779        if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
6780            boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
6781            if (p.applicationInfo.enabled != enabled) {
6782                return true;
6783            }
6784        }
6785        boolean suspended = (p.applicationInfo.flags & FLAG_SUSPENDED) != 0;
6786        if (state.suspended != suspended) {
6787            return true;
6788        }
6789        if (!state.installed || state.hidden) {
6790            return true;
6791        }
6792        if (state.stopped) {
6793            return true;
6794        }
6795        if (state.instantApp != p.applicationInfo.isInstantApp()) {
6796            return true;
6797        }
6798        if ((flags & PackageManager.GET_META_DATA) != 0
6799                && (metaData != null || p.mAppMetaData != null)) {
6800            return true;
6801        }
6802        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
6803                && p.usesLibraryFiles != null) {
6804            return true;
6805        }
6806        if (p.staticSharedLibName != null) {
6807            return true;
6808        }
6809        return false;
6810    }
6811
6812    public static ApplicationInfo generateApplicationInfo(Package p, int flags,
6813            PackageUserState state) {
6814        return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
6815    }
6816
6817    private static void updateApplicationInfo(ApplicationInfo ai, int flags,
6818            PackageUserState state) {
6819        // CompatibilityMode is global state.
6820        if (!sCompatibilityModeEnabled) {
6821            ai.disableCompatibilityMode();
6822        }
6823        if (state.installed) {
6824            ai.flags |= ApplicationInfo.FLAG_INSTALLED;
6825        } else {
6826            ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
6827        }
6828        if (state.suspended) {
6829            ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
6830        } else {
6831            ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
6832        }
6833        if (state.instantApp) {
6834            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT;
6835        } else {
6836            ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT;
6837        }
6838        if (state.hidden) {
6839            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
6840        } else {
6841            ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
6842        }
6843        if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
6844            ai.enabled = true;
6845        } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
6846            ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
6847        } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
6848                || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
6849            ai.enabled = false;
6850        }
6851        ai.enabledSetting = state.enabled;
6852        if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
6853            ai.category = state.categoryHint;
6854        }
6855        if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
6856            ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
6857        }
6858        ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
6859        ai.resourceDirs = state.overlayPaths;
6860    }
6861
6862    public static ApplicationInfo generateApplicationInfo(Package p, int flags,
6863            PackageUserState state, int userId) {
6864        if (p == null) return null;
6865        if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
6866            return null;
6867        }
6868        if (!copyNeeded(flags, p, state, null, userId)
6869                && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0
6870                        || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
6871            // In this case it is safe to directly modify the internal ApplicationInfo state:
6872            // - CompatibilityMode is global state, so will be the same for every call.
6873            // - We only come in to here if the app should reported as installed; this is the
6874            // default state, and we will do a copy otherwise.
6875            // - The enable state will always be reported the same for the application across
6876            // calls; the only exception is for the UNTIL_USED mode, and in that case we will
6877            // be doing a copy.
6878            updateApplicationInfo(p.applicationInfo, flags, state);
6879            return p.applicationInfo;
6880        }
6881
6882        // Make shallow copy so we can store the metadata/libraries safely
6883        ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
6884        ai.initForUser(userId);
6885        if ((flags & PackageManager.GET_META_DATA) != 0) {
6886            ai.metaData = p.mAppMetaData;
6887        }
6888        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
6889            ai.sharedLibraryFiles = p.usesLibraryFiles;
6890        }
6891        if (state.stopped) {
6892            ai.flags |= ApplicationInfo.FLAG_STOPPED;
6893        } else {
6894            ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
6895        }
6896        updateApplicationInfo(ai, flags, state);
6897        return ai;
6898    }
6899
6900    public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags,
6901            PackageUserState state, int userId) {
6902        if (ai == null) return null;
6903        if (!checkUseInstalledOrHidden(flags, state, ai)) {
6904            return null;
6905        }
6906        // This is only used to return the ResolverActivity; we will just always
6907        // make a copy.
6908        ai = new ApplicationInfo(ai);
6909        ai.initForUser(userId);
6910        if (state.stopped) {
6911            ai.flags |= ApplicationInfo.FLAG_STOPPED;
6912        } else {
6913            ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
6914        }
6915        updateApplicationInfo(ai, flags, state);
6916        return ai;
6917    }
6918
6919    public static final PermissionInfo generatePermissionInfo(
6920            Permission p, int flags) {
6921        if (p == null) return null;
6922        if ((flags&PackageManager.GET_META_DATA) == 0) {
6923            return p.info;
6924        }
6925        PermissionInfo pi = new PermissionInfo(p.info);
6926        pi.metaData = p.metaData;
6927        return pi;
6928    }
6929
6930    public static final PermissionGroupInfo generatePermissionGroupInfo(
6931            PermissionGroup pg, int flags) {
6932        if (pg == null) return null;
6933        if ((flags&PackageManager.GET_META_DATA) == 0) {
6934            return pg.info;
6935        }
6936        PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);
6937        pgi.metaData = pg.metaData;
6938        return pgi;
6939    }
6940
6941    public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
6942        public final ActivityInfo info;
6943
6944        public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
6945            super(args, _info);
6946            info = _info;
6947            info.applicationInfo = args.owner.applicationInfo;
6948        }
6949
6950        public void setPackageName(String packageName) {
6951            super.setPackageName(packageName);
6952            info.packageName = packageName;
6953        }
6954
6955        public String toString() {
6956            StringBuilder sb = new StringBuilder(128);
6957            sb.append("Activity{");
6958            sb.append(Integer.toHexString(System.identityHashCode(this)));
6959            sb.append(' ');
6960            appendComponentShortName(sb);
6961            sb.append('}');
6962            return sb.toString();
6963        }
6964
6965        @Override
6966        public int describeContents() {
6967            return 0;
6968        }
6969
6970        @Override
6971        public void writeToParcel(Parcel dest, int flags) {
6972            super.writeToParcel(dest, flags);
6973            dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
6974        }
6975
6976        private Activity(Parcel in) {
6977            super(in);
6978            info = in.readParcelable(Object.class.getClassLoader());
6979
6980            for (ActivityIntentInfo aii : intents) {
6981                aii.activity = this;
6982            }
6983
6984            if (info.permission != null) {
6985                info.permission = info.permission.intern();
6986            }
6987        }
6988
6989        public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Activity>() {
6990            public Activity createFromParcel(Parcel in) {
6991                return new Activity(in);
6992            }
6993
6994            public Activity[] newArray(int size) {
6995                return new Activity[size];
6996            }
6997        };
6998    }
6999
7000    public static final ActivityInfo generateActivityInfo(Activity a, int flags,
7001            PackageUserState state, int userId) {
7002        if (a == null) return null;
7003        if (!checkUseInstalledOrHidden(flags, state, a.owner.applicationInfo)) {
7004            return null;
7005        }
7006        if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
7007            updateApplicationInfo(a.info.applicationInfo, flags, state);
7008            return a.info;
7009        }
7010        // Make shallow copies so we can store the metadata safely
7011        ActivityInfo ai = new ActivityInfo(a.info);
7012        ai.metaData = a.metaData;
7013        ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);
7014        return ai;
7015    }
7016
7017    public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags,
7018            PackageUserState state, int userId) {
7019        if (ai == null) return null;
7020        if (!checkUseInstalledOrHidden(flags, state, ai.applicationInfo)) {
7021            return null;
7022        }
7023        // This is only used to return the ResolverActivity; we will just always
7024        // make a copy.
7025        ai = new ActivityInfo(ai);
7026        ai.applicationInfo = generateApplicationInfo(ai.applicationInfo, flags, state, userId);
7027        return ai;
7028    }
7029
7030    public final static class Service extends Component<ServiceIntentInfo> implements Parcelable {
7031        public final ServiceInfo info;
7032
7033        public Service(final ParseComponentArgs args, final ServiceInfo _info) {
7034            super(args, _info);
7035            info = _info;
7036            info.applicationInfo = args.owner.applicationInfo;
7037        }
7038
7039        public void setPackageName(String packageName) {
7040            super.setPackageName(packageName);
7041            info.packageName = packageName;
7042        }
7043
7044        public String toString() {
7045            StringBuilder sb = new StringBuilder(128);
7046            sb.append("Service{");
7047            sb.append(Integer.toHexString(System.identityHashCode(this)));
7048            sb.append(' ');
7049            appendComponentShortName(sb);
7050            sb.append('}');
7051            return sb.toString();
7052        }
7053
7054        @Override
7055        public int describeContents() {
7056            return 0;
7057        }
7058
7059        @Override
7060        public void writeToParcel(Parcel dest, int flags) {
7061            super.writeToParcel(dest, flags);
7062            dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
7063        }
7064
7065        private Service(Parcel in) {
7066            super(in);
7067            info = in.readParcelable(Object.class.getClassLoader());
7068
7069            for (ServiceIntentInfo aii : intents) {
7070                aii.service = this;
7071            }
7072
7073            if (info.permission != null) {
7074                info.permission = info.permission.intern();
7075            }
7076        }
7077
7078        public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Service>() {
7079            public Service createFromParcel(Parcel in) {
7080                return new Service(in);
7081            }
7082
7083            public Service[] newArray(int size) {
7084                return new Service[size];
7085            }
7086        };
7087    }
7088
7089    public static final ServiceInfo generateServiceInfo(Service s, int flags,
7090            PackageUserState state, int userId) {
7091        if (s == null) return null;
7092        if (!checkUseInstalledOrHidden(flags, state, s.owner.applicationInfo)) {
7093            return null;
7094        }
7095        if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
7096            updateApplicationInfo(s.info.applicationInfo, flags, state);
7097            return s.info;
7098        }
7099        // Make shallow copies so we can store the metadata safely
7100        ServiceInfo si = new ServiceInfo(s.info);
7101        si.metaData = s.metaData;
7102        si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId);
7103        return si;
7104    }
7105
7106    public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable {
7107        public final ProviderInfo info;
7108        public boolean syncable;
7109
7110        public Provider(final ParseComponentArgs args, final ProviderInfo _info) {
7111            super(args, _info);
7112            info = _info;
7113            info.applicationInfo = args.owner.applicationInfo;
7114            syncable = false;
7115        }
7116
7117        public Provider(Provider existingProvider) {
7118            super(existingProvider);
7119            this.info = existingProvider.info;
7120            this.syncable = existingProvider.syncable;
7121        }
7122
7123        public void setPackageName(String packageName) {
7124            super.setPackageName(packageName);
7125            info.packageName = packageName;
7126        }
7127
7128        public String toString() {
7129            StringBuilder sb = new StringBuilder(128);
7130            sb.append("Provider{");
7131            sb.append(Integer.toHexString(System.identityHashCode(this)));
7132            sb.append(' ');
7133            appendComponentShortName(sb);
7134            sb.append('}');
7135            return sb.toString();
7136        }
7137
7138        @Override
7139        public int describeContents() {
7140            return 0;
7141        }
7142
7143        @Override
7144        public void writeToParcel(Parcel dest, int flags) {
7145            super.writeToParcel(dest, flags);
7146            dest.writeParcelable(info, flags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
7147            dest.writeInt((syncable) ? 1 : 0);
7148        }
7149
7150        private Provider(Parcel in) {
7151            super(in);
7152            info = in.readParcelable(Object.class.getClassLoader());
7153            syncable = (in.readInt() == 1);
7154
7155            for (ProviderIntentInfo aii : intents) {
7156                aii.provider = this;
7157            }
7158
7159            if (info.readPermission != null) {
7160                info.readPermission = info.readPermission.intern();
7161            }
7162
7163            if (info.writePermission != null) {
7164                info.writePermission = info.writePermission.intern();
7165            }
7166
7167            if (info.authority != null) {
7168                info.authority = info.authority.intern();
7169            }
7170        }
7171
7172        public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Provider>() {
7173            public Provider createFromParcel(Parcel in) {
7174                return new Provider(in);
7175            }
7176
7177            public Provider[] newArray(int size) {
7178                return new Provider[size];
7179            }
7180        };
7181    }
7182
7183    public static final ProviderInfo generateProviderInfo(Provider p, int flags,
7184            PackageUserState state, int userId) {
7185        if (p == null) return null;
7186        if (!checkUseInstalledOrHidden(flags, state, p.owner.applicationInfo)) {
7187            return null;
7188        }
7189        if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
7190                && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
7191                        || p.info.uriPermissionPatterns == null)) {
7192            updateApplicationInfo(p.info.applicationInfo, flags, state);
7193            return p.info;
7194        }
7195        // Make shallow copies so we can store the metadata safely
7196        ProviderInfo pi = new ProviderInfo(p.info);
7197        pi.metaData = p.metaData;
7198        if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
7199            pi.uriPermissionPatterns = null;
7200        }
7201        pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId);
7202        return pi;
7203    }
7204
7205    public final static class Instrumentation extends Component<IntentInfo> implements
7206            Parcelable {
7207        public final InstrumentationInfo info;
7208
7209        public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
7210            super(args, _info);
7211            info = _info;
7212        }
7213
7214        public void setPackageName(String packageName) {
7215            super.setPackageName(packageName);
7216            info.packageName = packageName;
7217        }
7218
7219        public String toString() {
7220            StringBuilder sb = new StringBuilder(128);
7221            sb.append("Instrumentation{");
7222            sb.append(Integer.toHexString(System.identityHashCode(this)));
7223            sb.append(' ');
7224            appendComponentShortName(sb);
7225            sb.append('}');
7226            return sb.toString();
7227        }
7228
7229        @Override
7230        public int describeContents() {
7231            return 0;
7232        }
7233
7234        @Override
7235        public void writeToParcel(Parcel dest, int flags) {
7236            super.writeToParcel(dest, flags);
7237            dest.writeParcelable(info, flags);
7238        }
7239
7240        private Instrumentation(Parcel in) {
7241            super(in);
7242            info = in.readParcelable(Object.class.getClassLoader());
7243
7244            if (info.targetPackage != null) {
7245                info.targetPackage = info.targetPackage.intern();
7246            }
7247
7248            if (info.targetProcesses != null) {
7249                info.targetProcesses = info.targetProcesses.intern();
7250            }
7251        }
7252
7253        public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Instrumentation>() {
7254            public Instrumentation createFromParcel(Parcel in) {
7255                return new Instrumentation(in);
7256            }
7257
7258            public Instrumentation[] newArray(int size) {
7259                return new Instrumentation[size];
7260            }
7261        };
7262    }
7263
7264    public static final InstrumentationInfo generateInstrumentationInfo(
7265            Instrumentation i, int flags) {
7266        if (i == null) return null;
7267        if ((flags&PackageManager.GET_META_DATA) == 0) {
7268            return i.info;
7269        }
7270        InstrumentationInfo ii = new InstrumentationInfo(i.info);
7271        ii.metaData = i.metaData;
7272        return ii;
7273    }
7274
7275    public static abstract class IntentInfo extends IntentFilter {
7276        public boolean hasDefault;
7277        public int labelRes;
7278        public CharSequence nonLocalizedLabel;
7279        public int icon;
7280        public int logo;
7281        public int banner;
7282        public int preferred;
7283
7284        protected IntentInfo() {
7285        }
7286
7287        protected IntentInfo(Parcel dest) {
7288            super(dest);
7289            hasDefault = (dest.readInt() == 1);
7290            labelRes = dest.readInt();
7291            nonLocalizedLabel = dest.readCharSequence();
7292            icon = dest.readInt();
7293            logo = dest.readInt();
7294            banner = dest.readInt();
7295            preferred = dest.readInt();
7296        }
7297
7298
7299        public void writeIntentInfoToParcel(Parcel dest, int flags) {
7300            super.writeToParcel(dest, flags);
7301            dest.writeInt(hasDefault ? 1 : 0);
7302            dest.writeInt(labelRes);
7303            dest.writeCharSequence(nonLocalizedLabel);
7304            dest.writeInt(icon);
7305            dest.writeInt(logo);
7306            dest.writeInt(banner);
7307            dest.writeInt(preferred);
7308        }
7309    }
7310
7311    public final static class ActivityIntentInfo extends IntentInfo {
7312        public Activity activity;
7313
7314        public ActivityIntentInfo(Activity _activity) {
7315            activity = _activity;
7316        }
7317
7318        public String toString() {
7319            StringBuilder sb = new StringBuilder(128);
7320            sb.append("ActivityIntentInfo{");
7321            sb.append(Integer.toHexString(System.identityHashCode(this)));
7322            sb.append(' ');
7323            activity.appendComponentShortName(sb);
7324            sb.append('}');
7325            return sb.toString();
7326        }
7327
7328        public ActivityIntentInfo(Parcel in) {
7329            super(in);
7330        }
7331    }
7332
7333    public final static class ServiceIntentInfo extends IntentInfo {
7334        public Service service;
7335
7336        public ServiceIntentInfo(Service _service) {
7337            service = _service;
7338        }
7339
7340        public String toString() {
7341            StringBuilder sb = new StringBuilder(128);
7342            sb.append("ServiceIntentInfo{");
7343            sb.append(Integer.toHexString(System.identityHashCode(this)));
7344            sb.append(' ');
7345            service.appendComponentShortName(sb);
7346            sb.append('}');
7347            return sb.toString();
7348        }
7349
7350        public ServiceIntentInfo(Parcel in) {
7351            super(in);
7352        }
7353    }
7354
7355    public static final class ProviderIntentInfo extends IntentInfo {
7356        public Provider provider;
7357
7358        public ProviderIntentInfo(Provider provider) {
7359            this.provider = provider;
7360        }
7361
7362        public String toString() {
7363            StringBuilder sb = new StringBuilder(128);
7364            sb.append("ProviderIntentInfo{");
7365            sb.append(Integer.toHexString(System.identityHashCode(this)));
7366            sb.append(' ');
7367            provider.appendComponentShortName(sb);
7368            sb.append('}');
7369            return sb.toString();
7370        }
7371
7372        public ProviderIntentInfo(Parcel in) {
7373            super(in);
7374        }
7375    }
7376
7377    /**
7378     * @hide
7379     */
7380    public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
7381        sCompatibilityModeEnabled = compatibilityModeEnabled;
7382    }
7383
7384    private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>();
7385
7386    public static long readFullyIgnoringContents(InputStream in) throws IOException {
7387        byte[] buffer = sBuffer.getAndSet(null);
7388        if (buffer == null) {
7389            buffer = new byte[4096];
7390        }
7391
7392        int n = 0;
7393        int count = 0;
7394        while ((n = in.read(buffer, 0, buffer.length)) != -1) {
7395            count += n;
7396        }
7397
7398        sBuffer.set(buffer);
7399        return count;
7400    }
7401
7402    public static void closeQuietly(StrictJarFile jarFile) {
7403        if (jarFile != null) {
7404            try {
7405                jarFile.close();
7406            } catch (Exception ignored) {
7407            }
7408        }
7409    }
7410
7411    public static class PackageParserException extends Exception {
7412        public final int error;
7413
7414        public PackageParserException(int error, String detailMessage) {
7415            super(detailMessage);
7416            this.error = error;
7417        }
7418
7419        public PackageParserException(int error, String detailMessage, Throwable throwable) {
7420            super(detailMessage, throwable);
7421            this.error = error;
7422        }
7423    }
7424}
7425