• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 package com.android.server.pm.pkg.parsing;
18 
19 import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
20 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
21 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
22 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
23 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
24 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
25 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
26 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED;
27 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED;
28 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
29 import static android.os.Build.VERSION_CODES.DONUT;
30 import static android.os.Build.VERSION_CODES.O;
31 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
32 
33 import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
34 
35 import android.annotation.AnyRes;
36 import android.annotation.CheckResult;
37 import android.annotation.IntDef;
38 import android.annotation.NonNull;
39 import android.annotation.Nullable;
40 import android.annotation.StyleableRes;
41 import android.app.ActivityThread;
42 import android.app.ResourcesManager;
43 import android.content.Intent;
44 import android.content.IntentFilter;
45 import android.content.pm.ApplicationInfo;
46 import android.content.pm.ConfigurationInfo;
47 import android.content.pm.FeatureGroupInfo;
48 import android.content.pm.FeatureInfo;
49 import android.content.pm.PackageInfo;
50 import android.content.pm.PackageManager;
51 import android.content.pm.PackageManager.Property;
52 import android.content.pm.Signature;
53 import android.content.pm.SigningDetails;
54 import android.content.pm.parsing.ApkLiteParseUtils;
55 import android.content.pm.parsing.FrameworkParsingPackageUtils;
56 import android.content.pm.parsing.PackageLite;
57 import android.content.pm.parsing.result.ParseInput;
58 import android.content.pm.parsing.result.ParseInput.DeferredError;
59 import android.content.pm.parsing.result.ParseResult;
60 import android.content.pm.parsing.result.ParseTypeImpl;
61 import android.content.res.ApkAssets;
62 import android.content.res.AssetManager;
63 import android.content.res.Configuration;
64 import android.content.res.Resources;
65 import android.content.res.TypedArray;
66 import android.content.res.XmlResourceParser;
67 import android.net.Uri;
68 import android.os.Build;
69 import android.os.Bundle;
70 import android.os.Environment;
71 import android.os.Parcel;
72 import android.os.RemoteException;
73 import android.os.SystemProperties;
74 import android.os.Trace;
75 import android.os.UserHandle;
76 import android.os.ext.SdkExtensions;
77 import android.permission.PermissionManager;
78 import android.text.TextUtils;
79 import android.util.ArrayMap;
80 import android.util.ArraySet;
81 import android.util.AttributeSet;
82 import android.util.DisplayMetrics;
83 import android.util.Pair;
84 import android.util.Slog;
85 import android.util.SparseArray;
86 import android.util.SparseIntArray;
87 import android.util.TypedValue;
88 import android.util.apk.ApkSignatureVerifier;
89 
90 import com.android.internal.R;
91 import com.android.internal.os.ClassLoaderFactory;
92 import com.android.internal.util.ArrayUtils;
93 import com.android.internal.util.XmlUtils;
94 import com.android.server.pm.SharedUidMigration;
95 import com.android.server.pm.permission.CompatibilityPermissionInfo;
96 import com.android.server.pm.pkg.component.ComponentMutateUtils;
97 import com.android.server.pm.pkg.component.ComponentParseUtils;
98 import com.android.server.pm.pkg.component.InstallConstraintsTagParser;
99 import com.android.server.pm.pkg.component.ParsedActivity;
100 import com.android.server.pm.pkg.component.ParsedActivityUtils;
101 import com.android.server.pm.pkg.component.ParsedApexSystemService;
102 import com.android.server.pm.pkg.component.ParsedApexSystemServiceUtils;
103 import com.android.server.pm.pkg.component.ParsedAttribution;
104 import com.android.server.pm.pkg.component.ParsedAttributionUtils;
105 import com.android.server.pm.pkg.component.ParsedComponent;
106 import com.android.server.pm.pkg.component.ParsedInstrumentation;
107 import com.android.server.pm.pkg.component.ParsedInstrumentationUtils;
108 import com.android.server.pm.pkg.component.ParsedIntentInfo;
109 import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
110 import com.android.server.pm.pkg.component.ParsedIntentInfoUtils;
111 import com.android.server.pm.pkg.component.ParsedMainComponent;
112 import com.android.server.pm.pkg.component.ParsedPermission;
113 import com.android.server.pm.pkg.component.ParsedPermissionGroup;
114 import com.android.server.pm.pkg.component.ParsedPermissionUtils;
115 import com.android.server.pm.pkg.component.ParsedProcess;
116 import com.android.server.pm.pkg.component.ParsedProcessUtils;
117 import com.android.server.pm.pkg.component.ParsedProvider;
118 import com.android.server.pm.pkg.component.ParsedProviderUtils;
119 import com.android.server.pm.pkg.component.ParsedService;
120 import com.android.server.pm.pkg.component.ParsedServiceUtils;
121 import com.android.server.pm.pkg.component.ParsedUsesPermission;
122 import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
123 import com.android.server.pm.split.DefaultSplitAssetLoader;
124 import com.android.server.pm.split.SplitAssetDependencyLoader;
125 import com.android.server.pm.split.SplitAssetLoader;
126 
127 import libcore.io.IoUtils;
128 import libcore.util.EmptyArray;
129 import libcore.util.HexEncoding;
130 
131 import org.xmlpull.v1.XmlPullParser;
132 import org.xmlpull.v1.XmlPullParserException;
133 
134 import java.io.File;
135 import java.io.IOException;
136 import java.lang.annotation.Retention;
137 import java.lang.annotation.RetentionPolicy;
138 import java.security.PublicKey;
139 import java.util.ArrayList;
140 import java.util.List;
141 import java.util.Map;
142 import java.util.Objects;
143 import java.util.Set;
144 import java.util.StringTokenizer;
145 
146 /**
147  * TODO(b/135203078): Differentiate between parse_ methods and some add_ method for whether it
148  * mutates the passed-in component or not. Or consolidate so all parse_ methods mutate.
149  *
150  * @hide
151  */
152 public class ParsingPackageUtils {
153 
154     private static final String TAG = ParsingUtils.TAG;
155 
156     public static final boolean DEBUG_JAR = false;
157     public static final boolean DEBUG_BACKUP = false;
158     public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
159     public static final float ASPECT_RATIO_NOT_SET = -1f;
160 
161     /**
162      * File name in an APK for the Android manifest.
163      */
164     public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
165 
166     /**
167      * Path prefix for apps on expanded storage
168      */
169     public static final String MNT_EXPAND = "/mnt/expand/";
170 
171     public static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
172     public static final String TAG_APPLICATION = "application";
173     public static final String TAG_ATTRIBUTION = "attribution";
174     public static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";
175     public static final String TAG_EAT_COMMENT = "eat-comment";
176     public static final String TAG_FEATURE_GROUP = "feature-group";
177     public static final String TAG_INSTALL_CONSTRAINTS = "install-constraints";
178     public static final String TAG_INSTRUMENTATION = "instrumentation";
179     public static final String TAG_KEY_SETS = "key-sets";
180     public static final String TAG_MANIFEST = "manifest";
181     public static final String TAG_ORIGINAL_PACKAGE = "original-package";
182     public static final String TAG_OVERLAY = "overlay";
183     public static final String TAG_PACKAGE = "package";
184     public static final String TAG_PACKAGE_VERIFIER = "package-verifier";
185     public static final String TAG_PERMISSION = "permission";
186     public static final String TAG_PERMISSION_GROUP = "permission-group";
187     public static final String TAG_PERMISSION_TREE = "permission-tree";
188     public static final String TAG_PROFILEABLE = "profileable";
189     public static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";
190     public static final String TAG_QUERIES = "queries";
191     public static final String TAG_RECEIVER = "receiver";
192     public static final String TAG_RESTRICT_UPDATE = "restrict-update";
193     public static final String TAG_SUPPORTS_INPUT = "supports-input";
194     public static final String TAG_SUPPORT_SCREENS = "supports-screens";
195     public static final String TAG_USES_CONFIGURATION = "uses-configuration";
196     public static final String TAG_USES_FEATURE = "uses-feature";
197     public static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
198     public static final String TAG_USES_PERMISSION = "uses-permission";
199     public static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";
200     public static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
201     public static final String TAG_USES_SDK = "uses-sdk";
202     public static final String TAG_USES_SPLIT = "uses-split";
203 
204     public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
205     public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes";
206     public static final String METADATA_CAN_DISPLAY_ON_REMOTE_DEVICES =
207             "android.can_display_on_remote_devices";
208     public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY =
209             "android.activity_window_layout_affinity";
210     public static final String METADATA_ACTIVITY_LAUNCH_MODE = "android.activity.launch_mode";
211 
212     public static final int SDK_VERSION = Build.VERSION.SDK_INT;
213     public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
214 
215     public static boolean sCompatibilityModeEnabled = true;
216     public static boolean sUseRoundIcon = false;
217 
218     public static final int PARSE_DEFAULT_INSTALL_LOCATION =
219             PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
220     public static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
221 
222     /**
223      * If set to true, we will only allow package files that exactly match the DTD. Otherwise, we
224      * try to get as much from the package as we can without failing. This should normally be set to
225      * false, to support extensions to the DTD in future versions.
226      */
227     public static final boolean RIGID_PARSER = false;
228 
229     public static final int PARSE_MUST_BE_APK = 1 << 0;
230     public static final int PARSE_IGNORE_PROCESSES = 1 << 1;
231     public static final int PARSE_EXTERNAL_STORAGE = 1 << 3;
232     public static final int PARSE_IS_SYSTEM_DIR = 1 << 4;
233     public static final int PARSE_COLLECT_CERTIFICATES = 1 << 5;
234     public static final int PARSE_ENFORCE_CODE = 1 << 6;
235     /**
236      * This flag is applied in the ApkLiteParser. Used by OverlayConfigParser to ignore the checks
237      * of required system property within the overlay tag.
238      */
239     public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7;
240     public static final int PARSE_FRAMEWORK_RES_SPLITS = 1 << 8;
241     public static final int PARSE_APK_IN_APEX = 1 << 9;
242 
243     public static final int PARSE_CHATTY = 1 << 31;
244 
245     /** The total maximum number of activities, services, providers and activity-aliases */
246     private static final int MAX_NUM_COMPONENTS = 30000;
247     private static final String MAX_NUM_COMPONENTS_ERR_MSG =
248             "Total number of components has exceeded the maximum number: " + MAX_NUM_COMPONENTS;
249 
250     /** The maximum permission name length. */
251     private static final int MAX_PERMISSION_NAME_LENGTH = 512;
252 
253     @IntDef(flag = true, prefix = { "PARSE_" }, value = {
254             PARSE_CHATTY,
255             PARSE_COLLECT_CERTIFICATES,
256             PARSE_ENFORCE_CODE,
257             PARSE_EXTERNAL_STORAGE,
258             PARSE_IGNORE_PROCESSES,
259             PARSE_IS_SYSTEM_DIR,
260             PARSE_MUST_BE_APK,
261             PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY,
262             PARSE_FRAMEWORK_RES_SPLITS
263     })
264     @Retention(RetentionPolicy.SOURCE)
265     public @interface ParseFlags {}
266 
267     /**
268      * @see #parseDefault(ParseInput, File, int, List, boolean)
269      */
270     @NonNull
parseDefaultOneTime(File file, @ParseFlags int parseFlags, @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions, boolean collectCertificates)271     public static ParseResult<ParsingPackage> parseDefaultOneTime(File file,
272             @ParseFlags int parseFlags,
273             @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
274             boolean collectCertificates) {
275         ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
276         return parseDefault(input, file, parseFlags, splitPermissions, collectCertificates);
277     }
278 
279     /**
280      * For cases outside of PackageManagerService when an APK needs to be parsed as a one-off
281      * request, without caching the input object and without querying the internal system state for
282      * feature support.
283      */
284     @NonNull
parseDefault(ParseInput input, File file, @ParseFlags int parseFlags, @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions, boolean collectCertificates)285     public static ParseResult<ParsingPackage> parseDefault(ParseInput input, File file,
286             @ParseFlags int parseFlags,
287             @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
288             boolean collectCertificates) {
289         ParseResult<ParsingPackage> result;
290 
291         ParsingPackageUtils parser = new ParsingPackageUtils(false, null /*separateProcesses*/,
292                 null /*displayMetrics*/, splitPermissions, new Callback() {
293             @Override
294             public boolean hasFeature(String feature) {
295                 // Assume the device doesn't support anything. This will affect permission
296                 // parsing and will force <uses-permission/> declarations to include all
297                 // requiredNotFeature permissions and exclude all requiredFeature
298                 // permissions. This mirrors the old behavior.
299                 return false;
300             }
301 
302             @Override
303             public ParsingPackage startParsingPackage(
304                     @NonNull String packageName,
305                     @NonNull String baseApkPath,
306                     @NonNull String path,
307                     @NonNull TypedArray manifestArray, boolean isCoreApp) {
308                 return new ParsingPackageImpl(packageName, baseApkPath, path, manifestArray);
309             }
310         });
311         result = parser.parsePackage(input, file, parseFlags, /* frameworkSplits= */ null);
312         if (result.isError()) {
313             return input.error(result);
314         }
315 
316         final ParsingPackage pkg = result.getResult();
317         if (collectCertificates) {
318             final ParseResult<SigningDetails> ret =
319                     ParsingPackageUtils.getSigningDetails(input, pkg, false /*skipVerify*/);
320             if (ret.isError()) {
321                 return input.error(ret);
322             }
323             pkg.setSigningDetails(ret.getResult());
324         }
325 
326         // Need to call this to finish the parsing stage
327         pkg.hideAsParsed();
328 
329         return input.success(pkg);
330     }
331 
332     private boolean mOnlyCoreApps;
333     private String[] mSeparateProcesses;
334     private DisplayMetrics mDisplayMetrics;
335     @NonNull
336     private List<PermissionManager.SplitPermissionInfo> mSplitPermissionInfos;
337     private Callback mCallback;
338 
ParsingPackageUtils(boolean onlyCoreApps, String[] separateProcesses, DisplayMetrics displayMetrics, @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions, @NonNull Callback callback)339     public ParsingPackageUtils(boolean onlyCoreApps, String[] separateProcesses,
340             DisplayMetrics displayMetrics,
341             @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
342             @NonNull Callback callback) {
343         mOnlyCoreApps = onlyCoreApps;
344         mSeparateProcesses = separateProcesses;
345         mDisplayMetrics = displayMetrics;
346         mSplitPermissionInfos = splitPermissions;
347         mCallback = callback;
348     }
349 
350     /**
351      * Parse the package at the given location. Automatically detects if the package is a monolithic
352      * style (single APK file) or cluster style (directory of APKs).
353      * <p>
354      * This performs validity checking on cluster style packages, such as requiring identical
355      * package name and version codes, a single base APK, and unique split names.
356      * <p>
357      * Note that this <em>does not</em> perform signature verification; that must be done separately
358      * in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
359      * <p>
360      * If {@code useCaches} is true, the package parser might return a cached result from a previous
361      * parse of the same {@code packageFile} with the same {@code flags}. Note that this method does
362      * not check whether {@code packageFile} has changed since the last parse, it's up to callers to
363      * do so.
364      */
parsePackage(ParseInput input, File packageFile, int flags, List<File> frameworkSplits)365     public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags,
366             List<File> frameworkSplits) {
367         if (((flags & PARSE_FRAMEWORK_RES_SPLITS) != 0)
368                 && frameworkSplits.size() > 0
369                 && packageFile.getAbsolutePath().endsWith("/framework-res.apk")) {
370             return parseClusterPackage(input, packageFile, frameworkSplits, flags);
371         } else if (packageFile.isDirectory()) {
372             return parseClusterPackage(input, packageFile, /* frameworkSplits= */null, flags);
373         } else {
374             return parseMonolithicPackage(input, packageFile, flags);
375         }
376     }
377 
378     /**
379      * Parse all APKs contained in the given directory, treating them as a
380      * single package. This also performs validity checking, such as requiring
381      * identical package name and version codes, a single base APK, and unique
382      * split names.
383      * <p>
384      * Can also be passed the framework-res.apk file and a list of split apks coming from apexes
385      * (via {@code frameworkSplits}) in which case they will be parsed similar to cluster packages
386      * even if they are in different folders. Note that this code path may have other behaviour
387      * differences.
388      * <p>
389      * Note that this <em>does not</em> perform signature verification; that must be done separately
390      * in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
391      */
parseClusterPackage(ParseInput input, File packageDir, List<File> frameworkSplits, int flags)392     private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
393             List<File> frameworkSplits, int flags) {
394         // parseClusterPackageLite should receive no flags (0) for regular splits but we want to
395         // pass the flags for framework splits
396         int liteParseFlags = 0;
397         if ((flags & PARSE_FRAMEWORK_RES_SPLITS) != 0) {
398             liteParseFlags = flags;
399         }
400         if ((flags & PARSE_APK_IN_APEX) != 0) {
401             liteParseFlags |= PARSE_APK_IN_APEX;
402         }
403         final ParseResult<PackageLite> liteResult =
404                 ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, frameworkSplits,
405                         liteParseFlags);
406         if (liteResult.isError()) {
407             return input.error(liteResult);
408         }
409 
410         final PackageLite lite = liteResult.getResult();
411         if (mOnlyCoreApps && !lite.isCoreApp()) {
412             return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
413                     "Not a coreApp: " + packageDir);
414         }
415 
416         // Build the split dependency tree.
417         SparseArray<int[]> splitDependencies = null;
418         final SplitAssetLoader assetLoader;
419         if (lite.isIsolatedSplits() && !ArrayUtils.isEmpty(lite.getSplitNames())) {
420             try {
421                 splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
422                 assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
423             } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
424                 return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
425             }
426         } else {
427             assetLoader = new DefaultSplitAssetLoader(lite, flags);
428         }
429 
430         try {
431             final File baseApk = new File(lite.getBaseApkPath());
432             final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
433                     lite.getPath(), assetLoader, flags);
434             if (result.isError()) {
435                 return input.error(result);
436             }
437 
438             ParsingPackage pkg = result.getResult();
439             if (!ArrayUtils.isEmpty(lite.getSplitNames())) {
440                 pkg.asSplit(
441                         lite.getSplitNames(),
442                         lite.getSplitApkPaths(),
443                         lite.getSplitRevisionCodes(),
444                         splitDependencies
445                 );
446                 final int num = lite.getSplitNames().length;
447 
448                 for (int i = 0; i < num; i++) {
449                     final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
450                     final ParseResult<ParsingPackage> split =
451                             parseSplitApk(input, pkg, i, splitAssets, flags);
452                     if (split.isError()) {
453                         return input.error(split);
454                     }
455                 }
456             }
457 
458             pkg.setUse32BitAbi(lite.isUse32bitAbi());
459             return input.success(pkg);
460         } catch (IllegalArgumentException e) {
461             return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK
462                     : INSTALL_PARSE_FAILED_NOT_APK, e.getMessage(), e);
463         } finally {
464             IoUtils.closeQuietly(assetLoader);
465         }
466     }
467 
468     /**
469      * Parse the given APK file, treating it as as a single monolithic package.
470      * <p>
471      * Note that this <em>does not</em> perform signature verification; that must be done separately
472      * in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
473      */
parseMonolithicPackage(ParseInput input, File apkFile, int flags)474     private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
475             int flags) {
476         final ParseResult<PackageLite> liteResult =
477                 ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
478         if (liteResult.isError()) {
479             return input.error(liteResult);
480         }
481 
482         final PackageLite lite = liteResult.getResult();
483         if (mOnlyCoreApps && !lite.isCoreApp()) {
484             return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
485                     "Not a coreApp: " + apkFile);
486         }
487 
488         final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
489         try {
490             final ParseResult<ParsingPackage> result = parseBaseApk(input,
491                     apkFile,
492                     apkFile.getCanonicalPath(),
493                     assetLoader, flags);
494             if (result.isError()) {
495                 return input.error(result);
496             }
497 
498             return input.success(result.getResult()
499                     .setUse32BitAbi(lite.isUse32bitAbi()));
500         } catch (IOException e) {
501             return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
502                     "Failed to get path: " + apkFile, e);
503         } finally {
504             IoUtils.closeQuietly(assetLoader);
505         }
506     }
507 
parseBaseApk(ParseInput input, File apkFile, String codePath, SplitAssetLoader assetLoader, int flags)508     private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
509             String codePath, SplitAssetLoader assetLoader, int flags) {
510         final String apkPath = apkFile.getAbsolutePath();
511 
512         String volumeUuid = null;
513         if (apkPath.startsWith(MNT_EXPAND)) {
514             final int end = apkPath.indexOf('/', MNT_EXPAND.length());
515             volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
516         }
517 
518         if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
519 
520         final AssetManager assets;
521         try {
522             assets = assetLoader.getBaseAssetManager();
523         } catch (IllegalArgumentException e) {
524             return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK
525                     : INSTALL_PARSE_FAILED_NOT_APK, e.getMessage(), e);
526         }
527         final int cookie = assets.findCookieForPath(apkPath);
528         if (cookie == 0) {
529             return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
530                     "Failed adding asset path: " + apkPath);
531         }
532 
533         try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
534                 ANDROID_MANIFEST_FILENAME)) {
535             final Resources res = new Resources(assets, mDisplayMetrics, null);
536 
537             ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
538                     parser, flags);
539             if (result.isError()) {
540                 return input.error(result.getErrorCode(),
541                         apkPath + " (at " + parser.getPositionDescription() + "): "
542                                 + result.getErrorMessage());
543             }
544 
545             final ParsingPackage pkg = result.getResult();
546             if (assets.containsAllocatedTable()) {
547                 final ParseResult<?> deferResult = input.deferError(
548                         "Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires"
549                                 + " the resources.arsc of installed APKs to be stored uncompressed"
550                                 + " and aligned on a 4-byte boundary",
551                         DeferredError.RESOURCES_ARSC_COMPRESSED);
552                 if (deferResult.isError()) {
553                     return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,
554                             deferResult.getErrorMessage());
555                 }
556             }
557 
558             ApkAssets apkAssets = assetLoader.getBaseApkAssets();
559             boolean definesOverlayable = false;
560             try {
561                 definesOverlayable = apkAssets.definesOverlayable();
562             } catch (IOException ignored) {
563                 // Will fail if there's no packages in the ApkAssets, which can be treated as false
564             }
565 
566             if (definesOverlayable) {
567                 SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
568                 int size = packageNames.size();
569                 for (int index = 0; index < size; index++) {
570                     String packageName = packageNames.valueAt(index);
571                     Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
572                     if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
573                         for (String overlayable : overlayableToActor.keySet()) {
574                             pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
575                         }
576                     }
577                 }
578             }
579 
580             pkg.setVolumeUuid(volumeUuid);
581 
582             if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
583                 final ParseResult<SigningDetails> ret =
584                         getSigningDetails(input, pkg, false /*skipVerify*/);
585                 if (ret.isError()) {
586                     return input.error(ret);
587                 }
588                 pkg.setSigningDetails(ret.getResult());
589             } else {
590                 pkg.setSigningDetails(SigningDetails.UNKNOWN);
591             }
592 
593             return input.success(pkg);
594         } catch (Exception e) {
595             return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
596                     "Failed to read manifest from " + apkPath, e);
597         }
598     }
599 
parseSplitApk(ParseInput input, ParsingPackage pkg, int splitIndex, AssetManager assets, int flags)600     private ParseResult<ParsingPackage> parseSplitApk(ParseInput input,
601             ParsingPackage pkg, int splitIndex, AssetManager assets, int flags) {
602         final String apkPath = pkg.getSplitCodePaths()[splitIndex];
603 
604         if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
605 
606         // This must always succeed, as the path has been added to the AssetManager before.
607         final int cookie = assets.findCookieForPath(apkPath);
608         if (cookie == 0) {
609             return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
610                     "Failed adding asset path: " + apkPath);
611         }
612         try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
613                 ANDROID_MANIFEST_FILENAME)) {
614             Resources res = new Resources(assets, mDisplayMetrics, null);
615             ParseResult<ParsingPackage> parseResult = parseSplitApk(input, pkg, res,
616                     parser, flags, splitIndex);
617             if (parseResult.isError()) {
618                 return input.error(parseResult.getErrorCode(),
619                         apkPath + " (at " + parser.getPositionDescription() + "): "
620                                 + parseResult.getErrorMessage());
621             }
622 
623             return parseResult;
624         } catch (Exception e) {
625             return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
626                     "Failed to read manifest from " + apkPath, e);
627         }
628     }
629 
630     /**
631      * Parse the manifest of a <em>base APK</em>. When adding new features you need to consider
632      * whether they should be supported by split APKs and child packages.
633      *
634      * @param apkPath The package apk file path
635      * @param res     The resources from which to resolve values
636      * @param parser  The manifest parser
637      * @param flags   Flags how to parse
638      * @return Parsed package or null on error.
639      */
parseBaseApk(ParseInput input, String apkPath, String codePath, Resources res, XmlResourceParser parser, int flags)640     private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
641             String codePath, Resources res, XmlResourceParser parser, int flags)
642             throws XmlPullParserException, IOException {
643         final String splitName;
644         final String pkgName;
645 
646         ParseResult<Pair<String, String>> packageSplitResult =
647                 ApkLiteParseUtils.parsePackageSplitNames(input, parser);
648         if (packageSplitResult.isError()) {
649             return input.error(packageSplitResult);
650         }
651 
652         Pair<String, String> packageSplit = packageSplitResult.getResult();
653         pkgName = packageSplit.first;
654         splitName = packageSplit.second;
655 
656         if (!TextUtils.isEmpty(splitName)) {
657             return input.error(
658                     PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
659                     "Expected base APK, but found split " + splitName
660             );
661         }
662 
663         final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
664         try {
665             final boolean isCoreApp = parser.getAttributeBooleanValue(null /*namespace*/,
666                     "coreApp",false);
667             final ParsingPackage pkg = mCallback.startParsingPackage(
668                     pkgName, apkPath, codePath, manifestArray, isCoreApp);
669             final ParseResult<ParsingPackage> result =
670                     parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
671             if (result.isError()) {
672                 return result;
673             }
674 
675             return input.success(pkg);
676         } finally {
677             manifestArray.recycle();
678         }
679     }
680 
681     /**
682      * Parse the manifest of a <em>split APK</em>.
683      * <p>
684      * Note that split APKs have many more restrictions on what they're capable of doing, so many
685      * valid features of a base APK have been carefully omitted here.
686      *
687      * @param pkg builder to fill
688      * @return false on failure
689      */
parseSplitApk(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, int splitIndex)690     private ParseResult<ParsingPackage> parseSplitApk(ParseInput input, ParsingPackage pkg,
691             Resources res, XmlResourceParser parser, int flags, int splitIndex)
692             throws XmlPullParserException, IOException {
693         // We parsed manifest tag earlier; just skip past it
694         final ParseResult<Pair<String, String>> packageSplitResult =
695                 ApkLiteParseUtils.parsePackageSplitNames(input, parser);
696         if (packageSplitResult.isError()) {
697             return input.error(packageSplitResult);
698         }
699 
700         int type;
701 
702         boolean foundApp = false;
703 
704         int outerDepth = parser.getDepth();
705         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
706             if (outerDepth + 1 < parser.getDepth() || type != XmlPullParser.START_TAG) {
707                 continue;
708             }
709 
710             final ParseResult result;
711             String tagName = parser.getName();
712             if (TAG_APPLICATION.equals(tagName)) {
713                 if (foundApp) {
714                     if (RIGID_PARSER) {
715                         result = input.error("<manifest> has more than one <application>");
716                     } else {
717                         Slog.w(TAG, "<manifest> has more than one <application>");
718                         result = input.success(null);
719                     }
720                 } else {
721                     foundApp = true;
722                     result = parseSplitApplication(input, pkg, res, parser, flags, splitIndex);
723                 }
724             } else {
725                 result = ParsingUtils.unknownTag("<manifest>", pkg, parser, input);
726             }
727 
728             if (result.isError()) {
729                 return input.error(result);
730             }
731         }
732 
733         if (!foundApp) {
734             ParseResult<?> deferResult = input.deferError(
735                     "<manifest> does not contain an <application>", DeferredError.MISSING_APP_TAG);
736             if (deferResult.isError()) {
737                 return input.error(deferResult);
738             }
739         }
740 
741         return input.success(pkg);
742     }
743 
744     /**
745      * Parse the {@code application} XML tree at the current parse location in a
746      * <em>split APK</em> manifest.
747      * <p>
748      * Note that split APKs have many more restrictions on what they're capable of doing, so many
749      * valid features of a base APK have been carefully omitted here.
750      */
parseSplitApplication(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, int splitIndex)751     private ParseResult<ParsingPackage> parseSplitApplication(ParseInput input,
752             ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, int splitIndex)
753             throws XmlPullParserException, IOException {
754         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
755         try {
756             pkg.setSplitHasCode(splitIndex, sa.getBoolean(
757                     R.styleable.AndroidManifestApplication_hasCode, true));
758 
759             final String classLoaderName = sa.getString(
760                     R.styleable.AndroidManifestApplication_classLoader);
761             if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(
762                     classLoaderName)) {
763                 pkg.setSplitClassLoaderName(splitIndex, classLoaderName);
764             } else {
765                 return input.error("Invalid class loader name: " + classLoaderName);
766             }
767         } finally {
768             sa.recycle();
769         }
770 
771         // If the loaded component did not specify a split, inherit the split name
772         // based on the split it is defined in.
773         // This is used to later load the correct split when starting this
774         // component.
775         String defaultSplitName = pkg.getSplitNames()[splitIndex];
776 
777         final int depth = parser.getDepth();
778         int type;
779         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
780                 && (type != XmlPullParser.END_TAG
781                 || parser.getDepth() > depth)) {
782             if (type != XmlPullParser.START_TAG) {
783                 continue;
784             }
785 
786             ParsedMainComponent mainComponent = null;
787 
788             final ParseResult result;
789             String tagName = parser.getName();
790             boolean isActivity = false;
791             switch (tagName) {
792                 case "activity":
793                     isActivity = true;
794                     // fall-through
795                 case "receiver":
796                     ParseResult<ParsedActivity> activityResult =
797                             ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
798                                     res, parser, flags, sUseRoundIcon, defaultSplitName, input);
799                     if (activityResult.isSuccess()) {
800                         ParsedActivity activity = activityResult.getResult();
801                         if (isActivity) {
802                             pkg.addActivity(activity);
803                         } else {
804                             pkg.addReceiver(activity);
805                         }
806                         mainComponent = activity;
807                     }
808                     result = activityResult;
809                     break;
810                 case "service":
811                     ParseResult<ParsedService> serviceResult = ParsedServiceUtils.parseService(
812                             mSeparateProcesses, pkg, res, parser, flags, sUseRoundIcon,
813                             defaultSplitName, input);
814                     if (serviceResult.isSuccess()) {
815                         ParsedService service = serviceResult.getResult();
816                         pkg.addService(service);
817                         mainComponent = service;
818                     }
819                     result = serviceResult;
820                     break;
821                 case "provider":
822                     ParseResult<ParsedProvider> providerResult =
823                             ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
824                                     flags, sUseRoundIcon, defaultSplitName, input);
825                     if (providerResult.isSuccess()) {
826                         ParsedProvider provider = providerResult.getResult();
827                         pkg.addProvider(provider);
828                         mainComponent = provider;
829                     }
830                     result = providerResult;
831                     break;
832                 case "activity-alias":
833                     activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res, parser,
834                             sUseRoundIcon, defaultSplitName, input);
835                     if (activityResult.isSuccess()) {
836                         ParsedActivity activity = activityResult.getResult();
837                         pkg.addActivity(activity);
838                         mainComponent = activity;
839                     }
840 
841                     result = activityResult;
842                     break;
843                 default:
844                     result = parseSplitBaseAppChildTags(input, tagName, pkg, res, parser);
845                     break;
846             }
847 
848             if (result.isError()) {
849                 return input.error(result);
850             }
851 
852             if (hasTooManyComponents(pkg)) {
853                 return input.error(MAX_NUM_COMPONENTS_ERR_MSG);
854             }
855         }
856 
857         return input.success(pkg);
858     }
859 
hasTooManyComponents(ParsingPackage pkg)860     private static boolean hasTooManyComponents(ParsingPackage pkg) {
861         return pkg.getActivities().size() + pkg.getServices().size() + pkg.getProviders().size()
862                 > MAX_NUM_COMPONENTS;
863     }
864 
865     /**
866      * For parsing non-MainComponents. Main ones have an order and some special handling which is
867      * done directly in {@link #parseSplitApplication(ParseInput, ParsingPackage, Resources,
868      * XmlResourceParser, int, int)}.
869      */
parseSplitBaseAppChildTags(ParseInput input, String tag, ParsingPackage pkg, Resources res, XmlResourceParser parser)870     private ParseResult parseSplitBaseAppChildTags(ParseInput input, String tag, ParsingPackage pkg,
871             Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException {
872         switch (tag) {
873             case "meta-data":
874                 // note: application meta-data is stored off to the side, so it can
875                 // remain null in the primary copy (we like to avoid extra copies because
876                 // it can be large)
877                 ParseResult<Property> metaDataResult = parseMetaData(pkg, null /*component*/,
878                         res, parser, "<meta-data>", input);
879                 if (metaDataResult.isSuccess() && metaDataResult.getResult() != null) {
880                     pkg.setMetaData(metaDataResult.getResult().toBundle(pkg.getMetaData()));
881                 }
882                 return metaDataResult;
883             case "property":
884                 ParseResult<Property> propertyResult = parseMetaData(pkg, null /*component*/,
885                         res, parser, "<property>", input);
886                 if (propertyResult.isSuccess()) {
887                     pkg.addProperty(propertyResult.getResult());
888                 }
889                 return propertyResult;
890             case "uses-sdk-library":
891                 return parseUsesSdkLibrary(input, pkg, res, parser);
892             case "uses-static-library":
893                 return parseUsesStaticLibrary(input, pkg, res, parser);
894             case "uses-library":
895                 return parseUsesLibrary(input, pkg, res, parser);
896             case "uses-native-library":
897                 return parseUsesNativeLibrary(input, pkg, res, parser);
898             case "uses-package":
899                 // Dependencies for app installers; we don't currently try to
900                 // enforce this.
901                 return input.success(null);
902             default:
903                 return ParsingUtils.unknownTag("<application>", pkg, parser, input);
904         }
905     }
906 
parseBaseApkTags(ParseInput input, ParsingPackage pkg, TypedArray sa, Resources res, XmlResourceParser parser, int flags)907     private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
908             TypedArray sa, Resources res, XmlResourceParser parser, int flags)
909             throws XmlPullParserException, IOException {
910         ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);
911         if (sharedUserResult.isError()) {
912             return sharedUserResult;
913         }
914 
915         pkg.setInstallLocation(anInteger(PARSE_DEFAULT_INSTALL_LOCATION,
916                 R.styleable.AndroidManifest_installLocation, sa))
917                 .setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX,
918                         R.styleable.AndroidManifest_targetSandboxVersion, sa))
919                 /* Set the global "on SD card" flag */
920                 .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0);
921 
922         boolean foundApp = false;
923         final int depth = parser.getDepth();
924         int type;
925         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
926                 && (type != XmlPullParser.END_TAG
927                 || parser.getDepth() > depth)) {
928             if (type != XmlPullParser.START_TAG) {
929                 continue;
930             }
931 
932             String tagName = parser.getName();
933             final ParseResult result;
934 
935             // <application> has special logic, so it's handled outside the general method
936             if (TAG_APPLICATION.equals(tagName)) {
937                 if (foundApp) {
938                     if (RIGID_PARSER) {
939                         result = input.error("<manifest> has more than one <application>");
940                     } else {
941                         Slog.w(TAG, "<manifest> has more than one <application>");
942                         result = input.success(null);
943                     }
944                 } else {
945                     foundApp = true;
946                     result = parseBaseApplication(input, pkg, res, parser, flags);
947                 }
948             } else {
949                 result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
950             }
951 
952             if (result.isError()) {
953                 return input.error(result);
954             }
955         }
956 
957         if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) {
958             ParseResult<?> deferResult = input.deferError(
959                     "<manifest> does not contain an <application> or <instrumentation>",
960                     DeferredError.MISSING_APP_TAG);
961             if (deferResult.isError()) {
962                 return input.error(deferResult);
963             }
964         }
965 
966         if (!ParsedAttributionUtils.isCombinationValid(pkg.getAttributions())) {
967             return input.error(
968                     INSTALL_PARSE_FAILED_BAD_MANIFEST,
969                     "Combination <attribution> tags are not valid"
970             );
971         }
972 
973         if (ParsedPermissionUtils.declareDuplicatePermission(pkg)) {
974             return input.error(
975                     INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
976                     "Found duplicate permission with a different attribute value."
977             );
978         }
979 
980         convertCompatPermissions(pkg);
981 
982         convertSplitPermissions(pkg);
983 
984         // At this point we can check if an application is not supporting densities and hence
985         // cannot be windowed / resized. Note that an SDK version of 0 is common for
986         // pre-Doughnut applications.
987         if (pkg.getTargetSdkVersion() < DONUT
988                 || (!pkg.isSupportsSmallScreens()
989                 && !pkg.isSupportsNormalScreens()
990                 && !pkg.isSupportsLargeScreens()
991                 && !pkg.isSupportsExtraLargeScreens()
992                 && !pkg.isResizeable()
993                 && !pkg.isAnyDensity())) {
994             adjustPackageToBeUnresizeableAndUnpipable(pkg);
995         }
996 
997         return input.success(pkg);
998     }
999 
parseBaseApkTag(String tag, ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)1000     private ParseResult parseBaseApkTag(String tag, ParseInput input,
1001             ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
1002             throws IOException, XmlPullParserException {
1003         switch (tag) {
1004             case TAG_OVERLAY:
1005                 return parseOverlay(input, pkg, res, parser);
1006             case TAG_KEY_SETS:
1007                 return parseKeySets(input, pkg, res, parser);
1008             case "feature": // TODO moltmann: Remove
1009             case TAG_ATTRIBUTION:
1010                 return parseAttribution(input, pkg, res, parser);
1011             case TAG_PERMISSION_GROUP:
1012                 return parsePermissionGroup(input, pkg, res, parser);
1013             case TAG_PERMISSION:
1014                 return parsePermission(input, pkg, res, parser);
1015             case TAG_PERMISSION_TREE:
1016                 return parsePermissionTree(input, pkg, res, parser);
1017             case TAG_USES_PERMISSION:
1018             case TAG_USES_PERMISSION_SDK_M:
1019             case TAG_USES_PERMISSION_SDK_23:
1020                 return parseUsesPermission(input, pkg, res, parser);
1021             case TAG_USES_CONFIGURATION:
1022                 return parseUsesConfiguration(input, pkg, res, parser);
1023             case TAG_USES_FEATURE:
1024                 return parseUsesFeature(input, pkg, res, parser);
1025             case TAG_FEATURE_GROUP:
1026                 return parseFeatureGroup(input, pkg, res, parser);
1027             case TAG_USES_SDK:
1028                 return parseUsesSdk(input, pkg, res, parser, flags);
1029             case TAG_SUPPORT_SCREENS:
1030                 return parseSupportScreens(input, pkg, res, parser);
1031             case TAG_PROTECTED_BROADCAST:
1032                 return parseProtectedBroadcast(input, pkg, res, parser);
1033             case TAG_INSTRUMENTATION:
1034                 return parseInstrumentation(input, pkg, res, parser);
1035             case TAG_ORIGINAL_PACKAGE:
1036                 return parseOriginalPackage(input, pkg, res, parser);
1037             case TAG_ADOPT_PERMISSIONS:
1038                 return parseAdoptPermissions(input, pkg, res, parser);
1039             case TAG_USES_GL_TEXTURE:
1040             case TAG_COMPATIBLE_SCREENS:
1041             case TAG_SUPPORTS_INPUT:
1042             case TAG_EAT_COMMENT:
1043                 // Just skip this tag
1044                 XmlUtils.skipCurrentTag(parser);
1045                 return input.success(pkg);
1046             case TAG_RESTRICT_UPDATE:
1047                 return parseRestrictUpdateHash(flags, input, pkg, res, parser);
1048             case TAG_INSTALL_CONSTRAINTS:
1049                 return parseInstallConstraints(input, pkg, res, parser);
1050             case TAG_QUERIES:
1051                 return parseQueries(input, pkg, res, parser);
1052             default:
1053                 return ParsingUtils.unknownTag("<manifest>", pkg, parser, input);
1054         }
1055     }
1056 
parseSharedUser(ParseInput input, ParsingPackage pkg, TypedArray sa)1057     private static ParseResult<ParsingPackage> parseSharedUser(ParseInput input,
1058             ParsingPackage pkg, TypedArray sa) {
1059         String str = nonConfigString(0, R.styleable.AndroidManifest_sharedUserId, sa);
1060         if (TextUtils.isEmpty(str)) {
1061             return input.success(pkg);
1062         }
1063 
1064         if (!"android".equals(pkg.getPackageName())) {
1065             ParseResult<?> nameResult = FrameworkParsingPackageUtils.validateName(input, str,
1066                     true, true);
1067             if (nameResult.isError()) {
1068                 return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
1069                         "<manifest> specifies bad sharedUserId name \"" + str + "\": "
1070                                 + nameResult.getErrorMessage());
1071             }
1072         }
1073 
1074         boolean leaving = false;
1075         if (!SharedUidMigration.isDisabled()) {
1076             int max = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa);
1077             leaving = (max != 0) && (max < Build.VERSION.RESOURCES_SDK_INT);
1078         }
1079 
1080         return input.success(pkg
1081                 .setLeavingSharedUid(leaving)
1082                 .setSharedUserId(str.intern())
1083                 .setSharedUserLabel(resId(R.styleable.AndroidManifest_sharedUserLabel, sa)));
1084     }
1085 
parseKeySets(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1086     private static ParseResult<ParsingPackage> parseKeySets(ParseInput input,
1087             ParsingPackage pkg, Resources res, XmlResourceParser parser)
1088             throws XmlPullParserException, IOException {
1089         // we've encountered the 'key-sets' tag
1090         // all the keys and keysets that we want must be defined here
1091         // so we're going to iterate over the parser and pull out the things we want
1092         int outerDepth = parser.getDepth();
1093         int currentKeySetDepth = -1;
1094         int type;
1095         String currentKeySet = null;
1096         ArrayMap<String, PublicKey> publicKeys = new ArrayMap<>();
1097         ArraySet<String> upgradeKeySets = new ArraySet<>();
1098         ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<>();
1099         ArraySet<String> improperKeySets = new ArraySet<>();
1100         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1101                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1102             if (type == XmlPullParser.END_TAG) {
1103                 if (parser.getDepth() == currentKeySetDepth) {
1104                     currentKeySet = null;
1105                     currentKeySetDepth = -1;
1106                 }
1107                 continue;
1108             }
1109             String tagName = parser.getName();
1110             switch (tagName) {
1111                 case "key-set": {
1112                     if (currentKeySet != null) {
1113                         return input.error("Improperly nested 'key-set' tag at "
1114                                 + parser.getPositionDescription());
1115                     }
1116                     TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestKeySet);
1117                     try {
1118                         final String keysetName = sa.getNonResourceString(
1119                                 R.styleable.AndroidManifestKeySet_name);
1120                         definedKeySets.put(keysetName, new ArraySet<>());
1121                         currentKeySet = keysetName;
1122                         currentKeySetDepth = parser.getDepth();
1123                     } finally {
1124                         sa.recycle();
1125                     }
1126                 } break;
1127                 case "public-key": {
1128                     if (currentKeySet == null) {
1129                         return input.error("Improperly nested 'key-set' tag at "
1130                                 + parser.getPositionDescription());
1131                     }
1132                     TypedArray sa = res.obtainAttributes(parser,
1133                             R.styleable.AndroidManifestPublicKey);
1134                     try {
1135                         final String publicKeyName = nonResString(
1136                                 R.styleable.AndroidManifestPublicKey_name, sa);
1137                         final String encodedKey = nonResString(
1138                                 R.styleable.AndroidManifestPublicKey_value, sa);
1139                         if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
1140                             return input.error("'public-key' " + publicKeyName
1141                                     + " must define a public-key value on first use at "
1142                                     + parser.getPositionDescription());
1143                         } else if (encodedKey != null) {
1144                             PublicKey currentKey =
1145                                     FrameworkParsingPackageUtils.parsePublicKey(encodedKey);
1146                             if (currentKey == null) {
1147                                 Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
1148                                         + parser.getPositionDescription() + " key-set "
1149                                         + currentKeySet
1150                                         + " will not be added to the package's defined key-sets.");
1151                                 improperKeySets.add(currentKeySet);
1152                                 XmlUtils.skipCurrentTag(parser);
1153                                 continue;
1154                             }
1155                             if (publicKeys.get(publicKeyName) == null
1156                                     || publicKeys.get(publicKeyName).equals(currentKey)) {
1157 
1158                                 /* public-key first definition, or matches old definition */
1159                                 publicKeys.put(publicKeyName, currentKey);
1160                             } else {
1161                                 return input.error("Value of 'public-key' " + publicKeyName
1162                                         + " conflicts with previously defined value at "
1163                                         + parser.getPositionDescription());
1164                             }
1165                         }
1166                         definedKeySets.get(currentKeySet).add(publicKeyName);
1167                         XmlUtils.skipCurrentTag(parser);
1168                     } finally {
1169                         sa.recycle();
1170                     }
1171                 } break;
1172                 case "upgrade-key-set": {
1173                     TypedArray sa = res.obtainAttributes(parser,
1174                             R.styleable.AndroidManifestUpgradeKeySet);
1175                     try {
1176                         String name = sa.getNonResourceString(
1177                                 R.styleable.AndroidManifestUpgradeKeySet_name);
1178                         upgradeKeySets.add(name);
1179                         XmlUtils.skipCurrentTag(parser);
1180                     } finally {
1181                         sa.recycle();
1182                     }
1183                 } break;
1184                 default:
1185                     ParseResult result = ParsingUtils.unknownTag("<key-sets>", pkg, parser,
1186                             input);
1187                     if (result.isError()) {
1188                         return input.error(result);
1189                     }
1190                     break;
1191             }
1192         }
1193         String packageName = pkg.getPackageName();
1194         Set<String> publicKeyNames = publicKeys.keySet();
1195         if (publicKeyNames.removeAll(definedKeySets.keySet())) {
1196             return input.error("Package" + packageName
1197                     + " AndroidManifest.xml 'key-set' and 'public-key' names must be distinct.");
1198         }
1199 
1200         for (ArrayMap.Entry<String, ArraySet<String>> e : definedKeySets.entrySet()) {
1201             final String keySetName = e.getKey();
1202             if (e.getValue().size() == 0) {
1203                 Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml "
1204                         + "'key-set' " + keySetName + " has no valid associated 'public-key'."
1205                         + " Not including in package's defined key-sets.");
1206                 continue;
1207             } else if (improperKeySets.contains(keySetName)) {
1208                 Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml "
1209                         + "'key-set' " + keySetName + " contained improper 'public-key'"
1210                         + " tags. Not including in package's defined key-sets.");
1211                 continue;
1212             }
1213 
1214             for (String s : e.getValue()) {
1215                 pkg.addKeySet(keySetName, publicKeys.get(s));
1216             }
1217         }
1218         if (pkg.getKeySetMapping().keySet().containsAll(upgradeKeySets)) {
1219             pkg.setUpgradeKeySets(upgradeKeySets);
1220         } else {
1221             return input.error("Package" + packageName
1222                     + " AndroidManifest.xml does not define all 'upgrade-key-set's .");
1223         }
1224 
1225         return input.success(pkg);
1226     }
1227 
parseAttribution(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1228     private static ParseResult<ParsingPackage> parseAttribution(ParseInput input,
1229             ParsingPackage pkg, Resources res, XmlResourceParser parser)
1230             throws IOException, XmlPullParserException {
1231         ParseResult<ParsedAttribution> result = ParsedAttributionUtils.parseAttribution(res,
1232                 parser, input);
1233         if (result.isError()) {
1234             return input.error(result);
1235         }
1236         return input.success(pkg.addAttribution(result.getResult()));
1237     }
1238 
parsePermissionGroup(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1239     private static ParseResult<ParsingPackage> parsePermissionGroup(ParseInput input,
1240             ParsingPackage pkg, Resources res, XmlResourceParser parser)
1241             throws XmlPullParserException, IOException {
1242         ParseResult<ParsedPermissionGroup> result = ParsedPermissionUtils.parsePermissionGroup(
1243                 pkg, res, parser, sUseRoundIcon, input);
1244         if (result.isError()) {
1245             return input.error(result);
1246         }
1247         return input.success(pkg.addPermissionGroup(result.getResult()));
1248     }
1249 
parsePermission(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1250     private static ParseResult<ParsingPackage> parsePermission(ParseInput input,
1251             ParsingPackage pkg, Resources res, XmlResourceParser parser)
1252             throws XmlPullParserException, IOException {
1253         ParseResult<ParsedPermission> result = ParsedPermissionUtils.parsePermission(
1254                 pkg, res, parser, sUseRoundIcon, input);
1255         if (result.isError()) {
1256             return input.error(result);
1257         }
1258         return input.success(pkg.addPermission(result.getResult()));
1259     }
1260 
parsePermissionTree(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1261     private static ParseResult<ParsingPackage> parsePermissionTree(ParseInput input,
1262             ParsingPackage pkg, Resources res, XmlResourceParser parser)
1263             throws XmlPullParserException, IOException {
1264         ParseResult<ParsedPermission> result = ParsedPermissionUtils.parsePermissionTree(
1265                 pkg, res, parser, sUseRoundIcon, input);
1266         if (result.isError()) {
1267             return input.error(result);
1268         }
1269         return input.success(pkg.addPermission(result.getResult()));
1270     }
1271 
parseUsesPermission(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1272     private ParseResult<ParsingPackage> parseUsesPermission(ParseInput input,
1273             ParsingPackage pkg, Resources res, XmlResourceParser parser)
1274             throws IOException, XmlPullParserException {
1275         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesPermission);
1276         try {
1277             // Note: don't allow this value to be a reference to a resource
1278             // that may change.
1279             String name = sa.getNonResourceString(
1280                     R.styleable.AndroidManifestUsesPermission_name);
1281             if (TextUtils.length(name) > MAX_PERMISSION_NAME_LENGTH) {
1282                 return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1283                         "The name in the <uses-permission> is greater than "
1284                                 + MAX_PERMISSION_NAME_LENGTH);
1285             }
1286 
1287             int maxSdkVersion = 0;
1288             TypedValue val = sa.peekValue(
1289                     R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
1290             if (val != null) {
1291                 if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
1292                     maxSdkVersion = val.data;
1293                 }
1294             }
1295 
1296             final ArraySet<String> requiredFeatures = new ArraySet<>();
1297             String feature = sa.getNonConfigurationString(
1298                     com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredFeature,
1299                     0);
1300             if (feature != null) {
1301                 requiredFeatures.add(feature);
1302             }
1303 
1304             final ArraySet<String> requiredNotFeatures = new ArraySet<>();
1305             feature = sa.getNonConfigurationString(
1306                     com.android.internal.R.styleable
1307                             .AndroidManifestUsesPermission_requiredNotFeature,
1308                     0);
1309             if (feature != null) {
1310                 requiredNotFeatures.add(feature);
1311             }
1312 
1313             final int usesPermissionFlags = sa.getInt(
1314                 com.android.internal.R.styleable.AndroidManifestUsesPermission_usesPermissionFlags,
1315                 0);
1316 
1317             final int outerDepth = parser.getDepth();
1318             int type;
1319             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1320                     && (type != XmlPullParser.END_TAG
1321                     || parser.getDepth() > outerDepth)) {
1322                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1323                     continue;
1324                 }
1325 
1326                 final ParseResult<?> result;
1327                 switch (parser.getName()) {
1328                     case "required-feature":
1329                         result = parseRequiredFeature(input, res, parser);
1330                         if (result.isSuccess()) {
1331                             requiredFeatures.add((String) result.getResult());
1332                         }
1333                         break;
1334 
1335                     case "required-not-feature":
1336                         result = parseRequiredNotFeature(input, res, parser);
1337                         if (result.isSuccess()) {
1338                             requiredNotFeatures.add((String) result.getResult());
1339                         }
1340                         break;
1341 
1342                     default:
1343                         result = ParsingUtils.unknownTag("<uses-permission>", pkg, parser, input);
1344                         break;
1345                 }
1346 
1347                 if (result.isError()) {
1348                     return input.error(result);
1349                 }
1350             }
1351 
1352             // Can only succeed from here on out
1353             ParseResult<ParsingPackage> success = input.success(pkg);
1354 
1355             if (name == null) {
1356                 return success;
1357             }
1358 
1359             if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
1360                 return success;
1361             }
1362 
1363             if (mCallback != null) {
1364                 // Only allow requesting this permission if the platform supports all of the
1365                 // "required-feature"s.
1366                 for (int i = requiredFeatures.size() - 1; i >= 0; i--) {
1367                     if (!mCallback.hasFeature(requiredFeatures.valueAt(i))) {
1368                         return success;
1369                     }
1370                 }
1371 
1372                 // Only allow requesting this permission if the platform does not supports any of
1373                 // the "required-not-feature"s.
1374                 for (int i = requiredNotFeatures.size() - 1; i >= 0; i--) {
1375                     if (mCallback.hasFeature(requiredNotFeatures.valueAt(i))) {
1376                         return success;
1377                     }
1378                 }
1379             }
1380 
1381             // Quietly ignore duplicate permission requests, but fail loudly if
1382             // the two requests have conflicting flags
1383             boolean found = false;
1384             final List<ParsedUsesPermission> usesPermissions = pkg.getUsesPermissions();
1385             final int size = usesPermissions.size();
1386             for (int i = 0; i < size; i++) {
1387                 final ParsedUsesPermission usesPermission = usesPermissions.get(i);
1388                 if (Objects.equals(usesPermission.getName(), name)) {
1389                     if (usesPermission.getUsesPermissionFlags() != usesPermissionFlags) {
1390                         return input.error("Conflicting uses-permissions flags: "
1391                                 + name + " in package: " + pkg.getPackageName() + " at: "
1392                                 + parser.getPositionDescription());
1393                     } else {
1394                         Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
1395                                 + name + " in package: " + pkg.getPackageName() + " at: "
1396                                 + parser.getPositionDescription());
1397                     }
1398                     found = true;
1399                     break;
1400                 }
1401             }
1402 
1403             if (!found) {
1404                 pkg.addUsesPermission(new ParsedUsesPermissionImpl(name, usesPermissionFlags));
1405             }
1406             return success;
1407         } finally {
1408             sa.recycle();
1409         }
1410     }
1411 
parseRequiredFeature(ParseInput input, Resources res, AttributeSet attrs)1412     private ParseResult<String> parseRequiredFeature(ParseInput input, Resources res,
1413             AttributeSet attrs) {
1414         final TypedArray sa = res.obtainAttributes(attrs,
1415                 com.android.internal.R.styleable.AndroidManifestRequiredFeature);
1416         try {
1417             final String featureName = sa.getString(
1418                     R.styleable.AndroidManifestRequiredFeature_name);
1419             return TextUtils.isEmpty(featureName)
1420                     ? input.error("Feature name is missing from <required-feature> tag.")
1421                     : input.success(featureName);
1422         } finally {
1423             sa.recycle();
1424         }
1425     }
1426 
parseRequiredNotFeature(ParseInput input, Resources res, AttributeSet attrs)1427     private ParseResult<String> parseRequiredNotFeature(ParseInput input, Resources res,
1428             AttributeSet attrs) {
1429         final TypedArray sa = res.obtainAttributes(attrs,
1430                 com.android.internal.R.styleable.AndroidManifestRequiredNotFeature);
1431         try {
1432             final String featureName = sa.getString(
1433                     R.styleable.AndroidManifestRequiredNotFeature_name);
1434             return TextUtils.isEmpty(featureName)
1435                     ? input.error("Feature name is missing from <required-not-feature> tag.")
1436                     : input.success(featureName);
1437         } finally {
1438             sa.recycle();
1439         }
1440     }
1441 
parseUsesConfiguration(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1442     private static ParseResult<ParsingPackage> parseUsesConfiguration(ParseInput input,
1443             ParsingPackage pkg, Resources res, XmlResourceParser parser) {
1444         ConfigurationInfo cPref = new ConfigurationInfo();
1445         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesConfiguration);
1446         try {
1447             cPref.reqTouchScreen = sa.getInt(
1448                     R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
1449                     Configuration.TOUCHSCREEN_UNDEFINED);
1450             cPref.reqKeyboardType = sa.getInt(
1451                     R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
1452                     Configuration.KEYBOARD_UNDEFINED);
1453             if (sa.getBoolean(
1454                     R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
1455                     false)) {
1456                 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
1457             }
1458             cPref.reqNavigation = sa.getInt(
1459                     R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
1460                     Configuration.NAVIGATION_UNDEFINED);
1461             if (sa.getBoolean(
1462                     R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
1463                     false)) {
1464                 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
1465             }
1466             pkg.addConfigPreference(cPref);
1467             return input.success(pkg);
1468         } finally {
1469             sa.recycle();
1470         }
1471     }
1472 
parseUsesFeature(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1473     private static ParseResult<ParsingPackage> parseUsesFeature(ParseInput input,
1474             ParsingPackage pkg, Resources res, XmlResourceParser parser) {
1475         FeatureInfo fi = parseFeatureInfo(res, parser);
1476         pkg.addReqFeature(fi);
1477 
1478         if (fi.name == null) {
1479             ConfigurationInfo cPref = new ConfigurationInfo();
1480             cPref.reqGlEsVersion = fi.reqGlEsVersion;
1481             pkg.addConfigPreference(cPref);
1482         }
1483 
1484         return input.success(pkg);
1485     }
1486 
parseFeatureInfo(Resources res, AttributeSet attrs)1487     private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) {
1488         FeatureInfo fi = new FeatureInfo();
1489         TypedArray sa = res.obtainAttributes(attrs, R.styleable.AndroidManifestUsesFeature);
1490         try {
1491             // Note: don't allow this value to be a reference to a resource
1492             // that may change.
1493             fi.name = sa.getNonResourceString(R.styleable.AndroidManifestUsesFeature_name);
1494             fi.version = sa.getInt(R.styleable.AndroidManifestUsesFeature_version, 0);
1495             if (fi.name == null) {
1496                 fi.reqGlEsVersion = sa.getInt(R.styleable.AndroidManifestUsesFeature_glEsVersion,
1497                         FeatureInfo.GL_ES_VERSION_UNDEFINED);
1498             }
1499             if (sa.getBoolean(R.styleable.AndroidManifestUsesFeature_required, true)) {
1500                 fi.flags |= FeatureInfo.FLAG_REQUIRED;
1501             }
1502             return fi;
1503         } finally {
1504             sa.recycle();
1505         }
1506     }
1507 
parseFeatureGroup(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1508     private static ParseResult<ParsingPackage> parseFeatureGroup(ParseInput input,
1509             ParsingPackage pkg, Resources res, XmlResourceParser parser)
1510             throws IOException, XmlPullParserException {
1511         FeatureGroupInfo group = new FeatureGroupInfo();
1512         ArrayList<FeatureInfo> features = null;
1513         final int depth = parser.getDepth();
1514         int type;
1515         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1516                 && (type != XmlPullParser.END_TAG
1517                 || parser.getDepth() > depth)) {
1518             if (type != XmlPullParser.START_TAG) {
1519                 continue;
1520             }
1521 
1522             final String innerTagName = parser.getName();
1523             if (innerTagName.equals("uses-feature")) {
1524                 FeatureInfo featureInfo = parseFeatureInfo(res, parser);
1525                 // FeatureGroups are stricter and mandate that
1526                 // any <uses-feature> declared are mandatory.
1527                 featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
1528                 features = ArrayUtils.add(features, featureInfo);
1529             } else {
1530                 Slog.w(TAG,
1531                         "Unknown element under <feature-group>: " + innerTagName
1532                                 + " at " + pkg.getBaseApkPath() + " "
1533                                 + parser.getPositionDescription());
1534             }
1535         }
1536 
1537         if (features != null) {
1538             group.features = new FeatureInfo[features.size()];
1539             group.features = features.toArray(group.features);
1540         }
1541 
1542         pkg.addFeatureGroup(group);
1543         return input.success(pkg);
1544     }
1545 
parseUsesSdk(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)1546     private static ParseResult<ParsingPackage> parseUsesSdk(ParseInput input,
1547             ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
1548             throws IOException, XmlPullParserException {
1549         if (SDK_VERSION > 0) {
1550             final boolean isApkInApex = (flags & PARSE_APK_IN_APEX) != 0;
1551             TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk);
1552             try {
1553                 int minVers = ParsingUtils.DEFAULT_MIN_SDK_VERSION;
1554                 String minCode = null;
1555                 boolean minAssigned = false;
1556                 int targetVers = ParsingUtils.DEFAULT_TARGET_SDK_VERSION;
1557                 String targetCode = null;
1558                 int maxVers = Integer.MAX_VALUE;
1559 
1560                 TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion);
1561                 if (val != null) {
1562                     if (val.type == TypedValue.TYPE_STRING && val.string != null) {
1563                         minCode = val.string.toString();
1564                         minAssigned = !TextUtils.isEmpty(minCode);
1565                     } else {
1566                         // If it's not a string, it's an integer.
1567                         minVers = val.data;
1568                         minAssigned = true;
1569                     }
1570                 }
1571 
1572                 val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
1573                 if (val != null) {
1574                     if (val.type == TypedValue.TYPE_STRING && val.string != null) {
1575                         targetCode = val.string.toString();
1576                         if (!minAssigned) {
1577                             minCode = targetCode;
1578                         }
1579                     } else {
1580                         // If it's not a string, it's an integer.
1581                         targetVers = val.data;
1582                     }
1583                 } else {
1584                     targetVers = minVers;
1585                     targetCode = minCode;
1586                 }
1587 
1588                 if (isApkInApex) {
1589                     val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_maxSdkVersion);
1590                     if (val != null) {
1591                         // maxSdkVersion only supports integer
1592                         maxVers = val.data;
1593                     }
1594                 }
1595 
1596                 ParseResult<Integer> targetSdkVersionResult = FrameworkParsingPackageUtils
1597                         .computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, input,
1598                                 isApkInApex);
1599                 if (targetSdkVersionResult.isError()) {
1600                     return input.error(targetSdkVersionResult);
1601                 }
1602 
1603                 int targetSdkVersion = targetSdkVersionResult.getResult();
1604 
1605                 ParseResult<?> deferResult =
1606                         input.enableDeferredError(pkg.getPackageName(), targetSdkVersion);
1607                 if (deferResult.isError()) {
1608                     return input.error(deferResult);
1609                 }
1610 
1611                 ParseResult<Integer> minSdkVersionResult = FrameworkParsingPackageUtils
1612                         .computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES, input);
1613                 if (minSdkVersionResult.isError()) {
1614                     return input.error(minSdkVersionResult);
1615                 }
1616 
1617                 int minSdkVersion = minSdkVersionResult.getResult();
1618 
1619                 pkg.setMinSdkVersion(minSdkVersion)
1620                         .setTargetSdkVersion(targetSdkVersion);
1621                 if (isApkInApex) {
1622                     ParseResult<Integer> maxSdkVersionResult = FrameworkParsingPackageUtils
1623                             .computeMaxSdkVersion(maxVers, SDK_VERSION, input);
1624                     if (maxSdkVersionResult.isError()) {
1625                         return input.error(maxSdkVersionResult);
1626                     }
1627                     int maxSdkVersion = maxSdkVersionResult.getResult();
1628                     pkg.setMaxSdkVersion(maxSdkVersion);
1629                 }
1630 
1631                 int type;
1632                 final int innerDepth = parser.getDepth();
1633                 SparseIntArray minExtensionVersions = null;
1634                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1635                         && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
1636                     if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1637                         continue;
1638                     }
1639 
1640                     final ParseResult result;
1641                     if (parser.getName().equals("extension-sdk")) {
1642                         if (minExtensionVersions == null) {
1643                             minExtensionVersions = new SparseIntArray();
1644                         }
1645                         result = parseExtensionSdk(input, res, parser, minExtensionVersions);
1646                         XmlUtils.skipCurrentTag(parser);
1647                     } else {
1648                         result = ParsingUtils.unknownTag("<uses-sdk>", pkg, parser, input);
1649                     }
1650 
1651                     if (result.isError()) {
1652                         return input.error(result);
1653                     }
1654                 }
1655                 pkg.setMinExtensionVersions(exactSizedCopyOfSparseArray(minExtensionVersions));
1656             } finally {
1657                 sa.recycle();
1658             }
1659         }
1660         return input.success(pkg);
1661     }
1662 
1663     @Nullable
exactSizedCopyOfSparseArray(@ullable SparseIntArray input)1664     private static SparseIntArray exactSizedCopyOfSparseArray(@Nullable SparseIntArray input) {
1665         if (input == null) {
1666             return null;
1667         }
1668         SparseIntArray output = new SparseIntArray(input.size());
1669         for (int i = 0; i < input.size(); i++) {
1670             output.put(input.keyAt(i), input.valueAt(i));
1671         }
1672         return output;
1673     }
1674 
parseExtensionSdk( ParseInput input, Resources res, XmlResourceParser parser, SparseIntArray minExtensionVersions)1675     private static ParseResult<SparseIntArray> parseExtensionSdk(
1676             ParseInput input, Resources res, XmlResourceParser parser,
1677             SparseIntArray minExtensionVersions) {
1678         int sdkVersion;
1679         int minVersion;
1680         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestExtensionSdk);
1681         try {
1682             sdkVersion = sa.getInt(R.styleable.AndroidManifestExtensionSdk_sdkVersion, -1);
1683             minVersion = sa.getInt(R.styleable.AndroidManifestExtensionSdk_minExtensionVersion, -1);
1684         } finally {
1685             sa.recycle();
1686         }
1687 
1688         if (sdkVersion < 0) {
1689             return input.error(
1690                     PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1691                     "<extension-sdk> must specify an sdkVersion >= 0");
1692         }
1693         if (minVersion < 0) {
1694             return input.error(
1695                     PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1696                     "<extension-sdk> must specify minExtensionVersion >= 0");
1697         }
1698 
1699         try {
1700             int version = SdkExtensions.getExtensionVersion(sdkVersion);
1701             if (version < minVersion) {
1702                 return input.error(
1703                         PackageManager.INSTALL_FAILED_OLDER_SDK,
1704                         "Package requires " + sdkVersion + " extension version " + minVersion
1705                                 + " which exceeds device version " + version);
1706             }
1707         } catch (RuntimeException e) {
1708             return input.error(
1709                     PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1710                     "Specified sdkVersion " + sdkVersion + " is not valid");
1711         }
1712         minExtensionVersions.put(sdkVersion, minVersion);
1713         return input.success(minExtensionVersions);
1714     }
1715 
parseRestrictUpdateHash(int flags, ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1716     private static ParseResult<ParsingPackage> parseRestrictUpdateHash(int flags, ParseInput input,
1717             ParsingPackage pkg, Resources res, XmlResourceParser parser) {
1718         if ((flags & PARSE_IS_SYSTEM_DIR) != 0) {
1719             TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestRestrictUpdate);
1720             try {
1721                 final String hash = sa.getNonConfigurationString(
1722                         R.styleable.AndroidManifestRestrictUpdate_hash,
1723                         0);
1724 
1725                 if (hash != null) {
1726                     final int hashLength = hash.length();
1727                     final byte[] hashBytes = new byte[hashLength / 2];
1728                     for (int i = 0; i < hashLength; i += 2) {
1729                         hashBytes[i / 2] = (byte) ((Character.digit(hash.charAt(i), 16)
1730                                 << 4)
1731                                 + Character.digit(hash.charAt(i + 1), 16));
1732                     }
1733                     pkg.setRestrictUpdateHash(hashBytes);
1734                 } else {
1735                     pkg.setRestrictUpdateHash(null);
1736                 }
1737             } finally {
1738                 sa.recycle();
1739             }
1740         }
1741         return input.success(pkg);
1742     }
1743 
parseInstallConstraints( ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1744     private static ParseResult<ParsingPackage> parseInstallConstraints(
1745             ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)
1746             throws IOException, XmlPullParserException {
1747         return InstallConstraintsTagParser.parseInstallConstraints(input, pkg, res, parser);
1748     }
1749 
parseQueries(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)1750     private static ParseResult<ParsingPackage> parseQueries(ParseInput input, ParsingPackage pkg,
1751             Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException {
1752         final int depth = parser.getDepth();
1753         int type;
1754         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1755                 && (type != XmlPullParser.END_TAG
1756                 || parser.getDepth() > depth)) {
1757             if (type != XmlPullParser.START_TAG) {
1758                 continue;
1759             }
1760             if (parser.getName().equals("intent")) {
1761                 ParseResult<ParsedIntentInfoImpl> result = ParsedIntentInfoUtils.parseIntentInfo(
1762                         null /*className*/, pkg, res, parser, true /*allowGlobs*/,
1763                         true /*allowAutoVerify*/, input);
1764                 if (result.isError()) {
1765                     return input.error(result);
1766                 }
1767 
1768                 IntentFilter intentInfo = result.getResult().getIntentFilter();
1769 
1770                 Uri data = null;
1771                 String dataType = null;
1772                 String host = null;
1773                 final int numActions = intentInfo.countActions();
1774                 final int numSchemes = intentInfo.countDataSchemes();
1775                 final int numTypes = intentInfo.countDataTypes();
1776                 final int numHosts = intentInfo.getHosts().length;
1777                 if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) {
1778                     return input.error("intent tags must contain either an action or data.");
1779                 }
1780                 if (numActions > 1) {
1781                     return input.error("intent tag may have at most one action.");
1782                 }
1783                 if (numTypes > 1) {
1784                     return input.error("intent tag may have at most one data type.");
1785                 }
1786                 if (numSchemes > 1) {
1787                     return input.error("intent tag may have at most one data scheme.");
1788                 }
1789                 if (numHosts > 1) {
1790                     return input.error("intent tag may have at most one data host.");
1791                 }
1792                 Intent intent = new Intent();
1793                 for (int i = 0, max = intentInfo.countCategories(); i < max; i++) {
1794                     intent.addCategory(intentInfo.getCategory(i));
1795                 }
1796                 if (numHosts == 1) {
1797                     host = intentInfo.getHosts()[0];
1798                 }
1799                 if (numSchemes == 1) {
1800                     data = new Uri.Builder()
1801                             .scheme(intentInfo.getDataScheme(0))
1802                             .authority(host)
1803                             .path(IntentFilter.WILDCARD_PATH)
1804                             .build();
1805                 }
1806                 if (numTypes == 1) {
1807                     dataType = intentInfo.getDataType(0);
1808                     // The dataType may have had the '/' removed for the dynamic mimeType feature.
1809                     // If we detect that case, we add the * back.
1810                     if (!dataType.contains("/")) {
1811                         dataType = dataType + "/*";
1812                     }
1813                     if (data == null) {
1814                         data = new Uri.Builder()
1815                                 .scheme("content")
1816                                 .authority(IntentFilter.WILDCARD)
1817                                 .path(IntentFilter.WILDCARD_PATH)
1818                                 .build();
1819                     }
1820                 }
1821                 intent.setDataAndType(data, dataType);
1822                 if (numActions == 1) {
1823                     intent.setAction(intentInfo.getAction(0));
1824                 }
1825                 pkg.addQueriesIntent(intent);
1826             } else if (parser.getName().equals("package")) {
1827                 final TypedArray sa = res.obtainAttributes(parser,
1828                         R.styleable.AndroidManifestQueriesPackage);
1829                 final String packageName = sa.getNonConfigurationString(
1830                         R.styleable.AndroidManifestQueriesPackage_name, 0);
1831                 if (TextUtils.isEmpty(packageName)) {
1832                     return input.error("Package name is missing from package tag.");
1833                 }
1834                 pkg.addQueriesPackage(packageName.intern());
1835             } else if (parser.getName().equals("provider")) {
1836                 final TypedArray sa = res.obtainAttributes(parser,
1837                         R.styleable.AndroidManifestQueriesProvider);
1838                 try {
1839                     final String authorities = sa.getNonConfigurationString(
1840                             R.styleable.AndroidManifestQueriesProvider_authorities, 0);
1841                     if (TextUtils.isEmpty(authorities)) {
1842                         return input.error(
1843                                 PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1844                                 "Authority missing from provider tag."
1845                         );
1846                     }
1847                     StringTokenizer authoritiesTokenizer = new StringTokenizer(authorities, ";");
1848                     while (authoritiesTokenizer.hasMoreElements()) {
1849                         pkg.addQueriesProvider(authoritiesTokenizer.nextToken());
1850                     }
1851                 } finally {
1852                     sa.recycle();
1853                 }
1854             }
1855         }
1856         return input.success(pkg);
1857     }
1858 
1859     /**
1860      * Parse the {@code application} XML tree at the current parse location in a
1861      * <em>base APK</em> manifest.
1862      * <p>
1863      * When adding new features, carefully consider if they should also be supported by split APKs.
1864      * <p>
1865      * This method should avoid using a getter for fields set by this method. Prefer assigning a
1866      * local variable and using it. Otherwise there's an ordering problem which can be broken if any
1867      * code moves around.
1868      */
parseBaseApplication(ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)1869     private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
1870             ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
1871             throws XmlPullParserException, IOException {
1872         final String pkgName = pkg.getPackageName();
1873         int targetSdk = pkg.getTargetSdkVersion();
1874 
1875         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
1876         try {
1877             // TODO(b/135203078): Remove this and force unit tests to mock an empty manifest
1878             // This case can only happen in unit tests where we sometimes need to create fakes
1879             // of various package parser data structures.
1880             if (sa == null) {
1881                 return input.error("<application> does not contain any attributes");
1882             }
1883 
1884             String name = sa.getNonConfigurationString(R.styleable.AndroidManifestApplication_name,
1885                     0);
1886             if (name != null) {
1887                 String packageName = pkg.getPackageName();
1888                 String outInfoName = ParsingUtils.buildClassName(packageName, name);
1889                 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
1890                     return input.error("<application> invalid android:name");
1891                 } else if (outInfoName == null) {
1892                     return input.error("Empty class name in package " + packageName);
1893                 }
1894 
1895                 pkg.setClassName(outInfoName);
1896             }
1897 
1898             TypedValue labelValue = sa.peekValue(R.styleable.AndroidManifestApplication_label);
1899             if (labelValue != null) {
1900                 pkg.setLabelRes(labelValue.resourceId);
1901                 if (labelValue.resourceId == 0) {
1902                     pkg.setNonLocalizedLabel(labelValue.coerceToString());
1903                 }
1904             }
1905 
1906             parseBaseAppBasicFlags(pkg, sa);
1907 
1908             String manageSpaceActivity = nonConfigString(Configuration.NATIVE_CONFIG_VERSION,
1909                     R.styleable.AndroidManifestApplication_manageSpaceActivity, sa);
1910             if (manageSpaceActivity != null) {
1911                 String manageSpaceActivityName = ParsingUtils.buildClassName(pkgName,
1912                         manageSpaceActivity);
1913 
1914                 if (manageSpaceActivityName == null) {
1915                     return input.error("Empty class name in package " + pkgName);
1916                 }
1917 
1918                 pkg.setManageSpaceActivityName(manageSpaceActivityName);
1919             }
1920 
1921             if (pkg.isAllowBackup()) {
1922                 // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
1923                 // and restoreAnyVersion are only relevant if backup is possible for the
1924                 // given application.
1925                 String backupAgent = nonConfigString(Configuration.NATIVE_CONFIG_VERSION,
1926                         R.styleable.AndroidManifestApplication_backupAgent, sa);
1927                 if (backupAgent != null) {
1928                     String backupAgentName = ParsingUtils.buildClassName(pkgName, backupAgent);
1929                     if (backupAgentName == null) {
1930                         return input.error("Empty class name in package " + pkgName);
1931                     }
1932 
1933                     if (DEBUG_BACKUP) {
1934                         Slog.v(TAG, "android:backupAgent = " + backupAgentName
1935                                 + " from " + pkgName + "+" + backupAgent);
1936                     }
1937 
1938                     pkg.setBackupAgentName(backupAgentName)
1939                             .setKillAfterRestore(bool(true,
1940                                     R.styleable.AndroidManifestApplication_killAfterRestore, sa))
1941                             .setRestoreAnyVersion(bool(false,
1942                                     R.styleable.AndroidManifestApplication_restoreAnyVersion, sa))
1943                             .setFullBackupOnly(bool(false,
1944                                     R.styleable.AndroidManifestApplication_fullBackupOnly, sa))
1945                             .setBackupInForeground(bool(false,
1946                                     R.styleable.AndroidManifestApplication_backupInForeground, sa));
1947                 }
1948 
1949                 TypedValue v = sa.peekValue(
1950                         R.styleable.AndroidManifestApplication_fullBackupContent);
1951                 int fullBackupContent = 0;
1952 
1953                 if (v != null) {
1954                     fullBackupContent = v.resourceId;
1955 
1956                     if (v.resourceId == 0) {
1957                         if (DEBUG_BACKUP) {
1958                             Slog.v(TAG, "fullBackupContent specified as boolean=" +
1959                                     (v.data == 0 ? "false" : "true"));
1960                         }
1961                         // "false" => -1, "true" => 0
1962                         fullBackupContent = v.data == 0 ? -1 : 0;
1963                     }
1964 
1965                     pkg.setFullBackupContent(fullBackupContent);
1966                 }
1967                 if (DEBUG_BACKUP) {
1968                     Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName);
1969                 }
1970             }
1971 
1972             if (sa.getBoolean(R.styleable.AndroidManifestApplication_persistent, false)) {
1973                 // Check if persistence is based on a feature being present
1974                 final String requiredFeature = sa.getNonResourceString(R.styleable
1975                         .AndroidManifestApplication_persistentWhenFeatureAvailable);
1976                 pkg.setPersistent(requiredFeature == null || mCallback.hasFeature(requiredFeature));
1977             }
1978 
1979             if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
1980                 pkg.setResizeableActivity(sa.getBoolean(
1981                         R.styleable.AndroidManifestApplication_resizeableActivity, true));
1982             } else {
1983                 pkg.setResizeableActivityViaSdkVersion(
1984                         targetSdk >= Build.VERSION_CODES.N);
1985             }
1986 
1987             String taskAffinity;
1988             if (targetSdk >= Build.VERSION_CODES.FROYO) {
1989                 taskAffinity = sa.getNonConfigurationString(
1990                         R.styleable.AndroidManifestApplication_taskAffinity,
1991                         Configuration.NATIVE_CONFIG_VERSION);
1992             } else {
1993                 // Some older apps have been seen to use a resource reference
1994                 // here that on older builds was ignored (with a warning).  We
1995                 // need to continue to do this for them so they don't break.
1996                 taskAffinity = sa.getNonResourceString(
1997                         R.styleable.AndroidManifestApplication_taskAffinity);
1998             }
1999 
2000             ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName(
2001                     pkgName, pkgName, taskAffinity, input);
2002             if (taskAffinityResult.isError()) {
2003                 return input.error(taskAffinityResult);
2004             }
2005 
2006             pkg.setTaskAffinity(taskAffinityResult.getResult());
2007             String factory = sa.getNonResourceString(
2008                     R.styleable.AndroidManifestApplication_appComponentFactory);
2009             if (factory != null) {
2010                 String appComponentFactory = ParsingUtils.buildClassName(pkgName, factory);
2011                 if (appComponentFactory == null) {
2012                     return input.error("Empty class name in package " + pkgName);
2013                 }
2014 
2015                 pkg.setAppComponentFactory(appComponentFactory);
2016             }
2017 
2018             CharSequence pname;
2019             if (targetSdk >= Build.VERSION_CODES.FROYO) {
2020                 pname = sa.getNonConfigurationString(
2021                         R.styleable.AndroidManifestApplication_process,
2022                         Configuration.NATIVE_CONFIG_VERSION);
2023             } else {
2024                 // Some older apps have been seen to use a resource reference
2025                 // here that on older builds was ignored (with a warning).  We
2026                 // need to continue to do this for them so they don't break.
2027                 pname = sa.getNonResourceString(
2028                         R.styleable.AndroidManifestApplication_process);
2029             }
2030             ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
2031                     pkgName, null /*defProc*/, pname, flags, mSeparateProcesses, input);
2032             if (processNameResult.isError()) {
2033                 return input.error(processNameResult);
2034             }
2035 
2036             String processName = processNameResult.getResult();
2037             pkg.setProcessName(processName);
2038 
2039             if (pkg.isCantSaveState()) {
2040                 // A heavy-weight application can not be in a custom process.
2041                 // We can do direct compare because we intern all strings.
2042                 if (processName != null && !processName.equals(pkgName)) {
2043                     return input.error(
2044                             "cantSaveState applications can not use custom processes");
2045                 }
2046             }
2047 
2048             String classLoaderName = pkg.getClassLoaderName();
2049             if (classLoaderName != null
2050                     && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
2051                 return input.error("Invalid class loader name: " + classLoaderName);
2052             }
2053 
2054             pkg.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestApplication_gwpAsanMode, -1));
2055             pkg.setMemtagMode(sa.getInt(R.styleable.AndroidManifestApplication_memtagMode, -1));
2056             if (sa.hasValue(R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized)) {
2057                 final boolean v = sa.getBoolean(
2058                         R.styleable.AndroidManifestApplication_nativeHeapZeroInitialized, false);
2059                 pkg.setNativeHeapZeroInitialized(
2060                         v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED);
2061             }
2062             if (sa.hasValue(
2063                     R.styleable.AndroidManifestApplication_requestRawExternalStorageAccess)) {
2064                 pkg.setRequestRawExternalStorageAccess(sa.getBoolean(R.styleable
2065                                 .AndroidManifestApplication_requestRawExternalStorageAccess,
2066                         false));
2067             }
2068             if (sa.hasValue(
2069                     R.styleable.AndroidManifestApplication_requestForegroundServiceExemption)) {
2070                 pkg.setRequestForegroundServiceExemption(sa.getBoolean(R.styleable
2071                                 .AndroidManifestApplication_requestForegroundServiceExemption,
2072                         false));
2073             }
2074             final ParseResult<Set<String>> knownActivityEmbeddingCertsResult =
2075                     parseKnownActivityEmbeddingCerts(sa, res,
2076                             R.styleable.AndroidManifestApplication_knownActivityEmbeddingCerts,
2077                             input);
2078             if (knownActivityEmbeddingCertsResult.isError()) {
2079                 return input.error(knownActivityEmbeddingCertsResult);
2080             } else {
2081                 final Set<String> knownActivityEmbeddingCerts = knownActivityEmbeddingCertsResult
2082                         .getResult();
2083                 if (knownActivityEmbeddingCerts != null) {
2084                     pkg.setKnownActivityEmbeddingCerts(knownActivityEmbeddingCerts);
2085                 }
2086             }
2087         } finally {
2088             sa.recycle();
2089         }
2090 
2091         boolean hasActivityOrder = false;
2092         boolean hasReceiverOrder = false;
2093         boolean hasServiceOrder = false;
2094         final int depth = parser.getDepth();
2095         int type;
2096         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2097                 && (type != XmlPullParser.END_TAG
2098                 || parser.getDepth() > depth)) {
2099             if (type != XmlPullParser.START_TAG) {
2100                 continue;
2101             }
2102 
2103             final ParseResult result;
2104             String tagName = parser.getName();
2105             boolean isActivity = false;
2106             switch (tagName) {
2107                 case "activity":
2108                     isActivity = true;
2109                     // fall-through
2110                 case "receiver":
2111                     ParseResult<ParsedActivity> activityResult =
2112                             ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
2113                                     res, parser, flags, sUseRoundIcon, null /*defaultSplitName*/,
2114                                     input);
2115 
2116                     if (activityResult.isSuccess()) {
2117                         ParsedActivity activity = activityResult.getResult();
2118                         if (isActivity) {
2119                             hasActivityOrder |= (activity.getOrder() != 0);
2120                             pkg.addActivity(activity);
2121                         } else {
2122                             hasReceiverOrder |= (activity.getOrder() != 0);
2123                             pkg.addReceiver(activity);
2124                         }
2125                     }
2126 
2127                     result = activityResult;
2128                     break;
2129                 case "service":
2130                     ParseResult<ParsedService> serviceResult =
2131                             ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
2132                                     flags, sUseRoundIcon, null /*defaultSplitName*/,
2133                                     input);
2134                     if (serviceResult.isSuccess()) {
2135                         ParsedService service = serviceResult.getResult();
2136                         hasServiceOrder |= (service.getOrder() != 0);
2137                         pkg.addService(service);
2138                     }
2139 
2140                     result = serviceResult;
2141                     break;
2142                 case "provider":
2143                     ParseResult<ParsedProvider> providerResult =
2144                             ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
2145                                     flags, sUseRoundIcon, null /*defaultSplitName*/,
2146                                     input);
2147                     if (providerResult.isSuccess()) {
2148                         pkg.addProvider(providerResult.getResult());
2149                     }
2150 
2151                     result = providerResult;
2152                     break;
2153                 case "activity-alias":
2154                     activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
2155                             parser, sUseRoundIcon, null /*defaultSplitName*/,
2156                             input);
2157                     if (activityResult.isSuccess()) {
2158                         ParsedActivity activity = activityResult.getResult();
2159                         hasActivityOrder |= (activity.getOrder() != 0);
2160                         pkg.addActivity(activity);
2161                     }
2162 
2163                     result = activityResult;
2164                     break;
2165                 case "apex-system-service":
2166                     ParseResult<ParsedApexSystemService> systemServiceResult =
2167                             ParsedApexSystemServiceUtils.parseApexSystemService(res,
2168                                     parser, input);
2169                     if (systemServiceResult.isSuccess()) {
2170                         ParsedApexSystemService systemService =
2171                                 systemServiceResult.getResult();
2172                         pkg.addApexSystemService(systemService);
2173                     }
2174 
2175                     result = systemServiceResult;
2176                     break;
2177                 default:
2178                     result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags);
2179                     break;
2180             }
2181 
2182             if (result.isError()) {
2183                 return input.error(result);
2184             }
2185             if (hasTooManyComponents(pkg)) {
2186                 return input.error(MAX_NUM_COMPONENTS_ERR_MSG);
2187             }
2188         }
2189 
2190         if (TextUtils.isEmpty(pkg.getStaticSharedLibName()) && TextUtils.isEmpty(
2191                 pkg.getSdkLibName())) {
2192             // Add a hidden app detail activity to normal apps which forwards user to App Details
2193             // page.
2194             ParseResult<ParsedActivity> a = generateAppDetailsHiddenActivity(input, pkg);
2195             if (a.isError()) {
2196                 // Error should be impossible here, as the only failure case as of SDK R is a
2197                 // string validation error on a constant ":app_details" string passed in by the
2198                 // parsing code itself. For this reason, this is just a hard failure instead of
2199                 // deferred.
2200                 return input.error(a);
2201             }
2202 
2203             pkg.addActivity(a.getResult());
2204         }
2205 
2206         if (hasActivityOrder) {
2207             pkg.sortActivities();
2208         }
2209         if (hasReceiverOrder) {
2210             pkg.sortReceivers();
2211         }
2212         if (hasServiceOrder) {
2213             pkg.sortServices();
2214         }
2215 
2216         // Must be run after the entire {@link ApplicationInfo} has been fully processed and after
2217         // every activity info has had a chance to set it from its attributes.
2218         setMaxAspectRatio(pkg);
2219         setMinAspectRatio(pkg);
2220         setSupportsSizeChanges(pkg);
2221 
2222         pkg.setHasDomainUrls(hasDomainURLs(pkg));
2223 
2224         return input.success(pkg);
2225     }
2226 
2227     /**
2228      * Collection of single-line, no (or little) logic assignments. Separated for readability.
2229      * <p>
2230      * Flags are separated by type and by default value. They are sorted alphabetically within each
2231      * section.
2232      */
parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa)2233     private void parseBaseAppBasicFlags(ParsingPackage pkg, TypedArray sa) {
2234         int targetSdk = pkg.getTargetSdkVersion();
2235         //@formatter:off
2236         // CHECKSTYLE:off
2237         pkg
2238                 // Default true
2239                 .setAllowBackup(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa))
2240                 .setAllowClearUserData(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa))
2241                 .setAllowClearUserDataOnFailedRestore(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa))
2242                 .setAllowNativeHeapPointerTagging(bool(true, R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, sa))
2243                 .setEnabled(bool(true, R.styleable.AndroidManifestApplication_enabled, sa))
2244                 .setExtractNativeLibs(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa))
2245                 .setHasCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa))
2246                 // Default false
2247                 .setAllowTaskReparenting(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa))
2248                 .setCantSaveState(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa))
2249                 .setCrossProfile(bool(false, R.styleable.AndroidManifestApplication_crossProfile, sa))
2250                 .setDebuggable(bool(false, R.styleable.AndroidManifestApplication_debuggable, sa))
2251                 .setDefaultToDeviceProtectedStorage(bool(false, R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, sa))
2252                 .setDirectBootAware(bool(false, R.styleable.AndroidManifestApplication_directBootAware, sa))
2253                 .setForceQueryable(bool(false, R.styleable.AndroidManifestApplication_forceQueryable, sa))
2254                 .setGame(bool(false, R.styleable.AndroidManifestApplication_isGame, sa))
2255                 .setHasFragileUserData(bool(false, R.styleable.AndroidManifestApplication_hasFragileUserData, sa))
2256                 .setLargeHeap(bool(false, R.styleable.AndroidManifestApplication_largeHeap, sa))
2257                 .setMultiArch(bool(false, R.styleable.AndroidManifestApplication_multiArch, sa))
2258                 .setPreserveLegacyExternalStorage(bool(false, R.styleable.AndroidManifestApplication_preserveLegacyExternalStorage, sa))
2259                 .setRequiredForAllUsers(bool(false, R.styleable.AndroidManifestApplication_requiredForAllUsers, sa))
2260                 .setSupportsRtl(bool(false, R.styleable.AndroidManifestApplication_supportsRtl, sa))
2261                 .setTestOnly(bool(false, R.styleable.AndroidManifestApplication_testOnly, sa))
2262                 .setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa))
2263                 .setUsesNonSdkApi(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
2264                 .setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa))
2265                 .setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa))
2266                 .setAttributionsAreUserVisible(bool(false, R.styleable.AndroidManifestApplication_attributionsAreUserVisible, sa))
2267                 .setResetEnabledSettingsOnAppDataCleared(bool(false,
2268                         R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared,
2269                         sa))
2270                 .setOnBackInvokedCallbackEnabled(bool(false, R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa))
2271                 // targetSdkVersion gated
2272                 .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
2273                 .setBaseHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
2274                 .setRequestLegacyExternalStorage(bool(targetSdk < Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, sa))
2275                 .setUsesCleartextTraffic(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa))
2276                 // Ints Default 0
2277                 .setUiOptions(anInt(R.styleable.AndroidManifestApplication_uiOptions, sa))
2278                 // Ints
2279                 .setCategory(anInt(ApplicationInfo.CATEGORY_UNDEFINED, R.styleable.AndroidManifestApplication_appCategory, sa))
2280                 // Floats Default 0f
2281                 .setMaxAspectRatio(aFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, sa))
2282                 .setMinAspectRatio(aFloat(R.styleable.AndroidManifestApplication_minAspectRatio, sa))
2283                 // Resource ID
2284                 .setBanner(resId(R.styleable.AndroidManifestApplication_banner, sa))
2285                 .setDescriptionRes(resId(R.styleable.AndroidManifestApplication_description, sa))
2286                 .setIconRes(resId(R.styleable.AndroidManifestApplication_icon, sa))
2287                 .setLogo(resId(R.styleable.AndroidManifestApplication_logo, sa))
2288                 .setNetworkSecurityConfigRes(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
2289                 .setRoundIconRes(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
2290                 .setTheme(resId(R.styleable.AndroidManifestApplication_theme, sa))
2291                 .setDataExtractionRules(
2292                         resId(R.styleable.AndroidManifestApplication_dataExtractionRules, sa))
2293                 .setLocaleConfigRes(resId(R.styleable.AndroidManifestApplication_localeConfig, sa))
2294                 // Strings
2295                 .setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa))
2296                 .setRequiredAccountType(string(R.styleable.AndroidManifestApplication_requiredAccountType, sa))
2297                 .setRestrictedAccountType(string(R.styleable.AndroidManifestApplication_restrictedAccountType, sa))
2298                 .setZygotePreloadName(string(R.styleable.AndroidManifestApplication_zygotePreloadName, sa))
2299                 // Non-Config String
2300                 .setPermission(nonConfigString(0, R.styleable.AndroidManifestApplication_permission, sa));
2301         // CHECKSTYLE:on
2302         //@formatter:on
2303     }
2304 
2305     /**
2306      * For parsing non-MainComponents. Main ones have an order and some special handling which is
2307      * done directly in {@link #parseBaseApplication(ParseInput, ParsingPackage, Resources,
2308      * XmlResourceParser, int)}.
2309      */
2310     private ParseResult parseBaseAppChildTag(ParseInput input, String tag, ParsingPackage pkg,
2311             Resources res, XmlResourceParser parser, int flags)
2312             throws IOException, XmlPullParserException {
2313         switch (tag) {
2314             case "meta-data":
2315                 // TODO(b/135203078): I have no idea what this comment means
2316                 // note: application meta-data is stored off to the side, so it can
2317                 // remain null in the primary copy (we like to avoid extra copies because
2318                 // it can be large)
2319                 final ParseResult<Property> metaDataResult = parseMetaData(pkg, null /*component*/,
2320                         res, parser, "<meta-data>", input);
2321                 if (metaDataResult.isSuccess() && metaDataResult.getResult() != null) {
2322                     pkg.setMetaData(metaDataResult.getResult().toBundle(pkg.getMetaData()));
2323                 }
2324                 return metaDataResult;
2325             case "property":
2326                 final ParseResult<Property> propertyResult = parseMetaData(pkg, null /*component*/,
2327                         res, parser, "<property>", input);
2328                 if (propertyResult.isSuccess()) {
2329                     pkg.addProperty(propertyResult.getResult());
2330                 }
2331                 return propertyResult;
2332             case "sdk-library":
2333                 return parseSdkLibrary(pkg, res, parser, input);
2334             case "static-library":
2335                 return parseStaticLibrary(pkg, res, parser, input);
2336             case "library":
2337                 return parseLibrary(pkg, res, parser, input);
2338             case "uses-sdk-library":
2339                 return parseUsesSdkLibrary(input, pkg, res, parser);
2340             case "uses-static-library":
2341                 return parseUsesStaticLibrary(input, pkg, res, parser);
2342             case "uses-library":
2343                 return parseUsesLibrary(input, pkg, res, parser);
2344             case "uses-native-library":
2345                 return parseUsesNativeLibrary(input, pkg, res, parser);
2346             case "processes":
2347                 return parseProcesses(input, pkg, res, parser, mSeparateProcesses, flags);
2348             case "uses-package":
2349                 // Dependencies for app installers; we don't currently try to
2350                 // enforce this.
2351                 return input.success(null);
2352             case "profileable":
2353                 return parseProfileable(input, pkg, res, parser);
2354             default:
2355                 return ParsingUtils.unknownTag("<application>", pkg, parser, input);
2356         }
2357     }
2358 
2359     @NonNull
2360     private static ParseResult<ParsingPackage> parseSdkLibrary(
2361             ParsingPackage pkg, Resources res,
2362             XmlResourceParser parser, ParseInput input) {
2363         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestSdkLibrary);
2364         try {
2365             // Note: don't allow this value to be a reference to a resource that may change.
2366             String lname = sa.getNonResourceString(
2367                     R.styleable.AndroidManifestSdkLibrary_name);
2368             final int versionMajor = sa.getInt(
2369                     R.styleable.AndroidManifestSdkLibrary_versionMajor,
2370                     -1);
2371 
2372             // Fail if malformed.
2373             if (lname == null || versionMajor < 0) {
2374                 return input.error("Bad sdk-library declaration name: " + lname
2375                         + " version: " + versionMajor);
2376             } else if (pkg.getSharedUserId() != null) {
2377                 return input.error(
2378                         PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
2379                         "sharedUserId not allowed in SDK library"
2380                 );
2381             } else if (pkg.getSdkLibName() != null) {
2382                 return input.error("Multiple SDKs for package "
2383                         + pkg.getPackageName());
2384             }
2385 
2386             return input.success(pkg.setSdkLibName(lname.intern())
2387                     .setSdkLibVersionMajor(versionMajor)
2388                     .setSdkLibrary(true));
2389         } finally {
2390             sa.recycle();
2391         }
2392     }
2393 
2394     @NonNull
2395     private static ParseResult<ParsingPackage> parseStaticLibrary(
2396             ParsingPackage pkg, Resources res,
2397             XmlResourceParser parser, ParseInput input) {
2398         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestStaticLibrary);
2399         try {
2400             // Note: don't allow this value to be a reference to a resource
2401             // that may change.
2402             String lname = sa.getNonResourceString(
2403                     R.styleable.AndroidManifestStaticLibrary_name);
2404             final int version = sa.getInt(
2405                     R.styleable.AndroidManifestStaticLibrary_version, -1);
2406             final int versionMajor = sa.getInt(
2407                     R.styleable.AndroidManifestStaticLibrary_versionMajor,
2408                     0);
2409 
2410             // Since the app canot run without a static lib - fail if malformed
2411             if (lname == null || version < 0) {
2412                 return input.error("Bad static-library declaration name: " + lname
2413                         + " version: " + version);
2414             } else if (pkg.getSharedUserId() != null) {
2415                 return input.error(
2416                         PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
2417                         "sharedUserId not allowed in static shared library"
2418                 );
2419             } else if (pkg.getStaticSharedLibName() != null) {
2420                 return input.error("Multiple static-shared libs for package "
2421                         + pkg.getPackageName());
2422             }
2423 
2424             return input.success(pkg.setStaticSharedLibName(lname.intern())
2425                     .setStaticSharedLibVersion(
2426                             PackageInfo.composeLongVersionCode(versionMajor, version))
2427                     .setStaticSharedLibrary(true));
2428         } finally {
2429             sa.recycle();
2430         }
2431     }
2432 
2433     @NonNull
2434     private static ParseResult<ParsingPackage> parseLibrary(
2435             ParsingPackage pkg, Resources res,
2436             XmlResourceParser parser, ParseInput input) {
2437         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestLibrary);
2438         try {
2439             // Note: don't allow this value to be a reference to a resource
2440             // that may change.
2441             String lname = sa.getNonResourceString(R.styleable.AndroidManifestLibrary_name);
2442 
2443             if (lname != null) {
2444                 lname = lname.intern();
2445                 if (!ArrayUtils.contains(pkg.getLibraryNames(), lname)) {
2446                     pkg.addLibraryName(lname);
2447                 }
2448             }
2449             return input.success(pkg);
2450         } finally {
2451             sa.recycle();
2452         }
2453     }
2454 
2455     @NonNull
2456     private static ParseResult<ParsingPackage> parseUsesSdkLibrary(ParseInput input,
2457             ParsingPackage pkg, Resources res, XmlResourceParser parser)
2458             throws XmlPullParserException, IOException {
2459         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdkLibrary);
2460         try {
2461             // Note: don't allow this value to be a reference to a resource that may change.
2462             String lname = sa.getNonResourceString(
2463                     R.styleable.AndroidManifestUsesSdkLibrary_name);
2464             final int versionMajor = sa.getInt(
2465                     R.styleable.AndroidManifestUsesSdkLibrary_versionMajor, -1);
2466             String certSha256Digest = sa.getNonResourceString(R.styleable
2467                     .AndroidManifestUsesSdkLibrary_certDigest);
2468 
2469             // Since an APK providing a static shared lib can only provide the lib - fail if
2470             // malformed
2471             if (lname == null || versionMajor < 0 || certSha256Digest == null) {
2472                 return input.error("Bad uses-sdk-library declaration name: " + lname
2473                         + " version: " + versionMajor + " certDigest" + certSha256Digest);
2474             }
2475 
2476             // Can depend only on one version of the same library
2477             List<String> usesSdkLibraries = pkg.getUsesSdkLibraries();
2478             if (usesSdkLibraries.contains(lname)) {
2479                 return input.error(
2480                         "Depending on multiple versions of SDK library " + lname);
2481             }
2482 
2483             lname = lname.intern();
2484             // We allow ":" delimiters in the SHA declaration as this is the format
2485             // emitted by the certtool making it easy for developers to copy/paste.
2486             certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
2487 
2488             if ("".equals(certSha256Digest)) {
2489                 // Test-only uses-sdk-library empty certificate digest override.
2490                 certSha256Digest = SystemProperties.get(
2491                         "debug.pm.uses_sdk_library_default_cert_digest", "");
2492                 // Validate the overridden digest.
2493                 try {
2494                     HexEncoding.decode(certSha256Digest, false);
2495                 } catch (IllegalArgumentException e) {
2496                     certSha256Digest = "";
2497                 }
2498             }
2499 
2500             ParseResult<String[]> certResult = parseAdditionalCertificates(input, res, parser);
2501             if (certResult.isError()) {
2502                 return input.error(certResult);
2503             }
2504             String[] additionalCertSha256Digests = certResult.getResult();
2505 
2506             final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1];
2507             certSha256Digests[0] = certSha256Digest;
2508             System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests,
2509                     1, additionalCertSha256Digests.length);
2510 
2511             return input.success(pkg.addUsesSdkLibrary(lname, versionMajor, certSha256Digests));
2512         } finally {
2513             sa.recycle();
2514         }
2515     }
2516 
2517     @NonNull
2518     private static ParseResult<ParsingPackage> parseUsesStaticLibrary(ParseInput input,
2519             ParsingPackage pkg, Resources res, XmlResourceParser parser)
2520             throws XmlPullParserException, IOException {
2521         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesStaticLibrary);
2522         try {
2523             // Note: don't allow this value to be a reference to a resource that may change.
2524             String lname = sa.getNonResourceString(
2525                     R.styleable.AndroidManifestUsesLibrary_name);
2526             final int version = sa.getInt(
2527                     R.styleable.AndroidManifestUsesStaticLibrary_version, -1);
2528             String certSha256Digest = sa.getNonResourceString(R.styleable
2529                     .AndroidManifestUsesStaticLibrary_certDigest);
2530 
2531             // Since an APK providing a static shared lib can only provide the lib - fail if
2532             // malformed
2533             if (lname == null || version < 0 || certSha256Digest == null) {
2534                 return input.error("Bad uses-static-library declaration name: " + lname
2535                         + " version: " + version + " certDigest" + certSha256Digest);
2536             }
2537 
2538             // Can depend only on one version of the same library
2539             List<String> usesStaticLibraries = pkg.getUsesStaticLibraries();
2540             if (usesStaticLibraries.contains(lname)) {
2541                 return input.error(
2542                         "Depending on multiple versions of static library " + lname);
2543             }
2544 
2545             lname = lname.intern();
2546             // We allow ":" delimiters in the SHA declaration as this is the format
2547             // emitted by the certtool making it easy for developers to copy/paste.
2548             certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
2549 
2550             // Fot apps targeting O-MR1 we require explicit enumeration of all certs.
2551             String[] additionalCertSha256Digests = EmptyArray.STRING;
2552             if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) {
2553                 ParseResult<String[]> certResult = parseAdditionalCertificates(input, res, parser);
2554                 if (certResult.isError()) {
2555                     return input.error(certResult);
2556                 }
2557                 additionalCertSha256Digests = certResult.getResult();
2558             }
2559 
2560             final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1];
2561             certSha256Digests[0] = certSha256Digest;
2562             System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests,
2563                     1, additionalCertSha256Digests.length);
2564 
2565             return input.success(pkg.addUsesStaticLibrary(lname, version, certSha256Digests));
2566         } finally {
2567             sa.recycle();
2568         }
2569     }
2570 
2571     @NonNull
2572     private static ParseResult<ParsingPackage> parseUsesLibrary(ParseInput input,
2573             ParsingPackage pkg, Resources res, XmlResourceParser parser) {
2574         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary);
2575         try {
2576             // Note: don't allow this value to be a reference to a resource
2577             // that may change.
2578             String lname = sa.getNonResourceString(R.styleable.AndroidManifestUsesLibrary_name);
2579             boolean req = sa.getBoolean(R.styleable.AndroidManifestUsesLibrary_required, true);
2580 
2581             if (lname != null) {
2582                 lname = lname.intern();
2583                 if (req) {
2584                     // Upgrade to treat as stronger constraint
2585                     pkg.addUsesLibrary(lname)
2586                             .removeUsesOptionalLibrary(lname);
2587                 } else {
2588                     // Ignore if someone already defined as required
2589                     if (!ArrayUtils.contains(pkg.getUsesLibraries(), lname)) {
2590                         pkg.addUsesOptionalLibrary(lname);
2591                     }
2592                 }
2593             }
2594 
2595             return input.success(pkg);
2596         } finally {
2597             sa.recycle();
2598         }
2599     }
2600 
2601     @NonNull
2602     private static ParseResult<ParsingPackage> parseUsesNativeLibrary(ParseInput input,
2603             ParsingPackage pkg, Resources res, XmlResourceParser parser) {
2604         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesNativeLibrary);
2605         try {
2606             // Note: don't allow this value to be a reference to a resource
2607             // that may change.
2608             String lname = sa.getNonResourceString(
2609                     R.styleable.AndroidManifestUsesNativeLibrary_name);
2610             boolean req = sa.getBoolean(R.styleable.AndroidManifestUsesNativeLibrary_required,
2611                     true);
2612 
2613             if (lname != null) {
2614                 if (req) {
2615                     // Upgrade to treat as stronger constraint
2616                     pkg.addUsesNativeLibrary(lname)
2617                             .removeUsesOptionalNativeLibrary(lname);
2618                 } else {
2619                     // Ignore if someone already defined as required
2620                     if (!ArrayUtils.contains(pkg.getUsesNativeLibraries(), lname)) {
2621                         pkg.addUsesOptionalNativeLibrary(lname);
2622                     }
2623                 }
2624             }
2625 
2626             return input.success(pkg);
2627         } finally {
2628             sa.recycle();
2629         }
2630     }
2631 
2632     @NonNull
2633     private static ParseResult<ParsingPackage> parseProcesses(ParseInput input, ParsingPackage pkg,
2634             Resources res, XmlResourceParser parser, String[] separateProcesses, int flags)
2635             throws IOException, XmlPullParserException {
2636         ParseResult<ArrayMap<String, ParsedProcess>> result =
2637                 ParsedProcessUtils.parseProcesses(separateProcesses, pkg, res, parser, flags,
2638                         input);
2639         if (result.isError()) {
2640             return input.error(result);
2641         }
2642 
2643         return input.success(pkg.setProcesses(result.getResult()));
2644     }
2645 
2646     @NonNull
2647     private static ParseResult<ParsingPackage> parseProfileable(ParseInput input,
2648             ParsingPackage pkg, Resources res, XmlResourceParser parser) {
2649         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProfileable);
2650         try {
2651             ParsingPackage newPkg = pkg.setProfileableByShell(pkg.isProfileableByShell()
2652                     || bool(false, R.styleable.AndroidManifestProfileable_shell, sa));
2653             return input.success(newPkg.setProfileable(newPkg.isProfileable()
2654                     && bool(true, R.styleable.AndroidManifestProfileable_enabled, sa)));
2655         } finally {
2656             sa.recycle();
2657         }
2658     }
2659 
2660     private static ParseResult<String[]> parseAdditionalCertificates(ParseInput input,
2661             Resources resources, XmlResourceParser parser)
2662             throws XmlPullParserException, IOException {
2663         String[] certSha256Digests = EmptyArray.STRING;
2664         final int depth = parser.getDepth();
2665         int type;
2666         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2667                 && (type != XmlPullParser.END_TAG
2668                 || parser.getDepth() > depth)) {
2669             if (type != XmlPullParser.START_TAG) {
2670                 continue;
2671             }
2672 
2673             final String nodeName = parser.getName();
2674             if (nodeName.equals("additional-certificate")) {
2675                 TypedArray sa = resources.obtainAttributes(parser,
2676                         R.styleable.AndroidManifestAdditionalCertificate);
2677                 try {
2678                     String certSha256Digest = sa.getNonResourceString(
2679                             R.styleable.AndroidManifestAdditionalCertificate_certDigest);
2680 
2681                     if (TextUtils.isEmpty(certSha256Digest)) {
2682                         return input.error("Bad additional-certificate declaration with empty"
2683                                 + " certDigest:" + certSha256Digest);
2684                     }
2685 
2686 
2687                     // We allow ":" delimiters in the SHA declaration as this is the format
2688                     // emitted by the certtool making it easy for developers to copy/paste.
2689                     certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
2690                     certSha256Digests = ArrayUtils.appendElement(String.class,
2691                             certSha256Digests, certSha256Digest);
2692                 } finally {
2693                     sa.recycle();
2694                 }
2695             }
2696         }
2697 
2698         return input.success(certSha256Digests);
2699     }
2700 
2701     /**
2702      * Generate activity object that forwards user to App Details page automatically.
2703      * This activity should be invisible to user and user should not know or see it.
2704      */
2705     @NonNull
2706     private static ParseResult<ParsedActivity> generateAppDetailsHiddenActivity(ParseInput input,
2707             ParsingPackage pkg) {
2708         String packageName = pkg.getPackageName();
2709         ParseResult<String> result = ComponentParseUtils.buildTaskAffinityName(
2710                 packageName, packageName, ":app_details", input);
2711         if (result.isError()) {
2712             return input.error(result);
2713         }
2714 
2715         String taskAffinity = result.getResult();
2716 
2717         // Build custom App Details activity info instead of parsing it from xml
2718         return input.success(ParsedActivity.makeAppDetailsActivity(packageName,
2719                 pkg.getProcessName(), pkg.getUiOptions(), taskAffinity,
2720                 pkg.isBaseHardwareAccelerated()));
2721     }
2722 
2723     /**
2724      * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
2725      *
2726      * This is distinct from any of the functionality of app links domain verification, and cannot
2727      * be converted to remain backwards compatible. It's possible the presence of this flag does
2728      * not indicate a valid package for domain verification.
2729      */
2730     private static boolean hasDomainURLs(ParsingPackage pkg) {
2731         final List<ParsedActivity> activities = pkg.getActivities();
2732         final int activitiesSize = activities.size();
2733         for (int index = 0; index < activitiesSize; index++) {
2734             ParsedActivity activity = activities.get(index);
2735             List<ParsedIntentInfo> filters = activity.getIntents();
2736             final int filtersSize = filters.size();
2737             for (int filtersIndex = 0; filtersIndex < filtersSize; filtersIndex++) {
2738                 IntentFilter aii = filters.get(filtersIndex).getIntentFilter();
2739                 if (!aii.hasAction(Intent.ACTION_VIEW)) continue;
2740                 if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue;
2741                 if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
2742                         aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
2743                     return true;
2744                 }
2745             }
2746         }
2747         return false;
2748     }
2749 
2750     /**
2751      * Sets the max aspect ratio of every child activity that doesn't already have an aspect
2752      * ratio set.
2753      */
2754     private static void setMaxAspectRatio(ParsingPackage pkg) {
2755         // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater.
2756         // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD.
2757         float maxAspectRatio = pkg.getTargetSdkVersion() < O ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
2758 
2759         float packageMaxAspectRatio = pkg.getMaxAspectRatio();
2760         if (packageMaxAspectRatio != 0) {
2761             // Use the application max aspect ration as default if set.
2762             maxAspectRatio = packageMaxAspectRatio;
2763         } else {
2764             Bundle appMetaData = pkg.getMetaData();
2765             if (appMetaData != null && appMetaData.containsKey(METADATA_MAX_ASPECT_RATIO)) {
2766                 maxAspectRatio = appMetaData.getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio);
2767             }
2768         }
2769 
2770         List<ParsedActivity> activities = pkg.getActivities();
2771         int activitiesSize = activities.size();
2772         for (int index = 0; index < activitiesSize; index++) {
2773             ParsedActivity activity = activities.get(index);
2774             // If the max aspect ratio for the activity has already been set, skip.
2775             if (activity.getMaxAspectRatio() != ASPECT_RATIO_NOT_SET) {
2776                 continue;
2777             }
2778 
2779             // By default we prefer to use a values defined on the activity directly than values
2780             // defined on the application. We do not check the styled attributes on the activity
2781             // as it would have already been set when we processed the activity. We wait to
2782             // process the meta data here since this method is called at the end of processing
2783             // the application and all meta data is guaranteed.
2784             final float activityAspectRatio = activity.getMetaData()
2785                     .getFloat(METADATA_MAX_ASPECT_RATIO, maxAspectRatio);
2786 
2787             ComponentMutateUtils.setMaxAspectRatio(activity, activity.getResizeMode(),
2788                     activityAspectRatio);
2789         }
2790     }
2791 
2792     /**
2793      * Sets the min aspect ratio of every child activity that doesn't already have an aspect
2794      * ratio set.
2795      */
2796     private void setMinAspectRatio(ParsingPackage pkg) {
2797         // Use the application max aspect ration as default if set.
2798         final float minAspectRatio = pkg.getMinAspectRatio();
2799 
2800         List<ParsedActivity> activities = pkg.getActivities();
2801         int activitiesSize = activities.size();
2802         for (int index = 0; index < activitiesSize; index++) {
2803             ParsedActivity activity = activities.get(index);
2804             if (activity.getMinAspectRatio() == ASPECT_RATIO_NOT_SET) {
2805                 ComponentMutateUtils.setMinAspectRatio(activity, activity.getResizeMode(),
2806                         minAspectRatio);
2807             }
2808         }
2809     }
2810 
2811     private void setSupportsSizeChanges(ParsingPackage pkg) {
2812         final Bundle appMetaData = pkg.getMetaData();
2813         final boolean supportsSizeChanges = appMetaData != null
2814                 && appMetaData.getBoolean(METADATA_SUPPORTS_SIZE_CHANGES, false);
2815 
2816         List<ParsedActivity> activities = pkg.getActivities();
2817         int activitiesSize = activities.size();
2818         for (int index = 0; index < activitiesSize; index++) {
2819             ParsedActivity activity = activities.get(index);
2820             if (supportsSizeChanges || activity.getMetaData()
2821                     .getBoolean(METADATA_SUPPORTS_SIZE_CHANGES, false)) {
2822                 ComponentMutateUtils.setSupportsSizeChanges(activity, true);
2823             }
2824         }
2825     }
2826 
2827     private static ParseResult<ParsingPackage> parseOverlay(ParseInput input, ParsingPackage pkg,
2828             Resources res, XmlResourceParser parser) {
2829         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay);
2830         try {
2831             String target = sa.getString(R.styleable.AndroidManifestResourceOverlay_targetPackage);
2832             int priority = anInt(0, R.styleable.AndroidManifestResourceOverlay_priority, sa);
2833 
2834             if (target == null) {
2835                 return input.error("<overlay> does not specify a target package");
2836             } else if (priority < 0 || priority > 9999) {
2837                 return input.error("<overlay> priority must be between 0 and 9999");
2838             }
2839 
2840             // check to see if overlay should be excluded based on system property condition
2841             String propName = sa.getString(
2842                     R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName);
2843             String propValue = sa.getString(
2844                     R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue);
2845             if (!FrameworkParsingPackageUtils.checkRequiredSystemProperties(propName, propValue)) {
2846                 String message = "Skipping target and overlay pair " + target + " and "
2847                         + pkg.getBaseApkPath()
2848                         + ": overlay ignored due to required system property: "
2849                         + propName + " with value: " + propValue;
2850                 Slog.i(TAG, message);
2851                 return input.skip(message);
2852             }
2853 
2854             return input.success(pkg.setOverlay(true)
2855                     .setOverlayTarget(target)
2856                     .setOverlayPriority(priority)
2857                     .setOverlayTargetOverlayableName(
2858                             sa.getString(R.styleable.AndroidManifestResourceOverlay_targetName))
2859                     .setOverlayCategory(
2860                             sa.getString(R.styleable.AndroidManifestResourceOverlay_category))
2861                     .setOverlayIsStatic(
2862                             bool(false, R.styleable.AndroidManifestResourceOverlay_isStatic, sa)));
2863         } finally {
2864             sa.recycle();
2865         }
2866     }
2867 
2868     private static ParseResult<ParsingPackage> parseProtectedBroadcast(ParseInput input,
2869             ParsingPackage pkg, Resources res, XmlResourceParser parser) {
2870         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProtectedBroadcast);
2871         try {
2872             // Note: don't allow this value to be a reference to a resource
2873             // that may change.
2874             String name = nonResString(R.styleable.AndroidManifestProtectedBroadcast_name, sa);
2875             if (name != null) {
2876                 pkg.addProtectedBroadcast(name);
2877             }
2878             return input.success(pkg);
2879         } finally {
2880             sa.recycle();
2881         }
2882     }
2883 
2884     private static ParseResult<ParsingPackage> parseSupportScreens(ParseInput input,
2885             ParsingPackage pkg, Resources res, XmlResourceParser parser) {
2886         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestSupportsScreens);
2887         try {
2888             int requiresSmallestWidthDp = anInt(0,
2889                     R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, sa);
2890             int compatibleWidthLimitDp = anInt(0,
2891                     R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, sa);
2892             int largestWidthLimitDp = anInt(0,
2893                     R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, sa);
2894 
2895             // This is a trick to get a boolean and still able to detect
2896             // if a value was actually set.
2897             return input.success(pkg
2898                     .setSupportsSmallScreens(
2899                             anInt(1, R.styleable.AndroidManifestSupportsScreens_smallScreens, sa))
2900                     .setSupportsNormalScreens(
2901                             anInt(1, R.styleable.AndroidManifestSupportsScreens_normalScreens, sa))
2902                     .setSupportsLargeScreens(
2903                             anInt(1, R.styleable.AndroidManifestSupportsScreens_largeScreens, sa))
2904                     .setSupportsExtraLargeScreens(
2905                             anInt(1, R.styleable.AndroidManifestSupportsScreens_xlargeScreens, sa))
2906                     .setResizeable(
2907                             anInt(1, R.styleable.AndroidManifestSupportsScreens_resizeable, sa))
2908                     .setAnyDensity(
2909                             anInt(1, R.styleable.AndroidManifestSupportsScreens_anyDensity, sa))
2910                     .setRequiresSmallestWidthDp(requiresSmallestWidthDp)
2911                     .setCompatibleWidthLimitDp(compatibleWidthLimitDp)
2912                     .setLargestWidthLimitDp(largestWidthLimitDp));
2913         } finally {
2914             sa.recycle();
2915         }
2916     }
2917 
2918     private static ParseResult<ParsingPackage> parseInstrumentation(ParseInput input,
2919             ParsingPackage pkg, Resources res, XmlResourceParser parser)
2920             throws XmlPullParserException, IOException {
2921         ParseResult<ParsedInstrumentation> result = ParsedInstrumentationUtils.parseInstrumentation(
2922                 pkg, res, parser, sUseRoundIcon, input);
2923         if (result.isError()) {
2924             return input.error(result);
2925         }
2926         return input.success(pkg.addInstrumentation(result.getResult()));
2927     }
2928 
2929     private static ParseResult<ParsingPackage> parseOriginalPackage(ParseInput input,
2930             ParsingPackage pkg, Resources res, XmlResourceParser parser) {
2931         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestOriginalPackage);
2932         try {
2933             String orig = sa.getNonConfigurationString(
2934                     R.styleable.AndroidManifestOriginalPackage_name,
2935                     0);
2936             if (!pkg.getPackageName().equals(orig)) {
2937                 pkg.addOriginalPackage(orig);
2938             }
2939             return input.success(pkg);
2940         } finally {
2941             sa.recycle();
2942         }
2943     }
2944 
2945     private static ParseResult<ParsingPackage> parseAdoptPermissions(ParseInput input,
2946             ParsingPackage pkg, Resources res, XmlResourceParser parser) {
2947         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestOriginalPackage);
2948         try {
2949             String name = nonConfigString(0, R.styleable.AndroidManifestOriginalPackage_name, sa);
2950             if (name != null) {
2951                 pkg.addAdoptPermission(name);
2952             }
2953             return input.success(pkg);
2954         } finally {
2955             sa.recycle();
2956         }
2957     }
2958 
2959     private static void convertCompatPermissions(ParsingPackage pkg) {
2960         for (int i = 0, size = CompatibilityPermissionInfo.COMPAT_PERMS.length; i < size; i++) {
2961             final CompatibilityPermissionInfo info = CompatibilityPermissionInfo.COMPAT_PERMS[i];
2962             if (pkg.getTargetSdkVersion() >= info.getSdkVersion()) {
2963                 break;
2964             }
2965             if (!pkg.getRequestedPermissions().contains(info.getName())) {
2966                 pkg.addImplicitPermission(info.getName());
2967             }
2968         }
2969     }
2970 
2971     private void convertSplitPermissions(ParsingPackage pkg) {
2972         final int listSize = mSplitPermissionInfos.size();
2973         for (int is = 0; is < listSize; is++) {
2974             final PermissionManager.SplitPermissionInfo spi = mSplitPermissionInfos.get(is);
2975             List<String> requestedPermissions = pkg.getRequestedPermissions();
2976             if (pkg.getTargetSdkVersion() >= spi.getTargetSdk()
2977                     || !requestedPermissions.contains(spi.getSplitPermission())) {
2978                 continue;
2979             }
2980             final List<String> newPerms = spi.getNewPermissions();
2981             for (int in = 0; in < newPerms.size(); in++) {
2982                 final String perm = newPerms.get(in);
2983                 if (!requestedPermissions.contains(perm)) {
2984                     pkg.addImplicitPermission(perm);
2985                 }
2986             }
2987         }
2988     }
2989 
2990     /**
2991      * This is a pre-density application which will get scaled - instead of being pixel perfect.
2992      * This type of application is not resizable.
2993      *
2994      * @param pkg The package which needs to be marked as unresizable.
2995      */
2996     private static void adjustPackageToBeUnresizeableAndUnpipable(ParsingPackage pkg) {
2997         List<ParsedActivity> activities = pkg.getActivities();
2998         int activitiesSize = activities.size();
2999         for (int index = 0; index < activitiesSize; index++) {
3000             ParsedActivity activity = activities.get(index);
3001             ComponentMutateUtils.setResizeMode(activity, RESIZE_MODE_UNRESIZEABLE);
3002             ComponentMutateUtils.setExactFlags(activity,
3003                     activity.getFlags() & ~FLAG_SUPPORTS_PICTURE_IN_PICTURE);
3004         }
3005     }
3006 
3007     /**
3008      * Parse a meta data defined on the enclosing tag.
3009      * <p>Meta data can be defined by either &lt;meta-data&gt; or &lt;property&gt; elements.
3010      */
3011     public static ParseResult<Property> parseMetaData(ParsingPackage pkg, ParsedComponent component,
3012             Resources res, XmlResourceParser parser, String tagName, ParseInput input) {
3013         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestMetaData);
3014         try {
3015             final Property property;
3016             final String name = TextUtils.safeIntern(
3017                     nonConfigString(0, R.styleable.AndroidManifestMetaData_name, sa));
3018             if (name == null) {
3019                 return input.error(tagName + " requires an android:name attribute");
3020             }
3021 
3022             final String packageName = pkg.getPackageName();
3023             final String className = component != null ? component.getName() : null;
3024             TypedValue v = sa.peekValue(R.styleable.AndroidManifestMetaData_resource);
3025             if (v != null && v.resourceId != 0) {
3026                 property = new Property(name, v.resourceId, true, packageName, className);
3027             } else {
3028                 v = sa.peekValue(R.styleable.AndroidManifestMetaData_value);
3029                 if (v != null) {
3030                     if (v.type == TypedValue.TYPE_STRING) {
3031                         final CharSequence cs = v.coerceToString();
3032                         final String stringValue = cs != null ? cs.toString() : null;
3033                         property = new Property(name, stringValue, packageName, className);
3034                     } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
3035                         property = new Property(name, v.data != 0, packageName, className);
3036                     } else if (v.type >= TypedValue.TYPE_FIRST_INT
3037                             && v.type <= TypedValue.TYPE_LAST_INT) {
3038                         property = new Property(name, v.data, false, packageName, className);
3039                     } else if (v.type == TypedValue.TYPE_FLOAT) {
3040                         property = new Property(name, v.getFloat(), packageName, className);
3041                     } else {
3042                         if (!RIGID_PARSER) {
3043                             Slog.w(TAG,
3044                                     tagName + " only supports string, integer, float, color, "
3045                                             + "boolean, and resource reference types: "
3046                                             + parser.getName() + " at "
3047                                             + pkg.getBaseApkPath() + " "
3048                                             + parser.getPositionDescription());
3049                             property = null;
3050                         } else {
3051                             return input.error(tagName + " only supports string, integer, float, "
3052                                     + "color, boolean, and resource reference types");
3053                         }
3054                     }
3055                 } else {
3056                     return input.error(tagName + " requires an android:value "
3057                             + "or android:resource attribute");
3058                 }
3059             }
3060             return input.success(property);
3061         } finally {
3062             sa.recycle();
3063         }
3064     }
3065 
3066     /**
3067      * Collect certificates from all the APKs described in the given package. Also asserts that
3068      * all APK contents are signed correctly and consistently.
3069      *
3070      * TODO(b/155513789): Remove this in favor of collecting certificates during the original parse
3071      *  call if requested. Leaving this as an optional method for the caller means we have to
3072      *  construct a dummy ParseInput.
3073      */
3074     @CheckResult
3075     public static ParseResult<SigningDetails> getSigningDetails(ParseInput input,
3076             ParsingPackageRead pkg, boolean skipVerify) {
3077         SigningDetails signingDetails = SigningDetails.UNKNOWN;
3078 
3079         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
3080         try {
3081             ParseResult<SigningDetails> result = getSigningDetails(
3082                     input,
3083                     pkg.getBaseApkPath(),
3084                     skipVerify,
3085                     pkg.isStaticSharedLibrary(),
3086                     signingDetails,
3087                     pkg.getTargetSdkVersion()
3088             );
3089             if (result.isError()) {
3090                 return input.error(result);
3091             }
3092 
3093             signingDetails = result.getResult();
3094             final File frameworkRes = new File(Environment.getRootDirectory(),
3095                     "framework/framework-res.apk");
3096             boolean isFrameworkResSplit = frameworkRes.getAbsolutePath()
3097                     .equals(pkg.getBaseApkPath());
3098             String[] splitCodePaths = pkg.getSplitCodePaths();
3099             if (!ArrayUtils.isEmpty(splitCodePaths) && !isFrameworkResSplit) {
3100                 for (int i = 0; i < splitCodePaths.length; i++) {
3101                     result = getSigningDetails(
3102                             input,
3103                             splitCodePaths[i],
3104                             skipVerify,
3105                             pkg.isStaticSharedLibrary(),
3106                             signingDetails,
3107                             pkg.getTargetSdkVersion()
3108                     );
3109                     if (result.isError()) {
3110                         return input.error(result);
3111                     }
3112                 }
3113             }
3114             return result;
3115         } finally {
3116             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
3117         }
3118     }
3119 
3120     @CheckResult
3121     public static ParseResult<SigningDetails> getSigningDetails(ParseInput input,
3122             String baseCodePath, boolean skipVerify, boolean isStaticSharedLibrary,
3123             @NonNull SigningDetails existingSigningDetails, int targetSdk) {
3124         int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
3125                 targetSdk);
3126         if (isStaticSharedLibrary) {
3127             // must use v2 signing scheme
3128             minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
3129         }
3130         final ParseResult<SigningDetails> verified;
3131         if (skipVerify) {
3132             // systemDir APKs are already trusted, save time by not verifying
3133             verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(input, baseCodePath,
3134                     minSignatureScheme);
3135         } else {
3136             verified = ApkSignatureVerifier.verify(input, baseCodePath, minSignatureScheme);
3137         }
3138 
3139         if (verified.isError()) {
3140             return input.error(verified);
3141         }
3142 
3143         // Verify that entries are signed consistently with the first pkg
3144         // we encountered. Note that for splits, certificates may have
3145         // already been populated during an earlier parse of a base APK.
3146         if (existingSigningDetails == SigningDetails.UNKNOWN) {
3147             return verified;
3148         } else {
3149             if (!Signature.areExactMatch(existingSigningDetails.getSignatures(),
3150                     verified.getResult().getSignatures())) {
3151                 return input.error(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
3152                         baseCodePath + " has mismatched certificates");
3153             }
3154 
3155             return input.success(existingSigningDetails);
3156         }
3157     }
3158 
3159     /**
3160      * @hide
3161      */
3162     public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
3163         sCompatibilityModeEnabled = compatibilityModeEnabled;
3164     }
3165 
3166     /**
3167      * @hide
3168      */
3169     public static void readConfigUseRoundIcon(Resources r) {
3170         if (r != null) {
3171             sUseRoundIcon = r.getBoolean(com.android.internal.R.bool.config_useRoundIcon);
3172             return;
3173         }
3174 
3175         final ApplicationInfo androidAppInfo;
3176         try {
3177             androidAppInfo = ActivityThread.getPackageManager().getApplicationInfo(
3178                     "android", 0 /* flags */,
3179                     UserHandle.myUserId());
3180         } catch (RemoteException e) {
3181             throw e.rethrowFromSystemServer();
3182         }
3183         final Resources systemResources = Resources.getSystem();
3184 
3185         // Create in-flight as this overlayable resource is only used when config changes
3186         final Resources overlayableRes = ResourcesManager.getInstance().getResources(
3187                 null /* activityToken */,
3188                 null /* resDir */,
3189                 null /* splitResDirs */,
3190                 androidAppInfo.resourceDirs,
3191                 androidAppInfo.overlayPaths,
3192                 androidAppInfo.sharedLibraryFiles,
3193                 null /* overrideDisplayId */,
3194                 null /* overrideConfig */,
3195                 systemResources.getCompatibilityInfo(),
3196                 systemResources.getClassLoader(),
3197                 null /* loaders */);
3198 
3199         sUseRoundIcon = overlayableRes.getBoolean(com.android.internal.R.bool.config_useRoundIcon);
3200     }
3201 
3202     /*
3203      The following set of methods makes code easier to read by re-ordering the TypedArray methods.
3204 
3205      The first parameter is the default, which is the most important to understand for someone
3206      reading through the parsing code.
3207 
3208      That's followed by the attribute name, which is usually irrelevant during reading because
3209      it'll look like setSomeValue(true, R.styleable.ReallyLongParentName_SomeValueAttr... and
3210      the "setSomeValue" part is enough to communicate what the line does.
3211 
3212      Last comes the TypedArray, which is by far the least important since each try-with-resources
3213      should only have 1.
3214     */
3215 
3216     // Note there is no variant of bool without a defaultValue parameter, since explicit true/false
3217     // is important to specify when adding an attribute.
3218     private static boolean bool(boolean defaultValue, @StyleableRes int attribute, TypedArray sa) {
3219         return sa.getBoolean(attribute, defaultValue);
3220     }
3221 
3222     private static float aFloat(float defaultValue, @StyleableRes int attribute, TypedArray sa) {
3223         return sa.getFloat(attribute, defaultValue);
3224     }
3225 
3226     private static float aFloat(@StyleableRes int attribute, TypedArray sa) {
3227         return sa.getFloat(attribute, 0f);
3228     }
3229 
3230     private static int anInt(int defaultValue, @StyleableRes int attribute, TypedArray sa) {
3231         return sa.getInt(attribute, defaultValue);
3232     }
3233 
3234     private static int anInteger(int defaultValue, @StyleableRes int attribute, TypedArray sa) {
3235         return sa.getInteger(attribute, defaultValue);
3236     }
3237 
3238     private static int anInt(@StyleableRes int attribute, TypedArray sa) {
3239         return sa.getInt(attribute, 0);
3240     }
3241 
3242     @AnyRes
3243     private static int resId(@StyleableRes int attribute, TypedArray sa) {
3244         return sa.getResourceId(attribute, 0);
3245     }
3246 
3247     private static String string(@StyleableRes int attribute, TypedArray sa) {
3248         return sa.getString(attribute);
3249     }
3250 
3251     private static String nonConfigString(int allowedChangingConfigs, @StyleableRes int attribute,
3252             TypedArray sa) {
3253         return sa.getNonConfigurationString(attribute, allowedChangingConfigs);
3254     }
3255 
3256     private static String nonResString(@StyleableRes int index, TypedArray sa) {
3257         return sa.getNonResourceString(index);
3258     }
3259 
3260     /**
3261      * Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
3262      */
3263     public static void writeKeySetMapping(@NonNull Parcel dest,
3264             @NonNull Map<String, ArraySet<PublicKey>> keySetMapping) {
3265         if (keySetMapping == null) {
3266             dest.writeInt(-1);
3267             return;
3268         }
3269 
3270         final int N = keySetMapping.size();
3271         dest.writeInt(N);
3272 
3273         for (String key : keySetMapping.keySet()) {
3274             dest.writeString(key);
3275             ArraySet<PublicKey> keys = keySetMapping.get(key);
3276             if (keys == null) {
3277                 dest.writeInt(-1);
3278                 continue;
3279             }
3280 
3281             final int M = keys.size();
3282             dest.writeInt(M);
3283             for (int j = 0; j < M; j++) {
3284                 dest.writeSerializable(keys.valueAt(j));
3285             }
3286         }
3287     }
3288 
3289     /**
3290      * Reads a keyset mapping from the given parcel at the given data position. May return
3291      * {@code null} if the serialized mapping was {@code null}.
3292      */
3293     @NonNull
3294     public static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(@NonNull Parcel in) {
3295         final int N = in.readInt();
3296         if (N == -1) {
3297             return null;
3298         }
3299 
3300         ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>();
3301         for (int i = 0; i < N; ++i) {
3302             String key = in.readString();
3303             final int M = in.readInt();
3304             if (M == -1) {
3305                 keySetMapping.put(key, null);
3306                 continue;
3307             }
3308 
3309             ArraySet<PublicKey> keys = new ArraySet<>(M);
3310             for (int j = 0; j < M; ++j) {
3311                 PublicKey pk = (PublicKey) in.readSerializable();
3312                 keys.add(pk);
3313             }
3314 
3315             keySetMapping.put(key, keys);
3316         }
3317 
3318         return keySetMapping;
3319     }
3320 
3321 
3322     /**
3323      * Callback interface for retrieving information that may be needed while parsing
3324      * a package.
3325      */
3326     public interface Callback {
3327         boolean hasFeature(String feature);
3328 
3329         ParsingPackage startParsingPackage(@NonNull String packageName,
3330                 @NonNull String baseApkPath, @NonNull String path,
3331                 @NonNull TypedArray manifestArray, boolean isCoreApp);
3332     }
3333 }
3334