Merge "Fail install if required split type is missing"

This commit is contained in:
Jackal Guo
2021-08-30 08:34:52 +00:00
committed by Android (Google) Code Review
10 changed files with 217 additions and 30 deletions

View File

@@ -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

View File

@@ -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<String> mRequiredSplitTypes;
/** Split types of this APK */
private final @Nullable Set<String> 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<String> requiredSplitTypes, Set<String> 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<String> getRequiredSplitTypes() {
return mRequiredSplitTypes;
}
/**
* Split types of this APK
*/
@DataClass.Generated.Member
public @Nullable Set<String> 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<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> 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() {}

View File

@@ -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<String>[] requiredSplitTypes = null;
Set<String>[] 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<String, String> packageSplit = result.getResult();
final ParseResult<Pair<Set<String>, Set<String>>> requiredSplitTypesResult =
parseRequiredSplitTypes(input, parser);
if (requiredSplitTypesResult.isError()) {
return input.error(result);
}
Pair<Set<String>, Set<String>> 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<Pair<String, String>> 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<Pair<Set<String>, Set<String>>> parseRequiredSplitTypes(
ParseInput input, XmlResourceParser parser) {
Set<String> requiredSplitTypes = null;
Set<String> splitTypes = null;
String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "requiredSplitTypes");
if (!TextUtils.isEmpty(value)) {
final ParseResult<Set<String>> 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<Set<String>> result = separateAndValidateSplitTypes(input, value);
if (result.isError()) {
return input.error(result);
}
splitTypes = result.getResult();
}
return input.success(Pair.create(requiredSplitTypes, splitTypes));
}
private static ParseResult<Set<String>> separateAndValidateSplitTypes(ParseInput input,
String values) {
final Set<String> 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");

View File

@@ -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<String> mBaseRequiredSplitTypes;
/** Indicate the types of the required split are necessary for split APKs to run */
private final @Nullable Set<String>[] mRequiredSplitTypes;
/** Split type of any split APKs, ordered by parsed splitName */
private final @Nullable Set<String>[] 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<String>[] requiredSplitTypes, Set<String>[] 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<String> getBaseRequiredSplitTypes() {
return mBaseRequiredSplitTypes;
}
/**
* Indicate the types of the required split are necessary for split APKs to run
*/
@DataClass.Generated.Member
public @Nullable Set<String>[] getRequiredSplitTypes() {
return mRequiredSplitTypes;
}
/**
* Split type of any split APKs, ordered by parsed splitName
*/
@DataClass.Generated.Member
public @Nullable Set<String>[] 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<java.lang.String> 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<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] 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<java.lang.String> 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() {}

View File

@@ -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)

View File

@@ -1224,6 +1224,22 @@
resource] to be present in order to function. Default value is false. -->
<attr name="isSplitRequired" format="boolean" />
<!-- List of split types required by this APK to be present in order to function properly,
separated by commas. The platform will reject installation of an app that is missing
any required split types. Each split type is an arbitrary string that has no specific
meaning to the platform, and is only used for matching <code>splitTypes</code> and
<code>requiredSplitTypes</code>. As an example, if a split requires strings, drawables,
and native code this value could be "language,density,abi". Default value is null to
indicate no split types are required. -->
<attr name="requiredSplitTypes" format="string" />
<!-- List of split types offered by this APK, separated by commas. Each split type is an
arbitrary string that has no specific meaning to the platform, and is only used for
matching <code>splitTypes</code> and <code>requiredSplitTypes</code>. As an example,
if a split offers strings and drawables the value could be "language,density". Default
value is null to indicate no split types are offered. -->
<attr name="splitTypes" format="string" />
<!-- Flag to specify if this app wants to run the dex within its APK but not extracted or
locally compiled variants. This keeps the dex code protected by the APK signature. Such
apps will always run in JIT mode (same when they are first installed), and the system will
@@ -1664,6 +1680,8 @@
<attr name="compileSdkVersion" />
<attr name="compileSdkVersionCodename" />
<attr name="isSplitRequired" />
<attr name="requiredSplitTypes" />
<attr name="splitTypes" />
</declare-styleable>
<!-- The <code>application</code> tag describes application-level components

View File

@@ -3299,6 +3299,8 @@
<staging-public-group type="attr" first-id="0x01df0000">
<public name="sharedUserMaxSdkVersion" />
<public name="requiredSplitTypes" />
<public name="splitTypes" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01de0000">

View File

@@ -144,6 +144,7 @@ import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.os.SomeArgs;
import com.android.internal.security.VerityUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -2983,6 +2984,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Verify that all staged packages are internally consistent
final ArraySet<String> stagedSplits = new ArraySet<>();
final ArraySet<String> stagedSplitTypes = new ArraySet<>();
final ArraySet<String> requiredSplitTypes = new ArraySet<>();
final ArrayMap<String, ApkLite> splitApks = new ArrayMap<>();
final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
for (File addedFile : addedFiles) {
@@ -3038,6 +3041,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
} else {
splitApks.put(apk.getSplitName(), apk);
}
// Collect the requiredSplitTypes and staged splitTypes
CollectionUtils.addAll(requiredSplitTypes, apk.getRequiredSplitTypes());
CollectionUtils.addAll(stagedSplitTypes, apk.getSplitTypes());
}
if (removeSplitList.size() > 0) {
@@ -3092,7 +3099,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Full install must include a base package");
}
if (baseApk.isSplitRequired() && stagedSplits.size() <= 1) {
if (baseApk.isSplitRequired() && (stagedSplits.size() <= 1
|| !stagedSplitTypes.containsAll(requiredSplitTypes))) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
"Missing split for " + mPackageName);
}
@@ -3130,6 +3138,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (mResolvedBaseFile == null) {
mResolvedBaseFile = new File(appInfo.getBaseCodePath());
inheritFileLocked(mResolvedBaseFile);
// Collect the requiredSplitTypes from base
CollectionUtils.addAll(requiredSplitTypes, existing.getBaseRequiredSplitTypes());
}
// Inherit splits if not overridden.
@@ -3140,6 +3150,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final boolean splitRemoved = removeSplitList.contains(splitName);
if (!stagedSplits.contains(splitName) && !splitRemoved) {
inheritFileLocked(splitFile);
// Collect the requiredSplitTypes and staged splitTypes from splits
CollectionUtils.addAll(requiredSplitTypes,
existing.getRequiredSplitTypes()[i]);
CollectionUtils.addAll(stagedSplitTypes, existing.getSplitTypes()[i]);
}
}
}
@@ -3221,7 +3235,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final boolean allSplitsRemoved = (existingSplits == removeSplitList.size());
final boolean onlyBaseFileStaged = (stagedSplits.size() == 1
&& stagedSplits.contains(null));
if (allSplitsRemoved && (stagedSplits.isEmpty() || onlyBaseFileStaged)) {
if ((allSplitsRemoved && (stagedSplits.isEmpty() || onlyBaseFileStaged))
|| !stagedSplitTypes.containsAll(requiredSplitTypes)) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
"Missing split for " + mPackageName);
}

View File

@@ -581,8 +581,12 @@ class PackageManagerShellCommand extends ShellCommand {
apkLiteResult.getException());
}
final ApkLite apkLite = apkLiteResult.getResult();
final PackageLite pkgLite = new PackageLite(null, apkLite.getPath(), apkLite, null,
null, null, null, null, null, apkLite.getTargetSdkVersion());
final PackageLite pkgLite = new PackageLite(null, apkLite.getPath(), apkLite,
null /* splitNames */, null /* isFeatureSplits */,
null /* usesSplitNames */, null /* configForSplit */,
null /* splitApkPaths */, null /* splitRevisionCodes */,
apkLite.getTargetSdkVersion(), null /* requiredSplitTypes */,
null /* splitTypes */);
sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
params.sessionParams.abiOverride, fd.getFileDescriptor());
} catch (IOException e) {

View File

@@ -416,8 +416,11 @@ public class DexMetadataHelperTest {
result.getErrorMessage(), result.getException());
}
final ApkLite baseApk = result.getResult();
final PackageLite pkgLite = new PackageLite(null, baseApk.getPath(), baseApk, null,
null, null, null, null, null, baseApk.getTargetSdkVersion());
final PackageLite pkgLite = new PackageLite(null, baseApk.getPath(), baseApk,
null /* splitNames */, null /* isFeatureSplits */, null /* usesSplitNames */,
null /* configForSplit */, null /* splitApkPaths */,
null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(),
null /* requiredSplitTypes */, null /* splitTypes */);
Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkgLite));
}