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