From dfd7a656b5c82dce2966c6ba018c4d24cf4872ef Mon Sep 17 00:00:00 2001 From: Jackal Guo Date: Thu, 29 Jul 2021 13:54:13 +0800 Subject: [PATCH] Fail install if required split type is missing An application can declare that it must be installed with a specific split types using the manifest attribute "android:requiredSplitTypes". Listing the required split types in this attribute, the application can't be installed without these split types. Bug: 189882156 Test: atest android.appsecurity.cts.SplitTests Test: atest android.appsecurity.cts.IsolatedSplitsTests Change-Id: Icf6cde57596fe0fdf9764ef0f1a3812da16ec5ff --- core/api/current.txt | 2 + .../android/content/pm/parsing/ApkLite.java | 57 +++++++++++--- .../content/pm/parsing/ApkLiteParseUtils.java | 75 +++++++++++++++++-- .../content/pm/parsing/PackageLite.java | 57 ++++++++++++-- .../pm/parsing/ParsingPackageUtils.java | 2 +- core/res/res/values/attrs_manifest.xml | 18 +++++ core/res/res/values/public.xml | 2 + .../server/pm/PackageInstallerSession.java | 19 ++++- .../server/pm/PackageManagerShellCommand.java | 8 +- .../server/pm/dex/DexMetadataHelperTest.java | 7 +- 10 files changed, 217 insertions(+), 30 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index e4e5a1acc420e..fd8abf17f3018 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -1194,6 +1194,7 @@ package android { field public static final int requiredFeature = 16844116; // 0x1010554 field public static final int requiredForAllUsers = 16843728; // 0x10103d0 field public static final int requiredNotFeature = 16844117; // 0x1010555 + field public static final int requiredSplitTypes; field public static final int requiresFadingEdge = 16843685; // 0x10103a5 field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364 field public static final int resizeClip = 16843983; // 0x10104cf @@ -1329,6 +1330,7 @@ package android { field public static final int splitMotionEvents = 16843503; // 0x10102ef field public static final int splitName = 16844105; // 0x1010549 field public static final int splitTrack = 16843852; // 0x101044c + field public static final int splitTypes; field public static final int spotShadowAlpha = 16843967; // 0x10104bf field public static final int src = 16843033; // 0x1010119 field public static final int ssp = 16843747; // 0x10103e3 diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java index 024c18c30d37f..49d413702f9c7 100644 --- a/core/java/android/content/pm/parsing/ApkLite.java +++ b/core/java/android/content/pm/parsing/ApkLite.java @@ -19,12 +19,15 @@ package android.content.pm.parsing; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.content.pm.SigningDetails; import android.content.pm.VerifierInfo; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.DataClass; import java.util.List; +import java.util.Set; /** * Lightweight parsed details about a single APK file. @@ -44,6 +47,10 @@ public class ApkLite { private final @Nullable String mUsesSplitName; /** Name of the split APK that this APK is a configuration for */ private final @Nullable String mConfigForSplit; + /** Indicate the types of the required split are necessary for this package to run */ + private final @Nullable Set mRequiredSplitTypes; + /** Split types of this APK */ + private final @Nullable Set mSplitTypes; /** Major version number of this package */ private final int mVersionCodeMajor; @@ -105,9 +112,9 @@ public class ApkLite { /** * Indicate the policy to deal with user data when rollback is committed * - * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RESTORE} - * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#WIPE} - * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RETAIN} + * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RESTORE} + * @see {@link PackageManager#ROLLBACK_DATA_POLICY_WIPE} + * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RETAIN} */ private final int mRollbackDataPolicy; @@ -118,14 +125,17 @@ public class ApkLite { boolean debuggable, boolean profileableByShell, boolean multiArch, boolean use32bitAbi, boolean useEmbeddedDex, boolean extractNativeLibs, boolean isolatedSplits, String targetPackageName, boolean overlayIsStatic, int overlayPriority, - int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy) { + int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy, + Set requiredSplitTypes, Set splitTypes) { mPath = path; mPackageName = packageName; mSplitName = splitName; + mSplitTypes = splitTypes; mFeatureSplit = isFeatureSplit; mConfigForSplit = configForSplit; mUsesSplitName = usesSplitName; - mSplitRequired = isSplitRequired; + mRequiredSplitTypes = requiredSplitTypes; + mSplitRequired = (isSplitRequired || hasAnyRequiredSplitTypes()); mVersionCode = versionCode; mVersionCodeMajor = versionCodeMajor; mRevisionCode = revisionCode; @@ -156,9 +166,16 @@ public class ApkLite { return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode); } + /** + * Return if requiredSplitTypes presents. + */ + private boolean hasAnyRequiredSplitTypes() { + return !CollectionUtils.isEmpty(mRequiredSplitTypes); + } - // Code below generated by codegen v1.0.22. + + // Code below generated by codegen v1.0.23. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -211,6 +228,22 @@ public class ApkLite { return mConfigForSplit; } + /** + * Indicate the types of the required split are necessary for this package to run + */ + @DataClass.Generated.Member + public @Nullable Set getRequiredSplitTypes() { + return mRequiredSplitTypes; + } + + /** + * Split types of this APK + */ + @DataClass.Generated.Member + public @Nullable Set getSplitTypes() { + return mSplitTypes; + } + /** * Major version number of this package */ @@ -388,9 +421,9 @@ public class ApkLite { /** * Indicate the policy to deal with user data when rollback is committed * - * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RESTORE} - * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#WIPE} - * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RETAIN} + * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RESTORE} + * @see {@link PackageManager#ROLLBACK_DATA_POLICY_WIPE} + * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RETAIN} */ @DataClass.Generated.Member public int getRollbackDataPolicy() { @@ -398,10 +431,10 @@ public class ApkLite { } @DataClass.Generated( - time = 1616985847981L, - codegenVersion = "1.0.22", + time = 1628562554893L, + codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java", - inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final int mRollbackDataPolicy\npublic long getLongVersionCode()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") + inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final int mRollbackDataPolicy\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index f727a4869208f..d3b6f2b83553e 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -38,6 +38,7 @@ import android.content.res.XmlResourceParser; import android.os.Trace; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.AttributeSet; import android.util.Pair; import android.util.Slog; @@ -58,6 +59,7 @@ import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Objects; +import java.util.Set; /** @hide */ public class ApkLiteParseUtils { @@ -104,8 +106,11 @@ public class ApkLiteParseUtils { final ApkLite baseApk = result.getResult(); final String packagePath = packageFile.getAbsolutePath(); return input.success( - new PackageLite(packagePath, baseApk.getPath(), baseApk, null, - null, null, null, null, null, baseApk.getTargetSdkVersion())); + new PackageLite(packagePath, baseApk.getPath(), baseApk, null /* splitNames */, + null /* isFeatureSplits */, null /* usesSplitNames */, + null /* configForSplit */, null /* splitApkPaths */, + null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(), + null /* requiredSplitTypes */, null /* splitTypes */)); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } @@ -209,6 +214,8 @@ public class ApkLiteParseUtils { final int size = ArrayUtils.size(splitApks); String[] splitNames = null; + Set[] requiredSplitTypes = null; + Set[] splitTypes = null; boolean[] isFeatureSplits = null; String[] usesSplitNames = null; String[] configForSplits = null; @@ -216,6 +223,8 @@ public class ApkLiteParseUtils { int[] splitRevisionCodes = null; if (size > 0) { splitNames = new String[size]; + requiredSplitTypes = new Set[size]; + splitTypes = new Set[size]; isFeatureSplits = new boolean[size]; usesSplitNames = new String[size]; configForSplits = new String[size]; @@ -227,6 +236,8 @@ public class ApkLiteParseUtils { for (int i = 0; i < size; i++) { final ApkLite apk = splitApks.get(splitNames[i]); + requiredSplitTypes[i] = apk.getRequiredSplitTypes(); + splitTypes[i] = apk.getSplitTypes(); usesSplitNames[i] = apk.getUsesSplitName(); isFeatureSplits[i] = apk.isFeatureSplit(); configForSplits[i] = apk.getConfigForSplit(); @@ -242,7 +253,7 @@ public class ApkLiteParseUtils { return input.success( new PackageLite(codePath, baseCodePath, baseApk, splitNames, isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes, - baseApk.getTargetSdkVersion())); + baseApk.getTargetSdkVersion(), requiredSplitTypes, splitTypes)); } /** @@ -345,9 +356,15 @@ public class ApkLiteParseUtils { if (result.isError()) { return input.error(result); } - Pair packageSplit = result.getResult(); + final ParseResult, Set>> requiredSplitTypesResult = + parseRequiredSplitTypes(input, parser); + if (requiredSplitTypesResult.isError()) { + return input.error(result); + } + Pair, Set> requiredSplitTypes = requiredSplitTypesResult.getResult(); + int installLocation = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "installLocation", PARSE_DEFAULT_INSTALL_LOCATION); int versionCode = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "versionCode", 0); @@ -522,7 +539,7 @@ public class ApkLiteParseUtils { coreApp, debuggable, profilableByShell, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs, isolatedSplits, targetPackage, overlayIsStatic, overlayPriority, minSdkVersion, targetSdkVersion, - rollbackDataPolicy)); + rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second)); } public static ParseResult> parsePackageSplitNames(ParseInput input, @@ -567,6 +584,54 @@ public class ApkLiteParseUtils { (splitName != null) ? splitName.intern() : splitName)); } + /** + * Utility method that parses attributes android:requiredSplitTypes and android:splitTypes. + */ + public static ParseResult, Set>> parseRequiredSplitTypes( + ParseInput input, XmlResourceParser parser) { + Set requiredSplitTypes = null; + Set splitTypes = null; + String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "requiredSplitTypes"); + if (!TextUtils.isEmpty(value)) { + final ParseResult> result = separateAndValidateSplitTypes(input, value); + if (result.isError()) { + return input.error(result); + } + requiredSplitTypes = result.getResult(); + } + + value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "splitTypes"); + if (!TextUtils.isEmpty(value)) { + final ParseResult> result = separateAndValidateSplitTypes(input, value); + if (result.isError()) { + return input.error(result); + } + splitTypes = result.getResult(); + } + + return input.success(Pair.create(requiredSplitTypes, splitTypes)); + } + + private static ParseResult> separateAndValidateSplitTypes(ParseInput input, + String values) { + final Set ret = new ArraySet<>(); + for (String value : values.trim().split(",")) { + final String type = value.trim(); + // Using requireFilename as true because it limits length of the name to the + // {@link #MAX_FILE_NAME_SIZE}. + final ParseResult nameResult = validateName(input, type, + false /* requireSeparator */, true /* requireFilename */); + if (nameResult.isError()) { + return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Invalid manifest split types: " + nameResult.getErrorMessage()); + } + if (!ret.add(type)) { + Slog.w(TAG, type + " was defined multiple times"); + } + } + return input.success(ret); + } + public static VerifierInfo parseVerifier(AttributeSet attrs) { String packageName = attrs.getAttributeValue(ANDROID_RES_NAMESPACE, "name"); String encodedPublicKey = attrs.getAttributeValue(ANDROID_RES_NAMESPACE, "publicKey"); diff --git a/core/java/android/content/pm/parsing/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java index 9172555bfcd33..5f5e81253b313 100644 --- a/core/java/android/content/pm/parsing/PackageLite.java +++ b/core/java/android/content/pm/parsing/PackageLite.java @@ -22,11 +22,13 @@ import android.content.pm.PackageInfo; import android.content.pm.VerifierInfo; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.DataClass; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; /** * Lightweight parsed details about a single package. @@ -52,6 +54,12 @@ public class PackageLite { /** Dependencies of any split APKs, ordered by parsed splitName */ private final @Nullable String[] mUsesSplitNames; private final @Nullable String[] mConfigForSplit; + /** Indicate the types of the required split are necessary for base APK to run */ + private final @Nullable Set mBaseRequiredSplitTypes; + /** Indicate the types of the required split are necessary for split APKs to run */ + private final @Nullable Set[] mRequiredSplitTypes; + /** Split type of any split APKs, ordered by parsed splitName */ + private final @Nullable Set[] mSplitTypes; /** Major and minor version number of this package */ private final int mVersionCodeMajor; private final int mVersionCode; @@ -101,7 +109,7 @@ public class PackageLite { public PackageLite(String path, String baseApkPath, ApkLite baseApk, String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit, String[] splitApkPaths, int[] splitRevisionCodes, - int targetSdk) { + int targetSdk, Set[] requiredSplitTypes, Set[] splitTypes) { // The following paths may be different from the path in ApkLite because we // move or rename the APK files. Use parameters to indicate the correct paths. mPath = path; @@ -119,9 +127,12 @@ public class PackageLite { mExtractNativeLibs = baseApk.isExtractNativeLibs(); mIsolatedSplits = baseApk.isIsolatedSplits(); mUseEmbeddedDex = baseApk.isUseEmbeddedDex(); - mSplitRequired = baseApk.isSplitRequired(); + mBaseRequiredSplitTypes = baseApk.getRequiredSplitTypes(); + mRequiredSplitTypes = requiredSplitTypes; + mSplitRequired = (baseApk.isSplitRequired() || hasAnyRequiredSplitTypes()); mProfileableByShell = baseApk.isProfileableByShell(); mSplitNames = splitNames; + mSplitTypes = splitTypes; mIsFeatureSplits = isFeatureSplits; mUsesSplitNames = usesSplitNames; mConfigForSplit = configForSplit; @@ -150,9 +161,19 @@ public class PackageLite { return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode); } + /** + * Return if requiredSplitTypes presents in the package. + */ + private boolean hasAnyRequiredSplitTypes() { + if (!CollectionUtils.isEmpty(mBaseRequiredSplitTypes)) { + return true; + } + return ArrayUtils.find(mRequiredSplitTypes, r -> !CollectionUtils.isEmpty(r)) != null; + } - // Code below generated by codegen v1.0.22. + + // Code below generated by codegen v1.0.23. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -220,6 +241,30 @@ public class PackageLite { return mConfigForSplit; } + /** + * Indicate the types of the required split are necessary for base APK to run + */ + @DataClass.Generated.Member + public @Nullable Set getBaseRequiredSplitTypes() { + return mBaseRequiredSplitTypes; + } + + /** + * Indicate the types of the required split are necessary for split APKs to run + */ + @DataClass.Generated.Member + public @Nullable Set[] getRequiredSplitTypes() { + return mRequiredSplitTypes; + } + + /** + * Split type of any split APKs, ordered by parsed splitName + */ + @DataClass.Generated.Member + public @Nullable Set[] getSplitTypes() { + return mSplitTypes; + } + /** * Major and minor version number of this package */ @@ -357,10 +402,10 @@ public class PackageLite { } @DataClass.Generated( - time = 1615914120261L, - codegenVersion = "1.0.22", + time = 1628562559343L, + codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java", - inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\npublic java.util.List getAllApkPaths()\npublic long getLongVersionCode()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") + inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\npublic java.util.List getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index 80befcdf02de5..b9348a160e59f 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -234,7 +234,7 @@ public class ParsingPackageUtils { * For those names would be used as a part of the file name. Limits size to 223 and reserves 32 * for the OS. */ - private static final int MAX_FILE_NAME_SIZE = 223; + static final int MAX_FILE_NAME_SIZE = 223; /** * @see #parseDefault(ParseInput, File, int, List, boolean) diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index cbf35f4a080d9..c9df3ff2b49e0 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1224,6 +1224,22 @@ resource] to be present in order to function. Default value is false. --> + + + + + +