diff --git a/README.md b/README.md index c7416b18..d76f3c67 100644 --- a/README.md +++ b/README.md @@ -46,4 +46,4 @@ https://developer.android.com/studio/command-line/bundletool ## Releases -Latest release: [1.15.6](https://github.com/google/bundletool/releases) +Latest release: [1.16.0](https://github.com/google/bundletool/releases) diff --git a/build.gradle b/build.gradle index 2676cb2c..45dcf2e6 100644 --- a/build.gradle +++ b/build.gradle @@ -31,23 +31,23 @@ configurations { // The repackaging rules are defined in the "shadowJar" task below. dependencies { - implementation "com.android.tools:common:30.1.0-alpha07" + implementation "com.android.tools:common:31.3.0-alpha14" implementation "com.android.tools:r8:3.3.28" implementation "com.android.tools.build:apksig:4.2.0-alpha13" - implementation "com.android.tools.ddms:ddmlib:30.1.0-alpha07" + implementation "com.android.tools.ddms:ddmlib:31.3.0-alpha14" implementation "com.android:zipflinger:7.1.0-alpha07" shadow "com.android.tools.build:aapt2-proto:7.3.0-alpha07-8248216" shadow "com.google.auto.value:auto-value-annotations:1.6.2" annotationProcessor "com.google.auto.value:auto-value:1.6.2" shadow "com.google.errorprone:error_prone_annotations:2.3.1" - shadow "com.google.guava:guava:31.1-jre" - shadow "com.google.protobuf:protobuf-java:3.19.2" - shadow "com.google.protobuf:protobuf-java-util:3.19.2" + shadow "com.google.guava:guava:32.0.1-jre" + shadow "com.google.protobuf:protobuf-java:3.22.3" + shadow "com.google.protobuf:protobuf-java-util:3.22.3" shadow "com.google.dagger:dagger:2.28.3" annotationProcessor "com.google.dagger:dagger-compiler:2.28.3" shadow "javax.inject:javax.inject:1" - shadow("org.bitbucket.b_c:jose4j:0.7.0") { + shadow("org.bitbucket.b_c:jose4j:0.9.5") { exclude group: "org.slf4j", module: "slf4j-api" } shadow "org.slf4j:slf4j-api:1.7.30" @@ -64,12 +64,12 @@ dependencies { testImplementation "com.google.auto.value:auto-value-annotations:1.6.2" testAnnotationProcessor "com.google.auto.value:auto-value:1.6.2" testImplementation "com.google.errorprone:error_prone_annotations:2.3.1" - testImplementation "com.google.guava:guava:31.1-jre" - testImplementation "com.google.truth.extensions:truth-java8-extension:0.45" - testImplementation "com.google.truth.extensions:truth-proto-extension:0.45" + testImplementation "com.google.guava:guava:33.0.0-jre" + testImplementation "com.google.truth:truth:1.4.0" + testImplementation "com.google.truth.extensions:truth-proto-extension:1.4.0" testImplementation "com.google.jimfs:jimfs:1.1" - testImplementation "com.google.protobuf:protobuf-java:3.19.2" - testImplementation "com.google.protobuf:protobuf-java-util:3.19.2" + testImplementation "com.google.protobuf:protobuf-java:3.25.2" + testImplementation "com.google.protobuf:protobuf-java-util:3.25.2" testImplementation "org.mockito:mockito-core:2.18.3" testImplementation "junit:junit:4.12" testImplementation "org.bouncycastle:bcprov-jdk15on:1.56" @@ -84,7 +84,7 @@ dependencies { testImplementation("org.smali:dexlib2:2.3.4") { exclude group: "com.google.guava", module: "guava" } - testImplementation("org.bitbucket.b_c:jose4j:0.7.0") { + testImplementation("org.bitbucket.b_c:jose4j:0.9.5") { exclude group: "org.slf4j", module: "slf4j-api" } testImplementation "org.slf4j:slf4j-api:1.7.30" @@ -128,7 +128,7 @@ test { protobuf { protoc { - artifact = "com.google.protobuf:protoc:3.19.2" + artifact = "com.google.protobuf:protoc:3.25.2" } } diff --git a/gradle.properties b/gradle.properties index bf6979d8..96001844 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -release_version = 1.15.6 +release_version = 1.16.0 diff --git a/src/main/java/com/android/tools/build/bundletool/archive/ArchivedAndroidManifestUtils.java b/src/main/java/com/android/tools/build/bundletool/archive/ArchivedAndroidManifestUtils.java index 1e401306..59df7caa 100644 --- a/src/main/java/com/android/tools/build/bundletool/archive/ArchivedAndroidManifestUtils.java +++ b/src/main/java/com/android/tools/build/bundletool/archive/ArchivedAndroidManifestUtils.java @@ -198,7 +198,6 @@ public static AndroidManifest updateArchivedIconsAndTheme( return archivedManifestEditor.save(); } - private static Activity createReactivateActivity( IntentFilter intentFilter, Optional icon, Optional roundIcon) { return getCommonActivityBuilder() @@ -264,6 +263,5 @@ private static void addTvSupportIfRequired( editor.addUsesFeatureElement(TOUCHSCREEN_FEATURE_NAME, /* isRequired= */ false); } - private ArchivedAndroidManifestUtils() {} } diff --git a/src/main/java/com/android/tools/build/bundletool/commands/BuildApksCommand.java b/src/main/java/com/android/tools/build/bundletool/commands/BuildApksCommand.java index ad0be0ae..980931e4 100644 --- a/src/main/java/com/android/tools/build/bundletool/commands/BuildApksCommand.java +++ b/src/main/java/com/android/tools/build/bundletool/commands/BuildApksCommand.java @@ -41,6 +41,7 @@ import com.android.apksig.util.DataSource; import com.android.apksig.util.DataSources; import com.android.bundle.Devices.DeviceSpec; +import com.android.bundle.FeatureModulesConfigProto.FeatureModulesCustomConfig; import com.android.bundle.RuntimeEnabledSdkConfigProto.LocalDeploymentRuntimeEnabledSdkConfig; import com.android.bundle.RuntimeEnabledSdkConfigProto.RuntimeEnabledSdk; import com.android.tools.build.bundletool.androidtools.Aapt2Command; @@ -313,6 +314,10 @@ ListeningExecutorService getExecutorService() { public abstract boolean getEnableBaseModuleMinSdkAsDefaultTargeting(); + public abstract Optional getFeatureModulesCustomConfig(); + + public abstract Optional getMinModulesToEnableFeatureModulesConfig(); + public static Builder builder() { return new AutoValue_BuildApksCommand.Builder() .setOverwriteOutput(false) @@ -582,6 +587,18 @@ public abstract Builder setLocalDeploymentRuntimeEnabledSdkConfig( */ public abstract Builder setEnableBaseModuleMinSdkAsDefaultTargeting(boolean value); + /** + * Custom configurations for feature modules. + * + *

Used to disable split apk generation for certain feature modules. + */ + public abstract Builder setFeatureModulesCustomConfig( + Optional featureModulesCustomConfig); + + /** Minimum number of modules in a variant to enable feature modules config. */ + public abstract Builder setMinModulesToEnableFeatureModulesConfig( + int minModulesToEnableFeatureModulesConfig); + abstract BuildApksCommand autoBuild(); public BuildApksCommand build() { diff --git a/src/main/java/com/android/tools/build/bundletool/commands/BuildApksManager.java b/src/main/java/com/android/tools/build/bundletool/commands/BuildApksManager.java index 4c3b3082..c53494bf 100644 --- a/src/main/java/com/android/tools/build/bundletool/commands/BuildApksManager.java +++ b/src/main/java/com/android/tools/build/bundletool/commands/BuildApksManager.java @@ -27,6 +27,7 @@ import com.android.bundle.Config.BundleConfig; import com.android.bundle.Config.ResourceOptimizations.SparseEncoding; import com.android.bundle.Config.StandaloneConfig.FeatureModulesMode; +import com.android.bundle.Config.UncompressDexFiles; import com.android.bundle.Devices.DeviceSpec; import com.android.tools.build.bundletool.archive.ArchivedApksGenerator; import com.android.tools.build.bundletool.commands.BuildApksCommand.ApkBuildMode; @@ -373,6 +374,19 @@ private void setEnableUncompressedDexOptimization( builder.setEnableDexCompressionSplitter(false); return; } + // If uncompressed dex is specified in the BundleConfig it will be honoured. + if (appBundle.getBundleConfig().getOptimizations().hasUncompressDexFiles()) { + UncompressDexFiles uncompressedDexFiles = + appBundle.getBundleConfig().getOptimizations().getUncompressDexFiles(); + builder.setEnableDexCompressionSplitter(uncompressedDexFiles.getEnabled()); + builder.setDexCompressionSplitterForTargetSdk( + uncompressedDexFiles.getUncompressedDexTargetSdk()); + return; + } + // Otherwise we rely on default for bundletool version used to build this AAB: + // * no uncompressed dex for bundletool < 1.12.0; + // * uncompressed dex for Android S+ for bundletool [1.12.0, 1.16.0); + // * uncompressed dex for Android Q+ for bundletool >= 1.16.0. builder.setEnableDexCompressionSplitter(apkOptimizations.getUncompressDexFiles()); builder.setDexCompressionSplitterForTargetSdk(apkOptimizations.getUncompressedDexTargetSdk()); } diff --git a/src/main/java/com/android/tools/build/bundletool/commands/BuildApksModule.java b/src/main/java/com/android/tools/build/bundletool/commands/BuildApksModule.java index 4205ccdf..b47e3e78 100644 --- a/src/main/java/com/android/tools/build/bundletool/commands/BuildApksModule.java +++ b/src/main/java/com/android/tools/build/bundletool/commands/BuildApksModule.java @@ -20,6 +20,7 @@ import com.android.bundle.Config.BundleConfig; import com.android.bundle.Devices.DeviceSpec; +import com.android.bundle.FeatureModulesConfigProto.FeatureModulesCustomConfig; import com.android.bundle.RuntimeEnabledSdkConfigProto.LocalDeploymentRuntimeEnabledSdkConfig; import com.android.tools.build.bundletool.androidtools.P7ZipCommand; import com.android.tools.build.bundletool.commands.BuildApksCommand.ApkBuildMode; @@ -181,6 +182,20 @@ static boolean provideRemoveTvIconCloud(BuildApksCommand command) { return removeTvIconCloud; } + @CommandScoped + @Provides + static Optional provideFeatureModulesCustomConfig( + BuildApksCommand command) { + return command.getFeatureModulesCustomConfig(); + } + + @CommandScoped + @MinModulesToEnableFeatureModulesConfig + @Provides + static Optional provideMinModulesToEnableFeatureModulesConfig(BuildApksCommand command) { + return command.getMinModulesToEnableFeatureModulesConfig(); + } + /** * Qualifying annotation of an {@code Optional} for the first variant number to use when * numbering the generated variants. @@ -212,5 +227,13 @@ static boolean provideRemoveTvIconCloud(BuildApksCommand command) { @Retention(RUNTIME) public @interface RemoveTvIconCloud {} + /** + * Qualifying annotation of an {@code Optional} for the minimum number of modules in a + * variant to enable feature modules config. + */ + @Qualifier + @Retention(RUNTIME) + public @interface MinModulesToEnableFeatureModulesConfig {} + private BuildApksModule() {} } diff --git a/src/main/java/com/android/tools/build/bundletool/commands/BuildSdkApksForAppModule.java b/src/main/java/com/android/tools/build/bundletool/commands/BuildSdkApksForAppModule.java index 121490df..d4bb356b 100644 --- a/src/main/java/com/android/tools/build/bundletool/commands/BuildSdkApksForAppModule.java +++ b/src/main/java/com/android/tools/build/bundletool/commands/BuildSdkApksForAppModule.java @@ -21,8 +21,7 @@ import com.android.tools.build.bundletool.androidtools.Aapt2Command; import com.android.tools.build.bundletool.androidtools.P7ZipCommand; import com.android.tools.build.bundletool.commands.BuildApksCommand.ApkBuildMode; -import com.android.tools.build.bundletool.io.ApkSerializer; -import com.android.tools.build.bundletool.io.ModuleSplitSerializer; +import com.android.tools.build.bundletool.io.ApkSerializerModule; import com.android.tools.build.bundletool.io.TempDirectory; import com.android.tools.build.bundletool.model.ApkListener; import com.android.tools.build.bundletool.model.ApkModifier; @@ -38,13 +37,12 @@ import com.android.tools.build.bundletool.optimizations.ApkOptimizations; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.ListeningExecutorService; -import dagger.Binds; import dagger.Module; import dagger.Provides; import java.util.Optional; /** Dagger module for build-sdk-apks-for-app command. */ -@Module +@Module(includes = {ApkSerializerModule.class}) public abstract class BuildSdkApksForAppModule { @Provides @@ -137,7 +135,4 @@ static Bundle provideBundle(BundleModule module, BundleConfig bundleConfig) { .setPackageNameOptional(module.getAndroidManifest().getPackageName()) .build(); } - - @Binds - abstract ApkSerializer apkSerializerHelper(ModuleSplitSerializer apkSerializerHelper); } diff --git a/src/main/java/com/android/tools/build/bundletool/commands/BuildSdkApksModule.java b/src/main/java/com/android/tools/build/bundletool/commands/BuildSdkApksModule.java index cbee8ca5..456e4d9c 100644 --- a/src/main/java/com/android/tools/build/bundletool/commands/BuildSdkApksModule.java +++ b/src/main/java/com/android/tools/build/bundletool/commands/BuildSdkApksModule.java @@ -22,8 +22,7 @@ import com.android.tools.build.bundletool.androidtools.Aapt2Command; import com.android.tools.build.bundletool.androidtools.P7ZipCommand; import com.android.tools.build.bundletool.commands.BuildApksCommand.ApkBuildMode; -import com.android.tools.build.bundletool.io.ApkSerializer; -import com.android.tools.build.bundletool.io.ModuleSplitSerializer; +import com.android.tools.build.bundletool.io.ApkSerializerModule; import com.android.tools.build.bundletool.io.TempDirectory; import com.android.tools.build.bundletool.model.ApkListener; import com.android.tools.build.bundletool.model.ApkModifier; @@ -42,7 +41,7 @@ import java.util.Optional; /** Dagger module for the build-sdk-apks command. */ -@Module +@Module(includes = {ApkSerializerModule.class}) public abstract class BuildSdkApksModule { @Provides @@ -128,7 +127,4 @@ static Optional provideFirstVariantNumber(BuildSdkApksCommand command) static boolean provideVerbose(BuildSdkApksCommand command) { return command.getVerbose(); } - - @Binds - abstract ApkSerializer apkSerializerHelper(ModuleSplitSerializer apkSerializerHelper); } diff --git a/src/main/java/com/android/tools/build/bundletool/commands/ExtractApksCommand.java b/src/main/java/com/android/tools/build/bundletool/commands/ExtractApksCommand.java index bebc0d29..83264bbe 100644 --- a/src/main/java/com/android/tools/build/bundletool/commands/ExtractApksCommand.java +++ b/src/main/java/com/android/tools/build/bundletool/commands/ExtractApksCommand.java @@ -33,6 +33,7 @@ import com.android.bundle.Commands.ExtractApksResult; import com.android.bundle.Commands.ExtractedApk; import com.android.bundle.Commands.LocalTestingInfoForMetadata; +import com.android.bundle.Commands.Variant; import com.android.bundle.Config.SplitDimension.Value; import com.android.bundle.Devices.DeviceSpec; import com.android.tools.build.bundletool.commands.CommandHelp.CommandDescription; @@ -52,6 +53,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; import com.google.common.io.ByteStreams; import com.google.protobuf.Int32Value; import com.google.protobuf.StringValue; @@ -203,9 +205,9 @@ ImmutableList execute(PrintStream output) { validateInput(); BuildApksResult toc = ResultUtils.readTableOfContents(getApksArchivePath()); - Optional> requestedModuleNames = - getModules().map(modules -> resolveRequestedModules(modules, toc)); DeviceSpec deviceSpec = applyDefaultsToDeviceSpec(getDeviceSpec(), toc); + Optional> requestedModuleNames = + getModules().map(modules -> resolveRequestedModules(modules, toc, deviceSpec)); ApkMatcher apkMatcher = new ApkMatcher( @@ -233,10 +235,10 @@ ImmutableList execute(PrintStream output) { } static ImmutableSet resolveRequestedModules( - ImmutableSet requestedModules, BuildApksResult toc) { + ImmutableSet requestedModules, BuildApksResult toc, DeviceSpec deviceSpec) { return requestedModules.contains(ALL_MODULES_SHORTCUT) ? Stream.concat( - toc.getVariantList().stream() + getVariantsMatchingSdkRuntimeTargeting(toc, deviceSpec).stream() .flatMap(variant -> variant.getApkSetList().stream()) .map(apkSet -> apkSet.getModuleMetadata().getName()), toc.getAssetSliceSetList().stream() @@ -246,6 +248,20 @@ static ImmutableSet resolveRequestedModules( : requestedModules; } + private static ImmutableSet getVariantsMatchingSdkRuntimeTargeting( + BuildApksResult toc, DeviceSpec deviceSpec) { + ImmutableSet sdkRuntimeVariants = + toc.getVariantList().stream() + .filter( + variant -> variant.getTargeting().getSdkRuntimeTargeting().getRequiresSdkRuntime()) + .collect(toImmutableSet()); + if (deviceSpec.getSdkRuntime().getSupported() && !sdkRuntimeVariants.isEmpty()) { + return sdkRuntimeVariants; + } + return Sets.difference(ImmutableSet.copyOf(toc.getVariantList()), sdkRuntimeVariants) + .immutableCopy(); + } + private void validateInput() { if (getModules().isPresent() && getModules().get().isEmpty()) { throw InvalidCommandException.builder() diff --git a/src/main/java/com/android/tools/build/bundletool/commands/InstallApksCommand.java b/src/main/java/com/android/tools/build/bundletool/commands/InstallApksCommand.java index c5b714cc..10180f6b 100644 --- a/src/main/java/com/android/tools/build/bundletool/commands/InstallApksCommand.java +++ b/src/main/java/com/android/tools/build/bundletool/commands/InstallApksCommand.java @@ -285,7 +285,7 @@ private ImmutableList getApksToInstall( .map(AssetModuleMetadata::getName) .collect(toImmutableSet()); getModules() - .map(modules -> ExtractApksCommand.resolveRequestedModules(modules, toc)) + .map(modules -> ExtractApksCommand.resolveRequestedModules(modules, toc, deviceSpec)) .map(modules -> Sets.difference(modules, dynamicAssetModules).immutableCopy()) .ifPresent(extractApksCommand::setModules); return extractApksCommand.build().execute(); @@ -323,7 +323,7 @@ private ImmutableList getApksToPushToStorage( .collect(toImmutableSet()); ImmutableSet allModules = ExtractApksCommand.resolveRequestedModules( - ImmutableSet.of(ExtractApksCommand.ALL_MODULES_SHORTCUT), toc); + ImmutableSet.of(ExtractApksCommand.ALL_MODULES_SHORTCUT), toc, deviceSpec); // We exclude install-time asset modules from the list of requested modules and also force // the extract-apk layer to skip them explicitly. diff --git a/src/main/java/com/android/tools/build/bundletool/commands/InstallMultiApksCommand.java b/src/main/java/com/android/tools/build/bundletool/commands/InstallMultiApksCommand.java index 88d2de1d..13f2dab5 100644 --- a/src/main/java/com/android/tools/build/bundletool/commands/InstallMultiApksCommand.java +++ b/src/main/java/com/android/tools/build/bundletool/commands/InstallMultiApksCommand.java @@ -60,6 +60,7 @@ import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Streams; import com.google.common.io.ByteStreams; import com.google.errorprone.annotations.CanIgnoreReturnValue; @@ -70,6 +71,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; +import java.util.Collections; import java.util.Locale; import java.util.Optional; import java.util.concurrent.TimeoutException; @@ -89,10 +91,15 @@ public abstract class InstallMultiApksCommand { public static final String COMMAND_NAME = "install-multi-apks"; - public static final ImmutableMap NONUPDATABLE_PACKAGES_PAIRS = - ImmutableMap.of( - "com.google.android.ext.services", "com.google.android.extservices", - "com.google.android.permissioncontroller", "com.google.android.permission"); + public static final ImmutableSetMultimap NONUPDATABLE_PACKAGES_PAIRS = + ImmutableSetMultimap.builder() + .put("com.google.android.ext.services", "com.google.android.go.extservices") + .put("com.google.android.ext.services", "com.google.android.extservices") + .put("com.google.android.go.extservices", "com.google.android.extservices") + .put("com.google.android.permissioncontroller", "com.google.android.go.permission") + .put("com.google.android.permissioncontroller", "com.google.android.permission") + .put("com.google.android.go.permission", "com.google.android.permission") + .build(); private static final Flag ADB_PATH_FLAG = Flag.path("adb"); private static final Flag> APKS_ARCHIVES_FLAG = Flag.pathList("apks"); @@ -518,25 +525,28 @@ private static ImmutableList uniqueApksByPackageName( .collect(toImmutableSet()); return unfilteredResults.stream() - .filter(result -> !isRedundantNonUpdatablePackage(result.getPackageName(), packageNames)) + .filter(result -> !isRedundantPackage(result.getPackageName(), packageNames)) .collect(toImmutableList()); } /** - * Check for the non-updatable package. If an updatable and non-updatable versions are present in - * the package list, only use the updatable version for the installation. + * If any two or more packages among big Android updatable, Go package and big android + * non-updatable versions are present in the package list, only package with the highest priority + * in the order of the list can be installed. Install Order: (Big Android Updatable, Go, Big + * Android Non-updatable) */ - static boolean isRedundantNonUpdatablePackage( - String packageName, ImmutableSet packageNames) { + static boolean isRedundantPackage(String packageName, ImmutableSet packageNames) { - /* If non-updatable package and it's updatable pair is not present, return false. */ + /* If the package does not have multiple versions, or the package is Big Android updatable + package, it is not redundant. */ if (!NONUPDATABLE_PACKAGES_PAIRS.containsKey(packageName)) { return false; } - /* If updatable pair is present in the Apks list, return it for installation. */ - String name = NONUPDATABLE_PACKAGES_PAIRS.get(packageName); - return packageNames.contains(name); + /* If the package may have different versions with higher priority, check if the high priority + version is in the package list, too. */ + ImmutableSet names = NONUPDATABLE_PACKAGES_PAIRS.get(packageName); + return !Collections.disjoint(names, packageNames); } public static CommandHelp help() { diff --git a/src/main/java/com/android/tools/build/bundletool/device/DdmlibDevice.java b/src/main/java/com/android/tools/build/bundletool/device/DdmlibDevice.java index d5c03103..c64edadf 100644 --- a/src/main/java/com/android/tools/build/bundletool/device/DdmlibDevice.java +++ b/src/main/java/com/android/tools/build/bundletool/device/DdmlibDevice.java @@ -240,6 +240,11 @@ public void push(ImmutableList files, PushOptions pushOptions) { } } + @Override + public boolean supportsPrivacySandbox() { + return device.services().containsKey("sdk_sandbox"); + } + private void pushFiles( RemoteCommandExecutor executor, String splitsPath, ImmutableList files) throws IOException, SyncException, TimeoutException, AdbCommandRejectedException, diff --git a/src/main/java/com/android/tools/build/bundletool/device/Device.java b/src/main/java/com/android/tools/build/bundletool/device/Device.java index db79b982..06e0248e 100644 --- a/src/main/java/com/android/tools/build/bundletool/device/Device.java +++ b/src/main/java/com/android/tools/build/bundletool/device/Device.java @@ -75,6 +75,8 @@ public abstract void removeRemotePath( public abstract void pull(ImmutableList files); + public abstract boolean supportsPrivacySandbox(); + /** Options related to APK installation. */ @Immutable @AutoValue diff --git a/src/main/java/com/android/tools/build/bundletool/device/DeviceAnalyzer.java b/src/main/java/com/android/tools/build/bundletool/device/DeviceAnalyzer.java index 23ee85e4..6ca90f11 100644 --- a/src/main/java/com/android/tools/build/bundletool/device/DeviceAnalyzer.java +++ b/src/main/java/com/android/tools/build/bundletool/device/DeviceAnalyzer.java @@ -16,7 +16,6 @@ package com.android.tools.build.bundletool.device; -import static com.android.tools.build.bundletool.model.AndroidManifest.SDK_SANDBOX_MIN_VERSION; import static com.google.common.base.Preconditions.checkState; import com.android.bundle.Devices.DeviceSpec; @@ -81,7 +80,7 @@ public DeviceSpec getDeviceSpec(Optional deviceId) { checkState(!supportedAbis.isEmpty(), "Error retrieving device ABIs. Please try again."); SdkRuntime sdkRuntime = - SdkRuntime.newBuilder().setSupported(deviceSdkVersion >= SDK_SANDBOX_MIN_VERSION).build(); + SdkRuntime.newBuilder().setSupported(device.supportsPrivacySandbox()).build(); DeviceSpec.Builder builder = DeviceSpec.newBuilder() diff --git a/src/main/java/com/android/tools/build/bundletool/io/ApkSerializerModule.java b/src/main/java/com/android/tools/build/bundletool/io/ApkSerializerModule.java index 88c7ab8c..418c0ece 100644 --- a/src/main/java/com/android/tools/build/bundletool/io/ApkSerializerModule.java +++ b/src/main/java/com/android/tools/build/bundletool/io/ApkSerializerModule.java @@ -15,8 +15,14 @@ */ package com.android.tools.build.bundletool.io; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.android.bundle.Config.BundleConfig; import dagger.Binds; import dagger.Module; +import dagger.Provides; +import java.lang.annotation.Retention; +import javax.inject.Qualifier; /** Dagger module responsible for choosing the {@link ApkSerializer}. */ @Module @@ -25,5 +31,28 @@ public abstract class ApkSerializerModule { @Binds abstract ApkSerializer provideApkSerializer(ModuleSplitSerializer moduleSplitSerializerProvider); + @Provides + @NativeLibrariesAlignmentInBytes + static int provideNativeLibrariesAlignmentInBytes(BundleConfig bundleConfig) { + switch (bundleConfig.getOptimizations().getUncompressNativeLibraries().getAlignment()) { + case PAGE_ALIGNMENT_16K: + return 16384; + case PAGE_ALIGNMENT_64K: + return 65536; + case PAGE_ALIGNMENT_UNSPECIFIED: + case PAGE_ALIGNMENT_4K: + case UNRECOGNIZED: + return 4096; + } + throw new IllegalArgumentException("Wrong native libraries alignment."); + } + + /** + * Qualifying annotation of a {@code int} for alignment that should be used for native libraries. + */ + @Qualifier + @Retention(RUNTIME) + @interface NativeLibrariesAlignmentInBytes {} + private ApkSerializerModule() {} } diff --git a/src/main/java/com/android/tools/build/bundletool/io/ApkSigner.java b/src/main/java/com/android/tools/build/bundletool/io/ApkSigner.java index 31072681..65143232 100644 --- a/src/main/java/com/android/tools/build/bundletool/io/ApkSigner.java +++ b/src/main/java/com/android/tools/build/bundletool/io/ApkSigner.java @@ -22,6 +22,7 @@ import com.android.apksig.apk.ApkFormatException; import com.android.bundle.Commands.SigningDescription; import com.android.tools.build.bundletool.commands.BuildApksModule.ApkSigningConfigProvider; +import com.android.tools.build.bundletool.io.ApkSerializerModule.NativeLibrariesAlignmentInBytes; import com.android.tools.build.bundletool.model.ApksigSigningConfiguration; import com.android.tools.build.bundletool.model.ModuleEntry; import com.android.tools.build.bundletool.model.ModuleSplit; @@ -53,15 +54,18 @@ class ApkSigner { private final Optional signingConfigProvider; private final Optional sourceStampSigningConfig; private final TempDirectory tempDirectory; + private final int nativeLibrariesAlignment; @Inject ApkSigner( @ApkSigningConfigProvider Optional signingConfigProvider, Optional sourceStampSigningConfig, - TempDirectory tempDirectory) { + TempDirectory tempDirectory, + @NativeLibrariesAlignmentInBytes int nativeLibrariesAlignment) { this.signingConfigProvider = signingConfigProvider; this.sourceStampSigningConfig = sourceStampSigningConfig; this.tempDirectory = tempDirectory; + this.nativeLibrariesAlignment = nativeLibrariesAlignment; } public Optional signApk(Path apkPath, ModuleSplit split) { diff --git a/src/main/java/com/android/tools/build/bundletool/io/ModuleSplitSerializer.java b/src/main/java/com/android/tools/build/bundletool/io/ModuleSplitSerializer.java index b6a43fae..805ce3fd 100644 --- a/src/main/java/com/android/tools/build/bundletool/io/ModuleSplitSerializer.java +++ b/src/main/java/com/android/tools/build/bundletool/io/ModuleSplitSerializer.java @@ -29,6 +29,7 @@ import com.android.bundle.Config.Compression.ApkCompressionAlgorithm; import com.android.tools.build.bundletool.androidtools.P7ZipCommand; import com.android.tools.build.bundletool.commands.BuildApksModule.VerboseLogs; +import com.android.tools.build.bundletool.io.ApkSerializerModule.NativeLibrariesAlignmentInBytes; import com.android.tools.build.bundletool.model.ApkListener; import com.android.tools.build.bundletool.model.BundleModule.SpecialModuleEntry; import com.android.tools.build.bundletool.model.ModuleEntry; @@ -81,7 +82,8 @@ public class ModuleSplitSerializer extends ApkSerializer { BundleConfig bundleConfig, Version bundletoolVersion, ListeningExecutorService executorService, - Optional p7ZipCommand) { + Optional p7ZipCommand, + @NativeLibrariesAlignmentInBytes int nativeLibrariesAlignment) { super(apkListener, verbose); this.aapt2ResourceConverter = aapt2ResourceConverterFactory; this.apkSigner = apkSigner; @@ -98,7 +100,7 @@ public class ModuleSplitSerializer extends ApkSerializer { this.bundletoolVersion = bundletoolVersion; this.executorService = executorService; this.p7ZipCommand = p7ZipCommand; - this.nativeLibraryAlignment = getNativeLibraryAlignment(bundleConfig); + this.nativeLibraryAlignment = nativeLibrariesAlignment; } /** @@ -412,18 +414,4 @@ private boolean shouldUncompressBecauseOfLowRatio( } return compressedSize >= uncompressedSize; } - - private int getNativeLibraryAlignment(BundleConfig bundleConfig) { - switch (bundleConfig.getOptimizations().getUncompressNativeLibraries().getAlignment()) { - case PAGE_ALIGNMENT_16K: - return 16384; - case PAGE_ALIGNMENT_64K: - return 65536; - case PAGE_ALIGNMENT_UNSPECIFIED: - case PAGE_ALIGNMENT_4K: - case UNRECOGNIZED: - return 4096; - } - throw new IllegalArgumentException("Wrong native libraries alignment."); - } } diff --git a/src/main/java/com/android/tools/build/bundletool/io/ZipFlingerBundleSerializer.java b/src/main/java/com/android/tools/build/bundletool/io/ZipFlingerBundleSerializer.java index 771394d6..d54cc919 100644 --- a/src/main/java/com/android/tools/build/bundletool/io/ZipFlingerBundleSerializer.java +++ b/src/main/java/com/android/tools/build/bundletool/io/ZipFlingerBundleSerializer.java @@ -119,6 +119,13 @@ public void serializeAppBundle(AppBundle bundle, Path destBundlePath) throws IOE module.getApexConfig().get(), DEFAULT_COMPRESSION_LEVEL)); } + if (module.getRuntimeEnabledSdkConfig().isPresent()) { + zipArchive.add( + protoToSource( + moduleDir.resolve(SpecialModuleEntry.RUNTIME_ENABLED_SDK_CONFIG.getPath()), + module.getRuntimeEnabledSdkConfig().get(), + DEFAULT_COMPRESSION_LEVEL)); + } } } } diff --git a/src/main/java/com/android/tools/build/bundletool/model/AndroidManifest.java b/src/main/java/com/android/tools/build/bundletool/model/AndroidManifest.java index ecdcee41..bd83f3aa 100644 --- a/src/main/java/com/android/tools/build/bundletool/model/AndroidManifest.java +++ b/src/main/java/com/android/tools/build/bundletool/model/AndroidManifest.java @@ -144,6 +144,7 @@ public abstract class AndroidManifest { public static final String HOST_NAME = "host"; public static final String SPLIT_TYPES_ATTRIBUTE_NAME = "splitTypes"; public static final String REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME = "requiredSplitTypes"; + public static final String AUTO_VERIFY_NAME = "autoVerify"; public static final String SDK_PATCH_VERSION_ATTRIBUTE_NAME = "com.android.vending.sdk.version.patch"; @@ -244,8 +245,10 @@ public abstract class AndroidManifest { public static final int PATH_PREFIX_RESOURCE_ID = 0x0101002b; public static final int SCHEME_RESOURCE_ID = 0x01010027; public static final int HOST_RESOURCE_ID = 0x01010028; + public static final int PORT_RESOURCE_ID = 0x01010029; public static final int SPLIT_TYPES_RESOURCE_ID = 0x0101064f; public static final int REQUIRED_SPLIT_TYPES_RESOURCE_ID = 0x0101064e; + public static final int AUTO_VERIFY_RESOURCE_ID = 0x010104ee; // Matches the value of android.os.Build.VERSION_CODES.CUR_DEVELOPMENT, used when turning // a manifest attribute which references a prerelease API version (e.g., "Q") into an integer. @@ -736,7 +739,20 @@ public Optional> getRequiredSplitTypesValue() { public Optional getInstallLocationValue() { return getManifestElement() .getAndroidAttribute(INSTALL_LOCATION_RESOURCE_ID) - .map(XmlProtoAttribute::getValueAsString); + .map(this::getInstallLocation); + } + + private String getInstallLocation(XmlProtoAttribute installLocationValue) { + switch (installLocationValue.getValueAsInteger()) { + case 0: + return "auto"; + case 1: + return "internalOnly"; + case 2: + return "preferExternal"; + default: + return "unspecified"; + } } /** diff --git a/src/main/java/com/android/tools/build/bundletool/model/ManifestEditor.java b/src/main/java/com/android/tools/build/bundletool/model/ManifestEditor.java index 68e97116..1a4d13ef 100644 --- a/src/main/java/com/android/tools/build/bundletool/model/ManifestEditor.java +++ b/src/main/java/com/android/tools/build/bundletool/model/ManifestEditor.java @@ -60,6 +60,7 @@ import static com.android.tools.build.bundletool.model.AndroidManifest.REQUIRED_BY_PRIVACY_SANDBOX_SDK_ATTRIBUTE_NAME; import static com.android.tools.build.bundletool.model.AndroidManifest.REQUIRED_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME; +import static com.android.tools.build.bundletool.model.AndroidManifest.REQUIRED_SPLIT_TYPES_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.RESOURCE_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.ROUND_ICON_ATTRIBUTE_NAME; import static com.android.tools.build.bundletool.model.AndroidManifest.ROUND_ICON_RESOURCE_ID; @@ -70,6 +71,7 @@ import static com.android.tools.build.bundletool.model.AndroidManifest.SERVICE_ELEMENT_NAME; import static com.android.tools.build.bundletool.model.AndroidManifest.SPLIT_NAME_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.SPLIT_TYPES_ATTRIBUTE_NAME; +import static com.android.tools.build.bundletool.model.AndroidManifest.SPLIT_TYPES_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.TARGET_SANDBOX_VERSION_ATTRIBUTE_NAME; import static com.android.tools.build.bundletool.model.AndroidManifest.TARGET_SANDBOX_VERSION_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.THEME_ATTRIBUTE_NAME; @@ -320,12 +322,16 @@ public ManifestEditor setSplitsRequired(boolean value) { * *

Split types are arbitrary strings, stored comma-separated, and used along with {@code * requiredSplitTypes} to perform validation at install time. - * - *

Note: this is currently set under `dist:splitTypes` rather than as the Android attribute. - * This will be replaced once the verifier implementation has been validated. */ @CanIgnoreReturnValue - public ManifestEditor setSplitTypes(ImmutableList splitTypes) { + public ManifestEditor setSplitTypes( + ImmutableList splitTypes, boolean enableSystemAttribute) { + if (enableSystemAttribute) { + manifestElement + .getOrCreateAndroidAttribute(SPLIT_TYPES_ATTRIBUTE_NAME, SPLIT_TYPES_RESOURCE_ID) + .setValueAsString(splitTypes.stream().sorted().collect(joining(","))); + } + // TODO(b/199376532): Remove once the system attribute is fully rolled out. manifestElement .getOrCreateAttribute(DISTRIBUTION_NAMESPACE_URI, SPLIT_TYPES_ATTRIBUTE_NAME) .setValueAsString(splitTypes.stream().sorted().collect(joining(","))); @@ -337,12 +343,17 @@ public ManifestEditor setSplitTypes(ImmutableList splitTypes) { * *

Split types are arbitrary strings, stored comma-separated, and reference the split types * provided by {@code splitTypes} in splits. - * - *

Note: this is currently set under `dist:requiredSplitTypes` rather than as the Android - * attribute. This will be replaced once the verifier implementation has been validated. */ @CanIgnoreReturnValue - public ManifestEditor setRequiredSplitTypes(ImmutableList splitTypes) { + public ManifestEditor setRequiredSplitTypes( + ImmutableList splitTypes, boolean enableSystemAttribute) { + if (enableSystemAttribute) { + manifestElement + .getOrCreateAndroidAttribute( + REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME, REQUIRED_SPLIT_TYPES_RESOURCE_ID) + .setValueAsString(splitTypes.stream().sorted().collect(joining(","))); + } + // TODO(b/199376532): Remove once the system attribute is fully rolled out. manifestElement .getOrCreateAttribute(DISTRIBUTION_NAMESPACE_URI, REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME) .setValueAsString(splitTypes.stream().sorted().collect(joining(","))); diff --git a/src/main/java/com/android/tools/build/bundletool/model/ManifestMutator.java b/src/main/java/com/android/tools/build/bundletool/model/ManifestMutator.java index 58328de4..8001bb69 100644 --- a/src/main/java/com/android/tools/build/bundletool/model/ManifestMutator.java +++ b/src/main/java/com/android/tools/build/bundletool/model/ManifestMutator.java @@ -16,7 +16,6 @@ package com.android.tools.build.bundletool.model; -import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.Immutable; import java.util.function.Consumer; @@ -33,14 +32,4 @@ static ManifestMutator withExtractNativeLibs(boolean value) { static ManifestMutator withSplitsRequired(boolean value) { return manifestEditor -> manifestEditor.setSplitsRequired(value); } - - /** Add the {@code splitTypes} attribute to a manifest. */ - static ManifestMutator withProvidedSplitTypes(ImmutableList splitTypes) { - return manifestEditor -> manifestEditor.setSplitTypes(splitTypes); - } - - /** Add the {@code requiredSplitTypes} attribute to a manifest. */ - static ManifestMutator withRequiredSplitTypes(ImmutableList splitTypes) { - return manifestEditor -> manifestEditor.setRequiredSplitTypes(splitTypes); - } } diff --git a/src/main/java/com/android/tools/build/bundletool/model/RequiredSplitTypesInjector.java b/src/main/java/com/android/tools/build/bundletool/model/RequiredSplitTypesInjector.java index c90fa6e3..64bfc20c 100644 --- a/src/main/java/com/android/tools/build/bundletool/model/RequiredSplitTypesInjector.java +++ b/src/main/java/com/android/tools/build/bundletool/model/RequiredSplitTypesInjector.java @@ -16,6 +16,7 @@ package com.android.tools.build.bundletool.model; +import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_T_API_VERSION; import static com.google.common.collect.ImmutableList.toImmutableList; import com.android.bundle.Targeting.ApkTargeting; @@ -34,23 +35,31 @@ public class RequiredSplitTypesInjector { */ @CheckReturnValue public static ImmutableList injectSplitTypeValidation( - ImmutableList splits, ImmutableList requiredModules) { + ImmutableList splits, + ImmutableList requiredModules, + boolean enableSystemAttribute) { return splits.stream() .map( split -> { + // During the validation rollout, only inject system split types attribute for splits + // targeting T+. + boolean includeSystemAttribute = enableSystemAttribute && isTargetingAtLeastT(split); + ManifestEditor apkManifest = split.getAndroidManifest().toEditor(); apkManifest.setSplitTypes( getProvidedSplitTypes(split).stream() .map(RequiredSplitTypeName::toAttributeValue) - .collect(toImmutableList())); + .collect(toImmutableList()), + includeSystemAttribute); // Only base/feature modules have required split types. if (split.isMasterSplit()) { apkManifest.setRequiredSplitTypes( getRequiredSplitTypes(splits, requiredModules, split).stream() .map(RequiredSplitTypeName::toAttributeValue) - .collect(toImmutableList())); + .collect(toImmutableList()), + includeSystemAttribute); } return split.toBuilder().setAndroidManifest(apkManifest.save()).build(); @@ -130,6 +139,14 @@ private static ImmutableSet getRequiredSplitTypes( return splitTypes.build(); } + private static boolean isTargetingAtLeastT(ModuleSplit split) { + return split.getVariantTargeting().getSdkVersionTargeting().getValueList().stream() + .mapToInt(sdkVersion -> sdkVersion.getMin().getValue()) + .min() + .orElse(1) + >= ANDROID_T_API_VERSION; + } + private RequiredSplitTypesInjector() {} static enum RequiredSplitType { diff --git a/src/main/java/com/android/tools/build/bundletool/model/SigningConfigurationProvider.java b/src/main/java/com/android/tools/build/bundletool/model/SigningConfigurationProvider.java index f807af16..bea955ae 100644 --- a/src/main/java/com/android/tools/build/bundletool/model/SigningConfigurationProvider.java +++ b/src/main/java/com/android/tools/build/bundletool/model/SigningConfigurationProvider.java @@ -21,7 +21,9 @@ import com.android.bundle.Targeting.ApkTargeting; import com.android.bundle.Targeting.VariantTargeting; +import com.android.tools.build.bundletool.model.ModuleSplit.SplitType; import com.google.auto.value.AutoValue; +import java.util.Optional; /** Allows clients to provide a {@link SigningConfiguration} for each generated APK. */ public interface SigningConfigurationProvider { @@ -48,6 +50,24 @@ public abstract class ApkDescription { /** Targeting of the variant. */ public abstract VariantTargeting getVariantTargeting(); + /** Version code of APK. */ + public abstract Optional getVersionCode(); + + /** Variant/Derived id of APK. */ + public abstract Optional getVariantId(); + + /** Module name of split. */ + public abstract String getModuleName(); + + /** Package name of app. */ + public abstract String getPackageName(); + + /** The split type being represented by this split. */ + public abstract SplitType getSplitType(); + + /** Split/Asset name of the split/AssetPack. */ + public abstract Optional getSplitName(); + /** * Minimum platform API version that the APK will be installed on. This is derived as the * highest version out of the minSdkVersion (from Android manifest), the ApkTargeting, and the @@ -61,11 +81,16 @@ public int getMinSdkVersionTargeting() { } public static ApkDescription fromModuleSplit(ModuleSplit moduleSplit) { - int minSdkVersionFromManifest = moduleSplit.getAndroidManifest().getEffectiveMinSdkVersion(); + AndroidManifest androidManifest = moduleSplit.getAndroidManifest(); return builder() - .setMinSdkVersionFromManifest(minSdkVersionFromManifest) + .setMinSdkVersionFromManifest(androidManifest.getEffectiveMinSdkVersion()) .setApkTargeting(moduleSplit.getApkTargeting()) .setVariantTargeting(moduleSplit.getVariantTargeting()) + .setVersionCode(androidManifest.getVersionCode()) + .setModuleName(moduleSplit.getModuleName().getName()) + .setSplitType(moduleSplit.getSplitType()) + .setSplitName(androidManifest.getSplitId()) + .setPackageName(androidManifest.getPackageName()) .build(); } @@ -82,6 +107,18 @@ public abstract static class Builder { public abstract Builder setVariantTargeting(VariantTargeting variantTargeting); + public abstract Builder setVersionCode(Optional versionCode); + + public abstract Builder setModuleName(String moduleName); + + public abstract Builder setPackageName(String packageName); + + public abstract Builder setVariantId(Optional variantId); + + public abstract Builder setSplitType(SplitType splitType); + + public abstract Builder setSplitName(Optional splitName); + public abstract ApkDescription build(); } } diff --git a/src/main/java/com/android/tools/build/bundletool/model/version/BundleToolVersion.java b/src/main/java/com/android/tools/build/bundletool/model/version/BundleToolVersion.java index 74822589..c7f3949a 100644 --- a/src/main/java/com/android/tools/build/bundletool/model/version/BundleToolVersion.java +++ b/src/main/java/com/android/tools/build/bundletool/model/version/BundleToolVersion.java @@ -26,7 +26,7 @@ */ public final class BundleToolVersion { - private static final String CURRENT_VERSION = "1.15.6"; + private static final String CURRENT_VERSION = "1.16.0"; /** Returns the version of BundleTool being run. */ diff --git a/src/main/java/com/android/tools/build/bundletool/optimizations/ApkOptimizations.java b/src/main/java/com/android/tools/build/bundletool/optimizations/ApkOptimizations.java index ce8f05ae..ddd36a56 100644 --- a/src/main/java/com/android/tools/build/bundletool/optimizations/ApkOptimizations.java +++ b/src/main/java/com/android/tools/build/bundletool/optimizations/ApkOptimizations.java @@ -98,6 +98,39 @@ public abstract class ApkOptimizations { .setUncompressDexFiles(true) .setUncompressedDexTargetSdk(UncompressedDexTargetSdk.SDK_31) .build()) + .put( + Version.of("1.15.7"), + ApkOptimizations.builder() + .setSplitDimensions( + ImmutableSet.of( + ABI, + SCREEN_DENSITY, + TEXTURE_COMPRESSION_FORMAT, + LANGUAGE, + DEVICE_TIER, + COUNTRY_SET)) + .setUncompressNativeLibraries(true) + .setStandaloneDimensions(ImmutableSet.of(ABI, SCREEN_DENSITY)) + .setUncompressDexFiles(true) + .setUncompressedDexTargetSdk(UncompressedDexTargetSdk.SDK_31) + .build()) + .put( + Version.of("1.16.0"), + ApkOptimizations.builder() + .setSplitDimensions( + ImmutableSet.of( + ABI, + SCREEN_DENSITY, + TEXTURE_COMPRESSION_FORMAT, + LANGUAGE, + DEVICE_TIER, + COUNTRY_SET)) + .setUncompressNativeLibraries(true) + .setStandaloneDimensions(ImmutableSet.of(ABI, SCREEN_DENSITY)) + .setUncompressDexFiles(true) + // UNSPECIFIED here means SDK 29+ (Android Q+) + .setUncompressedDexTargetSdk(UncompressedDexTargetSdk.UNSPECIFIED) + .build()) .buildOrThrow(); /** List of dimensions supported by asset modules. */ diff --git a/src/main/java/com/android/tools/build/bundletool/splitters/DexCompressionVariantGenerator.java b/src/main/java/com/android/tools/build/bundletool/splitters/DexCompressionVariantGenerator.java index 2ba5678f..d249a874 100644 --- a/src/main/java/com/android/tools/build/bundletool/splitters/DexCompressionVariantGenerator.java +++ b/src/main/java/com/android/tools/build/bundletool/splitters/DexCompressionVariantGenerator.java @@ -20,7 +20,6 @@ import static com.android.tools.build.bundletool.model.utils.TargetingProtoUtils.sdkVersionFrom; import static com.android.tools.build.bundletool.model.utils.TargetingProtoUtils.sdkVersionTargeting; import static com.android.tools.build.bundletool.model.utils.TargetingProtoUtils.variantTargeting; -import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_P_API_VERSION; import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_Q_API_VERSION; import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_S_API_VERSION; import static com.google.common.collect.ImmutableSet.toImmutableSet; diff --git a/src/main/java/com/android/tools/build/bundletool/splitters/PerModuleVariantTargetingGenerator.java b/src/main/java/com/android/tools/build/bundletool/splitters/PerModuleVariantTargetingGenerator.java index be9f73db..20e86f0f 100644 --- a/src/main/java/com/android/tools/build/bundletool/splitters/PerModuleVariantTargetingGenerator.java +++ b/src/main/java/com/android/tools/build/bundletool/splitters/PerModuleVariantTargetingGenerator.java @@ -74,6 +74,7 @@ private static ImmutableList getVariantGenerators( unused -> Stream.of(lPlusVariantTargeting()), new NativeLibsCompressionVariantGenerator(apkGenerationConfiguration), new DexCompressionVariantGenerator(apkGenerationConfiguration), + new RequiredSplitTypesVariantGenerator(apkGenerationConfiguration), new SigningConfigurationVariantGenerator(apkGenerationConfiguration), new SparseEncodingVariantGenerator(apkGenerationConfiguration)); } diff --git a/src/main/java/com/android/tools/build/bundletool/splitters/RequiredSplitTypesVariantGenerator.java b/src/main/java/com/android/tools/build/bundletool/splitters/RequiredSplitTypesVariantGenerator.java new file mode 100644 index 00000000..592e7e3f --- /dev/null +++ b/src/main/java/com/android/tools/build/bundletool/splitters/RequiredSplitTypesVariantGenerator.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.tools.build.bundletool.splitters; + +import static com.android.tools.build.bundletool.model.utils.TargetingProtoUtils.sdkVersionFrom; +import static com.android.tools.build.bundletool.model.utils.TargetingProtoUtils.sdkVersionTargeting; +import static com.android.tools.build.bundletool.model.utils.TargetingProtoUtils.variantTargeting; +import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_T_API_VERSION; + +import com.android.bundle.Targeting.VariantTargeting; +import com.android.tools.build.bundletool.model.BundleModule; +import java.util.stream.Stream; + +/** Generates variant targetings based on inclusion of required split types attributes. */ +public final class RequiredSplitTypesVariantGenerator implements BundleModuleVariantGenerator { + + private final ApkGenerationConfiguration apkGenerationConfiguration; + + public RequiredSplitTypesVariantGenerator(ApkGenerationConfiguration apkGenerationConfiguration) { + this.apkGenerationConfiguration = apkGenerationConfiguration; + } + + @Override + public Stream generate(BundleModule module) { + if (!apkGenerationConfiguration.getEnableRequiredSplitTypes()) { + return Stream.of(); + } + + return Stream.of(variantTargeting(sdkVersionTargeting(sdkVersionFrom(ANDROID_T_API_VERSION)))); + } +} diff --git a/src/main/java/com/android/tools/build/bundletool/splitters/SplitApksGenerator.java b/src/main/java/com/android/tools/build/bundletool/splitters/SplitApksGenerator.java index d12c914a..0d415879 100644 --- a/src/main/java/com/android/tools/build/bundletool/splitters/SplitApksGenerator.java +++ b/src/main/java/com/android/tools/build/bundletool/splitters/SplitApksGenerator.java @@ -19,7 +19,9 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableSet.toImmutableSet; +import com.android.bundle.FeatureModulesConfigProto.FeatureModulesCustomConfig; import com.android.bundle.Targeting.VariantTargeting; +import com.android.tools.build.bundletool.commands.BuildApksModule.MinModulesToEnableFeatureModulesConfig; import com.android.tools.build.bundletool.model.AppBundle; import com.android.tools.build.bundletool.model.BundleModule; import com.android.tools.build.bundletool.model.BundleModule.ModuleType; @@ -41,17 +43,24 @@ public final class SplitApksGenerator { private final Optional stampSource; private final VariantTargetingGenerator variantTargetingGenerator; private final AppBundle appBundle; + private final Optional featureModulesCustomConfig; + private final int minModulesToEnableFeatureModulesConfig; @Inject public SplitApksGenerator( Version bundletoolVersion, Optional stampSource, VariantTargetingGenerator variantTargetingGenerator, - AppBundle appBundle) { + AppBundle appBundle, + Optional featureModulesCustomConfig, + @MinModulesToEnableFeatureModulesConfig + Optional minModulesToEnableFeatureModulesConfig) { this.bundletoolVersion = bundletoolVersion; this.stampSource = stampSource; this.variantTargetingGenerator = variantTargetingGenerator; this.appBundle = appBundle; + this.featureModulesCustomConfig = featureModulesCustomConfig; + this.minModulesToEnableFeatureModulesConfig = minModulesToEnableFeatureModulesConfig.orElse(0); } public ImmutableList generateSplits( @@ -82,7 +91,11 @@ private ImmutableList generateSplitApks( module, bundletoolVersion, appBundle, - getApkGenerationConfigurationForModule(module, commonApkGenerationConfiguration), + getApkGenerationConfigurationForModule( + module, + commonApkGenerationConfiguration, + /* enableFeatureModulesConfig= */ modules.size() + >= minModulesToEnableFeatureModulesConfig), variantTargeting, allModuleNames, stampSource.map(SourceStamp::getSource), @@ -90,17 +103,16 @@ private ImmutableList generateSplitApks( splits.addAll(moduleSplitter.splitModule()); } - if (commonApkGenerationConfiguration.getEnableRequiredSplitTypes()) { - ImmutableList nonRemovableModules = - modulesForVariant.stream() - .filter(module -> module.getAndroidManifest().isAlwaysInstalledModule()) - .map(BundleModule::getName) - .collect(toImmutableList()); - return RequiredSplitTypesInjector.injectSplitTypeValidation( - splits.build(), nonRemovableModules); - } + ImmutableList nonRemovableModules = + modulesForVariant.stream() + .filter(module -> module.getAndroidManifest().isAlwaysInstalledModule()) + .map(BundleModule::getName) + .collect(toImmutableList()); - return splits.build(); + // Feature flag for enabling the system validation on T+. Remove after b/199376532. + boolean enableSystemAttribute = commonApkGenerationConfiguration.getEnableRequiredSplitTypes(); + return RequiredSplitTypesInjector.injectSplitTypeValidation( + splits.build(), nonRemovableModules, enableSystemAttribute); } private ImmutableList getModulesForVariant( @@ -114,11 +126,23 @@ private ImmutableList getModulesForVariant( } private ApkGenerationConfiguration getApkGenerationConfigurationForModule( - BundleModule module, ApkGenerationConfiguration commonGenerationConfig) { + BundleModule module, + ApkGenerationConfiguration commonGenerationConfig, + boolean enableFeatureModulesConfig) { if (module.getModuleType().equals(ModuleType.SDK_DEPENDENCY_MODULE)) { // We never generate splits for runtime-enabled SDK dependency modules. return ApkGenerationConfiguration.getDefaultInstance(); } + if (enableFeatureModulesConfig + && featureModulesCustomConfig.isPresent() + && featureModulesCustomConfig + .get() + .getDisableConfigSplitsModulesList() + .contains(module.getName().getName())) { + return commonGenerationConfig.toBuilder() + .setOptimizationDimensions(ImmutableSet.of()) + .build(); + } return commonGenerationConfig; } } diff --git a/src/main/proto/app_integrity_config.proto b/src/main/proto/app_integrity_config.proto index 51fcb045..346dec76 100644 --- a/src/main/proto/app_integrity_config.proto +++ b/src/main/proto/app_integrity_config.proto @@ -6,7 +6,7 @@ option java_package = "com.android.bundle"; // Specifies integrity protection options that should be applied to an app // bundle. -// Next tag: 8. +// Next tag: 9. message AppIntegrityConfig { bool enabled = 1; LicenseCheck license_check = 2; @@ -17,6 +17,7 @@ message AppIntegrityConfig { // config. DexProtectionConfig dex_protection_config = 6; string version_label = 7; + Telemetry telemetry = 8; } // Next tag: 4. @@ -75,3 +76,8 @@ message DexProtectionConfig { } TargetingMode targeting_mode = 3; } + +message Telemetry { + // Whether telemetry is enabled for this Android App Bundle. + bool enabled = 1; +} diff --git a/src/main/proto/config.proto b/src/main/proto/config.proto index 15a76c54..55539770 100644 --- a/src/main/proto/config.proto +++ b/src/main/proto/config.proto @@ -205,6 +205,7 @@ message UncompressDexFiles { UNSPECIFIED = 0; // S+ variant will be generated. SDK_31 = 1; + reserved 2; } } diff --git a/src/main/proto/feature_modules_config.proto b/src/main/proto/feature_modules_config.proto new file mode 100644 index 00000000..6b4ea888 --- /dev/null +++ b/src/main/proto/feature_modules_config.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package android.bundle; + +option java_package = "com.android.bundle"; +option java_outer_classname = "FeatureModulesConfigProto"; + +// Custom configutations for feature modules of the App Bundle. +message FeatureModulesCustomConfig { + // Specifies feature modules which are not split on split dimensions. + repeated string disable_config_splits_modules = 1; +} diff --git a/src/main/resources/com/android/tools/build/bundletool/archive/dex/1_16_0/classes.dex b/src/main/resources/com/android/tools/build/bundletool/archive/dex/1_16_0/classes.dex new file mode 100644 index 00000000..e29b043f Binary files /dev/null and b/src/main/resources/com/android/tools/build/bundletool/archive/dex/1_16_0/classes.dex differ diff --git a/src/test/java/com/android/tools/build/bundletool/commands/AddTransparencyCommandTest.java b/src/test/java/com/android/tools/build/bundletool/commands/AddTransparencyCommandTest.java index 54d629dc..8f3fcc1e 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/AddTransparencyCommandTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/AddTransparencyCommandTest.java @@ -24,7 +24,6 @@ import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.withSharedUserId; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static org.jose4j.jws.AlgorithmIdentifiers.RSA_USING_SHA256; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/commands/BuildApksCommandTest.java b/src/test/java/com/android/tools/build/bundletool/commands/BuildApksCommandTest.java index 72fff809..6d88a14c 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/BuildApksCommandTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/BuildApksCommandTest.java @@ -54,7 +54,6 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.StandardSystemProperty.USER_HOME; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; import static org.jose4j.jws.AlgorithmIdentifiers.RSA_USING_SHA256; diff --git a/src/test/java/com/android/tools/build/bundletool/commands/BuildApksManagerTest.java b/src/test/java/com/android/tools/build/bundletool/commands/BuildApksManagerTest.java index 13a9df8c..309dde48 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/BuildApksManagerTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/BuildApksManagerTest.java @@ -50,6 +50,7 @@ import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_Q_API_VERSION; import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_S_API_VERSION; import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_S_V2_API_VERSION; +import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_T_API_VERSION; import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_U_API_VERSION; import static com.android.tools.build.bundletool.testing.ApkSetUtils.extractFromApkSetFile; import static com.android.tools.build.bundletool.testing.ApkSetUtils.extractTocFromApkSetFile; @@ -129,7 +130,6 @@ import static com.google.common.collect.MoreCollectors.onlyElement; import static com.google.common.collect.Multimaps.transformValues; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static java.util.Comparator.comparing; import static java.util.function.Function.identity; @@ -297,6 +297,7 @@ public class BuildApksManagerTest { private static final SdkVersion P_SDK_VERSION = sdkVersionFrom(ANDROID_P_API_VERSION); private static final SdkVersion Q_SDK_VERSION = sdkVersionFrom(ANDROID_Q_API_VERSION); private static final SdkVersion S_SDK_VERSION = sdkVersionFrom(ANDROID_S_API_VERSION); + private static final SdkVersion T_SDK_VERSION = sdkVersionFrom(ANDROID_T_API_VERSION); private static final SdkVersion S2_V2_SDK_VERSION = sdkVersionFrom(ANDROID_S_V2_API_VERSION); @Rule public final TemporaryFolder tmp = new TemporaryFolder(); @@ -322,7 +323,7 @@ public class BuildApksManagerTest { @Inject BuildApksCommand command; protected TestModule.Builder createTestModuleBuilder() { - return TestModule.builder(); + return TestModule.builder().withEnableRequiredSplitTypes(false); } @BeforeClass @@ -2227,6 +2228,7 @@ public void buildApksCommand_splitApks_targetLPlus() throws Exception { .containsExactly(L_SDK_VERSION); } + @Test public void buildApksCommand_splitApks_targetMinSdkVersion() throws Exception { AppBundle appBundle = @@ -2870,7 +2872,7 @@ public void enableNativeLibraryCompressionWithExternalStorage_multipleSplitVaria .setNativeConfig( nativeLibraries( targetedNativeDirectory("lib/x86", nativeDirectoryTargeting(X86)))) - .setManifest(androidManifest("com.test.app", withInstallLocation("auto")))) + .setManifest(androidManifest("com.test.app", withInstallLocation(0)))) .setBundleConfig( BundleConfigBuilder.create() .setUncompressNativeLibraries(true) @@ -3025,7 +3027,8 @@ public void enabledDexCompressionSplitter_disabledUncompressedDex_noUncompressed .setBundleConfig(BundleConfigBuilder.create().setUncompressDexFiles(true).build()) .build(); TestComponent.useTestModule( - this, TestModule.builder().withAppBundle(appBundle).withOutputPath(outputFilePath).build()); + this, + createTestModuleBuilder().withAppBundle(appBundle).withOutputPath(outputFilePath).build()); buildApksManager.execute(); @@ -3039,15 +3042,15 @@ public void enabledDexCompressionSplitter_disabledUncompressedDex_noUncompressed } @Test - public void dexCompressionIsNotSet_enabledByDefault() throws Exception { - SdkVersion expectedDefaultUncompressedDexSdk = S_SDK_VERSION; + public void noUncompressDexInBundleConfig_1_12_0_uncompressedDexByDefaultForSPlus() + throws Exception { AppBundle appBundle = new AppBundleBuilder() + .setBundleConfig(BundleConfigBuilder.create().setVersion("1.12.0").build()) .addModule( "base", builder -> builder.addFile("dex/classes.dex").setManifest(androidManifest("com.test.app"))) - .setBundleConfig(BundleConfig.getDefaultInstance()) .build(); TestComponent.useTestModule( this, @@ -3063,18 +3066,40 @@ public void dexCompressionIsNotSet_enabledByDefault() throws Exception { splitApkVariants.stream() .map(variant -> variant.getTargeting().getSdkVersionTargeting())) .containsExactly( - sdkVersionTargeting( - L_SDK_VERSION, - ImmutableSet.of(LOWEST_SDK_VERSION, expectedDefaultUncompressedDexSdk)), - sdkVersionTargeting( - expectedDefaultUncompressedDexSdk, - ImmutableSet.of(LOWEST_SDK_VERSION, L_SDK_VERSION))); + sdkVersionTargeting(L_SDK_VERSION, ImmutableSet.of(LOWEST_SDK_VERSION, S_SDK_VERSION)), + sdkVersionTargeting(S_SDK_VERSION, ImmutableSet.of(LOWEST_SDK_VERSION, L_SDK_VERSION))); Variant uncompressedDexVariant = splitApkVariants.stream() .filter(variant -> variant.getVariantProperties().getUncompressedDex()) .collect(onlyElement()); assertThat(uncompressedDexVariant.getTargeting().getSdkVersionTargeting().getValue(0)) - .isEqualTo(expectedDefaultUncompressedDexSdk); + .isEqualTo(S_SDK_VERSION); + } + + @Test + public void noUncompressDexInBundleConfig_1_11_0_noUncompressedDexByDefault() throws Exception { + AppBundle appBundle = + new AppBundleBuilder() + .setBundleConfig(BundleConfigBuilder.create().setVersion("1.11.0").build()) + .addModule( + "base", + builder -> + builder.addFile("dex/classes.dex").setManifest(androidManifest("com.test.app"))) + .build(); + TestComponent.useTestModule( + this, + createTestModuleBuilder().withAppBundle(appBundle).withOutputPath(outputFilePath).build()); + + buildApksManager.execute(); + + ZipFile apkSetFile = openZipFile(outputFilePath.toFile()); + BuildApksResult result = extractTocFromApkSetFile(apkSetFile, outputDir); + + ImmutableList splitApkVariants = splitApkVariants(result); + assertThat( + splitApkVariants.stream() + .map(variant -> variant.getTargeting().getSdkVersionTargeting())) + .containsExactly(sdkVersionTargeting(L_SDK_VERSION, ImmutableSet.of(LOWEST_SDK_VERSION))); } @Test diff --git a/src/test/java/com/android/tools/build/bundletool/commands/BuildApksPreprocessingTest.java b/src/test/java/com/android/tools/build/bundletool/commands/BuildApksPreprocessingTest.java index 1772f5fd..b818270f 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/BuildApksPreprocessingTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/BuildApksPreprocessingTest.java @@ -39,7 +39,6 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/commands/BuildApksResourcePinningTest.java b/src/test/java/com/android/tools/build/bundletool/commands/BuildApksResourcePinningTest.java index 265a7ebd..49c20346 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/BuildApksResourcePinningTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/BuildApksResourcePinningTest.java @@ -161,7 +161,12 @@ public void resourceIds_pinnedToMasterSplits() throws Exception { .build(); TestComponent.useTestModule( - this, TestModule.builder().withAppBundle(appBundle).withOutputPath(outputFilePath).build()); + this, + TestModule.builder() + .withEnableRequiredSplitTypes(false) + .withAppBundle(appBundle) + .withOutputPath(outputFilePath) + .build()); buildApksManager.execute(); ZipFile apkSetFile = new ZipFile(outputFilePath.toFile()); diff --git a/src/test/java/com/android/tools/build/bundletool/commands/BuildBundleCommandTest.java b/src/test/java/com/android/tools/build/bundletool/commands/BuildBundleCommandTest.java index 66c14456..64575107 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/BuildBundleCommandTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/BuildBundleCommandTest.java @@ -40,7 +40,6 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksCommandTest.java b/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksCommandTest.java index dfebd36c..9736a265 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksCommandTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksCommandTest.java @@ -33,7 +33,6 @@ import static com.android.tools.build.bundletool.testing.TestUtils.expectMissingRequiredFlagException; import static com.google.common.base.StandardSystemProperty.USER_HOME; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Arrays.stream; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksForAppCommandTest.java b/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksForAppCommandTest.java index b1280df2..bcea6eba 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksForAppCommandTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksForAppCommandTest.java @@ -33,7 +33,6 @@ import static com.android.tools.build.bundletool.testing.TestUtils.expectMissingRequiredFlagException; import static com.android.tools.build.bundletool.testing.TestUtils.extractAndroidManifest; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import com.android.bundle.Commands.ApkSet; diff --git a/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksManagerTest.java b/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksManagerTest.java index a7c6119d..bc21d198 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksManagerTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkApksManagerTest.java @@ -33,7 +33,6 @@ import static com.android.tools.build.bundletool.testing.TestUtils.createKeystore; import static com.android.tools.build.bundletool.testing.TestUtils.extractAndroidManifest; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Arrays.stream; diff --git a/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkAsarCommandTest.java b/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkAsarCommandTest.java index 09865ac1..dc3047e6 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkAsarCommandTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/BuildSdkAsarCommandTest.java @@ -25,7 +25,6 @@ import static com.android.tools.build.bundletool.testing.TestUtils.expectMissingRequiredBuilderPropertyException; import static com.android.tools.build.bundletool.testing.TestUtils.expectMissingRequiredFlagException; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static java.util.Arrays.stream; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/commands/DebugKeystoreUtilsTest.java b/src/test/java/com/android/tools/build/bundletool/commands/DebugKeystoreUtilsTest.java index 097b41fe..f50d6ef7 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/DebugKeystoreUtilsTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/DebugKeystoreUtilsTest.java @@ -17,7 +17,7 @@ package com.android.tools.build.bundletool.commands; import static com.google.common.base.StandardSystemProperty.USER_HOME; -import static com.google.common.truth.Truth8.assertThat; +import static com.google.common.truth.Truth.assertThat; import com.android.tools.build.bundletool.model.utils.files.FileUtils; import com.android.tools.build.bundletool.testing.FakeSystemEnvironmentProvider; diff --git a/src/test/java/com/android/tools/build/bundletool/commands/ExtractApksCommandTest.java b/src/test/java/com/android/tools/build/bundletool/commands/ExtractApksCommandTest.java index 6d8ca80d..51364672 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/ExtractApksCommandTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/ExtractApksCommandTest.java @@ -21,6 +21,8 @@ import static com.android.bundle.Targeting.Abi.AbiAlias.X86; import static com.android.bundle.Targeting.Abi.AbiAlias.X86_64; import static com.android.bundle.Targeting.ScreenDensity.DensityAlias.XXHDPI; +import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_L_API_VERSION; +import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_U_API_VERSION; import static com.android.tools.build.bundletool.model.utils.files.FilePreconditions.checkFileExistsAndReadable; import static com.android.tools.build.bundletool.testing.ApksArchiveHelpers.createApkDescription; import static com.android.tools.build.bundletool.testing.ApksArchiveHelpers.createApksArchiveFile; @@ -58,11 +60,11 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.moduleFeatureTargeting; import static com.android.tools.build.bundletool.testing.TargetingUtils.moduleMinSdkVersionTargeting; import static com.android.tools.build.bundletool.testing.TargetingUtils.multiAbiTargeting; +import static com.android.tools.build.bundletool.testing.TargetingUtils.sdkRuntimeVariantTargeting; import static com.android.tools.build.bundletool.testing.TargetingUtils.sdkVersionFrom; import static com.android.tools.build.bundletool.testing.TargetingUtils.variantSdkTargeting; import static com.android.tools.build.bundletool.testing.TestUtils.expectMissingRequiredFlagException; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -1660,6 +1662,193 @@ public void shortcutToExtractAllModules(TocFormat tocFormat) throws Exception { } } + @Theory + @Test + public void extractAllModules_appHasNoSdkRuntimeModule_deviceHasSdkRuntime_allModulesReturned( + TocFormat tocFormat) throws Exception { + ZipPath apkBase = ZipPath.create("base-master.apk"); + ZipPath apkBaseXxhdpi = ZipPath.create("base-xxhdpi.apk"); + ZipPath apkFeature = ZipPath.create("feature-master.apk"); + ZipPath apkFeatureXxhdpi = ZipPath.create("feature-xxhdpi.apk"); + ZipPath apkFeature2 = ZipPath.create("feature2.apk"); + ZipPath apkFeature2Arm64 = ZipPath.create("feature2-arm64_v8a.apk"); + BuildApksResult tableOfContentsProto = + BuildApksResult.newBuilder() + .setBundletool( + Bundletool.newBuilder() + .setVersion(BundleToolVersion.getCurrentVersion().toString())) + .addVariant( + createVariant( + variantSdkTargeting( + sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), + createSplitApkSet( + "base", + createMasterApkDescription(ApkTargeting.getDefaultInstance(), apkBase), + createApkDescription(apkDensityTargeting(XXHDPI), apkBaseXxhdpi, false)), + createSplitApkSet( + "feature", + DeliveryType.ON_DEMAND, + /* moduleDependencies= */ ImmutableList.of("feature2"), + createMasterApkDescription(ApkTargeting.getDefaultInstance(), apkFeature), + createApkDescription(apkDensityTargeting(XXHDPI), apkFeatureXxhdpi, false)), + createSplitApkSet( + "feature2", + DeliveryType.ON_DEMAND, + /* moduleDependencies= */ ImmutableList.of(), + createMasterApkDescription(ApkTargeting.getDefaultInstance(), apkFeature2), + createApkDescription(apkAbiTargeting(ARM64_V8A), apkFeature2Arm64, false)))) + .build(); + Path apksArchiveFile = + createApksArchiveFile(tableOfContentsProto, tmpDir.resolve("bundle.apks"), tocFormat); + + DeviceSpec deviceSpec = + mergeSpecs(deviceWithSdk(ANDROID_U_API_VERSION), sdkRuntimeSupported(true)); + + ImmutableList matchedApks = + ExtractApksCommand.builder() + .setApksArchivePath(apksArchiveFile) + .setDeviceSpec(deviceSpec) + .setOutputDirectory(tmpDir) + .setModules(ImmutableSet.of("_ALL_")) + .build() + .execute(); + + assertThat(matchedApks) + .containsExactly( + inOutputDirectory(apkBase), + inOutputDirectory(apkBaseXxhdpi), + inOutputDirectory(apkFeature), + inOutputDirectory(apkFeatureXxhdpi), + inOutputDirectory(apkFeature2), + inOutputDirectory(apkFeature2Arm64)); + for (Path matchedApk : matchedApks) { + checkFileExistsAndReadable(tmpDir.resolve(matchedApk)); + } + } + + @Theory + @Test + public void extractAllModules_appHasSdkRuntimeVariant_sdkRuntimeDevice_sdkSplitsNotMatched( + TocFormat tocFormat) throws Exception { + ZipPath baseMasterApk = ZipPath.create("base-master.apk"); + ZipPath sdkSplitApk1 = ZipPath.create("sdk1-master.apk"); + ZipPath sdkSplitApk2 = ZipPath.create("sdk2-master.apk"); + ZipPath baseMaster2Apk = ZipPath.create("base-master_2.apk"); + BuildApksResult buildApksResult = + BuildApksResult.newBuilder() + .setBundletool( + Bundletool.newBuilder() + .setVersion(BundleToolVersion.getCurrentVersion().toString())) + .addVariant( + createVariant( + /* variantNumber= */ 1, + variantSdkTargeting( + sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), + createSplitApkSet( + /* moduleName= */ "base", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), baseMasterApk)), + createSplitApkSet( + /* moduleName= */ "sdk1", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), sdkSplitApk1)), + createSplitApkSet( + /* moduleName= */ "sdk2", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), sdkSplitApk2)))) + .addVariant( + createVariant( + /* variantNumber= */ 2, + sdkRuntimeVariantTargeting(), + createSplitApkSet( + "base", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), baseMaster2Apk)))) + .build(); + Path apksArchiveFile = + createApksArchiveFile(buildApksResult, tmpDir.resolve("bundle.apks"), tocFormat); + + DeviceSpec deviceSpec = + mergeSpecs(deviceWithSdk(ANDROID_U_API_VERSION), sdkRuntimeSupported(true)); + + ImmutableList matchedApks = + ExtractApksCommand.builder() + .setApksArchivePath(apksArchiveFile) + .setDeviceSpec(deviceSpec) + .setOutputDirectory(tmpDir) + .setModules(ImmutableSet.of("_ALL_")) + .build() + .execute(); + + assertThat(matchedApks).containsExactly(inOutputDirectory(baseMaster2Apk)); + for (Path matchedApk : matchedApks) { + checkFileExistsAndReadable(tmpDir.resolve(matchedApk)); + } + } + + @Theory + @Test + public void extractAllModules_appHasSdkRuntimeVariant_nonSdkRuntimeDevice_sdkSplitsMatched( + TocFormat tocFormat) throws Exception { + ZipPath baseMasterApk = ZipPath.create("base-master.apk"); + ZipPath sdkSplitApk1 = ZipPath.create("sdk1-master.apk"); + ZipPath sdkSplitApk2 = ZipPath.create("sdk2-master.apk"); + ZipPath baseMaster2Apk = ZipPath.create("base-master_2.apk"); + BuildApksResult buildApksResult = + BuildApksResult.newBuilder() + .setBundletool( + Bundletool.newBuilder() + .setVersion(BundleToolVersion.getCurrentVersion().toString())) + .addVariant( + createVariant( + /* variantNumber= */ 1, + variantSdkTargeting( + sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), + createSplitApkSet( + /* moduleName= */ "base", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), baseMasterApk)), + createSplitApkSet( + /* moduleName= */ "sdk1", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), sdkSplitApk1)), + createSplitApkSet( + /* moduleName= */ "sdk2", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), sdkSplitApk2)))) + .addVariant( + createVariant( + /* variantNumber= */ 2, + sdkRuntimeVariantTargeting(), + createSplitApkSet( + "base", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), baseMaster2Apk)))) + .build(); + Path apksArchiveFile = + createApksArchiveFile(buildApksResult, tmpDir.resolve("bundle.apks"), tocFormat); + + DeviceSpec deviceSpec = deviceWithSdk(ANDROID_L_API_VERSION); + + ImmutableList matchedApks = + ExtractApksCommand.builder() + .setApksArchivePath(apksArchiveFile) + .setDeviceSpec(deviceSpec) + .setOutputDirectory(tmpDir) + .setModules(ImmutableSet.of("_ALL_")) + .build() + .execute(); + + assertThat(matchedApks) + .containsExactly( + inOutputDirectory(baseMasterApk), + inOutputDirectory(sdkSplitApk1), + inOutputDirectory(sdkSplitApk2)); + for (Path matchedApk : matchedApks) { + checkFileExistsAndReadable(tmpDir.resolve(matchedApk)); + } + } + @Theory @Test public void extractAssetModules(TocFormat tocFormat) throws Exception { diff --git a/src/test/java/com/android/tools/build/bundletool/commands/InstallApksCommandTest.java b/src/test/java/com/android/tools/build/bundletool/commands/InstallApksCommandTest.java index 9fe8f01b..2ff70f14 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/InstallApksCommandTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/InstallApksCommandTest.java @@ -18,6 +18,8 @@ import static com.android.bundle.Targeting.Abi.AbiAlias.X86; import static com.android.bundle.Targeting.Abi.AbiAlias.X86_64; +import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_L_API_VERSION; +import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_U_API_VERSION; import static com.android.tools.build.bundletool.testing.ApksArchiveHelpers.createApkDescription; import static com.android.tools.build.bundletool.testing.ApksArchiveHelpers.createApksArchiveFile; import static com.android.tools.build.bundletool.testing.ApksArchiveHelpers.createApksDirectory; @@ -28,9 +30,11 @@ import static com.android.tools.build.bundletool.testing.ApksArchiveHelpers.splitApkDescription; import static com.android.tools.build.bundletool.testing.DeviceFactory.abis; import static com.android.tools.build.bundletool.testing.DeviceFactory.density; +import static com.android.tools.build.bundletool.testing.DeviceFactory.deviceWithSdk; import static com.android.tools.build.bundletool.testing.DeviceFactory.lDeviceWithLocales; import static com.android.tools.build.bundletool.testing.DeviceFactory.locales; import static com.android.tools.build.bundletool.testing.DeviceFactory.mergeSpecs; +import static com.android.tools.build.bundletool.testing.DeviceFactory.sdkRuntimeSupported; import static com.android.tools.build.bundletool.testing.DeviceFactory.sdkVersion; import static com.android.tools.build.bundletool.testing.FakeSystemEnvironmentProvider.ANDROID_HOME; import static com.android.tools.build.bundletool.testing.FakeSystemEnvironmentProvider.ANDROID_SERIAL; @@ -41,13 +45,13 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.apkLanguageTargeting; import static com.android.tools.build.bundletool.testing.TargetingUtils.countrySetTargeting; import static com.android.tools.build.bundletool.testing.TargetingUtils.deviceTierTargeting; +import static com.android.tools.build.bundletool.testing.TargetingUtils.sdkRuntimeVariantTargeting; import static com.android.tools.build.bundletool.testing.TargetingUtils.sdkVersionFrom; import static com.android.tools.build.bundletool.testing.TargetingUtils.variantSdkTargeting; import static com.android.tools.build.bundletool.testing.TestUtils.expectMissingRequiredBuilderPropertyException; import static com.android.tools.build.bundletool.testing.TestUtils.expectMissingRequiredFlagException; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import com.android.bundle.Commands.AssetModuleMetadata; @@ -1625,6 +1629,126 @@ public void bundleWithCountrySetTargeting_countrySetSpecified_filterByCountrySet .containsExactly(baseMasterApk.toString(), baseSeaApk.toString()); } + @Test + public void appWithRuntimeEnabledSdkDep_sdkRuntimeVariantMatched_noSdkSplitsInstalled() + throws Exception { + ZipPath baseMasterApk = ZipPath.create("base-master.apk"); + ZipPath sdkSplitApk1 = ZipPath.create("sdk1-master.apk"); + ZipPath sdkSplitApk2 = ZipPath.create("sdk2-master.apk"); + ZipPath baseMaster2Apk = ZipPath.create("base-master_2.apk"); + BuildApksResult buildApksResult = + BuildApksResult.newBuilder() + .setBundletool( + Bundletool.newBuilder() + .setVersion(BundleToolVersion.getCurrentVersion().toString())) + .addVariant( + createVariant( + /* variantNumber= */ 1, + variantSdkTargeting( + sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), + createSplitApkSet( + /* moduleName= */ "base", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), baseMasterApk)), + createSplitApkSet( + /* moduleName= */ "sdk1", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), sdkSplitApk1)), + createSplitApkSet( + /* moduleName= */ "sdk2", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), sdkSplitApk2)))) + .addVariant( + createVariant( + /* variantNumber= */ 2, + sdkRuntimeVariantTargeting(), + createSplitApkSet( + "base", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), baseMaster2Apk)))) + .build(); + + Path apksFile = createApksArchiveFile(buildApksResult, tmpDir.resolve("bundle.apks")); + List installedApks = new ArrayList<>(); + FakeDevice fakeDevice = + FakeDevice.fromDeviceSpec( + DEVICE_ID, + DeviceState.ONLINE, + mergeSpecs(deviceWithSdk(ANDROID_U_API_VERSION), sdkRuntimeSupported(true))); + fakeDevice.setInstallApksSideEffect((apks, installOptions) -> installedApks.addAll(apks)); + AdbServer adbServer = + new FakeAdbServer(/* hasInitialDeviceList= */ true, ImmutableList.of(fakeDevice)); + + InstallApksCommand.builder() + .setApksArchivePath(apksFile) + .setAdbPath(adbPath) + .setAdbServer(adbServer) + .build() + .execute(); + + assertThat(getFileNames(installedApks)).containsExactly(baseMaster2Apk.toString()); + } + + @Test + public void appWithRuntimeEnabledSdkDep_backwardsCompatVariantMatched_sdkSplitsInstalled() + throws Exception { + ZipPath baseMasterApk = ZipPath.create("base-master.apk"); + ZipPath sdkSplitApk1 = ZipPath.create("sdk1-master.apk"); + ZipPath sdkSplitApk2 = ZipPath.create("sdk2-master.apk"); + ZipPath baseMaster2Apk = ZipPath.create("base-master_2.apk"); + BuildApksResult buildApksResult = + BuildApksResult.newBuilder() + .setBundletool( + Bundletool.newBuilder() + .setVersion(BundleToolVersion.getCurrentVersion().toString())) + .addVariant( + createVariant( + /* variantNumber= */ 1, + variantSdkTargeting( + sdkVersionFrom(21), ImmutableSet.of(SdkVersion.getDefaultInstance())), + createSplitApkSet( + /* moduleName= */ "base", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), baseMasterApk)), + createSplitApkSet( + /* moduleName= */ "sdk1", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), sdkSplitApk1)), + createSplitApkSet( + /* moduleName= */ "sdk2", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), sdkSplitApk2)))) + .addVariant( + createVariant( + /* variantNumber= */ 2, + sdkRuntimeVariantTargeting(), + createSplitApkSet( + "base", + createMasterApkDescription( + ApkTargeting.getDefaultInstance(), baseMaster2Apk)))) + .build(); + + Path apksFile = createApksArchiveFile(buildApksResult, tmpDir.resolve("bundle.apks")); + List installedApks = new ArrayList<>(); + FakeDevice fakeDevice = + FakeDevice.fromDeviceSpec( + DEVICE_ID, DeviceState.ONLINE, deviceWithSdk(ANDROID_L_API_VERSION)); + fakeDevice.setInstallApksSideEffect((apks, installOptions) -> installedApks.addAll(apks)); + AdbServer adbServer = + new FakeAdbServer(/* hasInitialDeviceList= */ true, ImmutableList.of(fakeDevice)); + + InstallApksCommand.builder() + .setApksArchivePath(apksFile) + .setAdbPath(adbPath) + .setAdbServer(adbServer) + .build() + .execute(); + + assertThat(getFileNames(installedApks)) + .containsExactly( + baseMasterApk.toString(), sdkSplitApk1.toString(), sdkSplitApk2.toString()); + } + @Test public void printHelp_doesNotCrash() { GetDeviceSpecCommand.help(); diff --git a/src/test/java/com/android/tools/build/bundletool/commands/InstallMultiApksCommandTest.java b/src/test/java/com/android/tools/build/bundletool/commands/InstallMultiApksCommandTest.java index cf7fe43f..02da0c7c 100644 --- a/src/test/java/com/android/tools/build/bundletool/commands/InstallMultiApksCommandTest.java +++ b/src/test/java/com/android/tools/build/bundletool/commands/InstallMultiApksCommandTest.java @@ -32,7 +32,6 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableMap.toImmutableMap; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import com.android.bundle.Commands.ApkDescription; @@ -90,6 +89,8 @@ public class InstallMultiApksCommandTest { private static final String NONUPDATABLE_PKG_NAME_3 = "com.google.android.permissioncontroller"; private static final String NONUPDATABLE_PKG_NAME_4 = "com.google.android.extservices"; private static final String NONUPDATABLE_PKG_NAME_5 = "com.google.android.permission"; + private static final String NONUPDATABLE_PKG_NAME_6 = "com.google.android.go.extservices"; + private static final String NONUPDATABLE_PKG_NAME_7 = "com.google.android.go.permission"; @Rule public TemporaryFolder tmp = new TemporaryFolder(); @@ -632,6 +633,64 @@ public void execute_installUpdatablePackageOnly() throws Exception { assertAdbCommandExecuted(); } + @Test + public void execute_installBigAndroidUpdatablePackageOnly() throws Exception { + BuildApksResult tableOfContents4 = fakeTableOfContents(NONUPDATABLE_PKG_NAME_4); + Path apksPath4 = createApksArchiveFile(tableOfContents4, tmpDir.resolve("package4.apks")); + BuildApksResult tableOfContents5 = fakeTableOfContents(NONUPDATABLE_PKG_NAME_5); + Path apksPath5 = createApksArchiveFile(tableOfContents5, tmpDir.resolve("package5.apks")); + BuildApksResult tableOfContents6 = fakeTableOfContents(NONUPDATABLE_PKG_NAME_6); + Path apksPath6 = createApksArchiveFile(tableOfContents6, tmpDir.resolve("package6.apks")); + BuildApksResult tableOfContents7 = fakeTableOfContents(NONUPDATABLE_PKG_NAME_7); + Path apksPath7 = createApksArchiveFile(tableOfContents7, tmpDir.resolve("package7.apks")); + + InstallMultiApksCommand command = + InstallMultiApksCommand.builder() + .setAdbServer(fakeServerOneDevice(device)) + .setDeviceId(DEVICE_ID) + .setAdbPath(adbPath) + .setApksArchivePaths(ImmutableList.of(apksPath4, apksPath5, apksPath6, apksPath7)) + .setAapt2Command( + createFakeAapt2Command( + ImmutableMap.of( + NONUPDATABLE_PKG_NAME_4, + 1L, + NONUPDATABLE_PKG_NAME_5, + 1L, + NONUPDATABLE_PKG_NAME_6, + 1L, + NONUPDATABLE_PKG_NAME_7, + 1L))) + .setAdbCommand( + // EXPECT two packages to be installed. + createFakeAdbCommand( + ImmutableListMultimap.builder() + .putAll(expectedInstallApks(NONUPDATABLE_PKG_NAME_4, tableOfContents4)) + .putAll(expectedInstallApks(NONUPDATABLE_PKG_NAME_5, tableOfContents5)) + .build(), + /* expectedStaged= */ false, + /* expectedEnableRollback= */ false, + Optional.of(DEVICE_ID))) + .build(); + + // EXPECT to filter out the go packages which have big Android updatable versions available. + device.injectShellCommandOutput( + "pm list packages --show-versioncode", + () -> + String.format( + "package:%s versionCode:1\n" + + "package:%s versionCode:1\n" + + "package:%s versionCode:1\n" + + "package:%s versionCode:1", + NONUPDATABLE_PKG_NAME_4, + NONUPDATABLE_PKG_NAME_5, + NONUPDATABLE_PKG_NAME_6, + NONUPDATABLE_PKG_NAME_7)); + device.injectShellCommandOutput("pm list packages --apex-only --show-versioncode", () -> ""); + command.execute(); + assertAdbCommandExecuted(); + } + @Test public void execute_gracefulExitIfNoPackagesFound() throws Exception { // GIVEN a zip file containing fake .apks files for multiple packages. diff --git a/src/test/java/com/android/tools/build/bundletool/device/DeviceAnalyzerTest.java b/src/test/java/com/android/tools/build/bundletool/device/DeviceAnalyzerTest.java index 768c82ac..bc1ef0cf 100644 --- a/src/test/java/com/android/tools/build/bundletool/device/DeviceAnalyzerTest.java +++ b/src/test/java/com/android/tools/build/bundletool/device/DeviceAnalyzerTest.java @@ -16,13 +16,13 @@ package com.android.tools.build.bundletool.device; -import static com.android.tools.build.bundletool.model.AndroidManifest.SDK_SANDBOX_MIN_VERSION; import static com.android.tools.build.bundletool.testing.DeviceFactory.abis; import static com.android.tools.build.bundletool.testing.DeviceFactory.density; import static com.android.tools.build.bundletool.testing.DeviceFactory.deviceFeatures; import static com.android.tools.build.bundletool.testing.DeviceFactory.glExtensions; import static com.android.tools.build.bundletool.testing.DeviceFactory.locales; import static com.android.tools.build.bundletool.testing.DeviceFactory.mergeSpecs; +import static com.android.tools.build.bundletool.testing.DeviceFactory.sdkRuntimeSupported; import static com.android.tools.build.bundletool.testing.DeviceFactory.sdkVersion; import static com.google.common.truth.Truth.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -434,14 +434,18 @@ public void getDeviceSpec_deviceVersionIsPreview_sdkLevelReturnsFeatureLevel() { } @Test - public void getDeviceSpec_deviceVersionIsSandboxMin_sdkRuntimeSupported() { + public void getDeviceSpec_sdkRuntimeSupported() { String deviceId = "id1"; FakeDevice fakeDevice = FakeDevice.fromDeviceSpec( deviceId, DeviceState.ONLINE, mergeSpecs( - density(240), locales("en-US"), abis("x86"), sdkVersion(SDK_SANDBOX_MIN_VERSION))); + density(240), + locales("en-US"), + abis("x86"), + sdkVersion(34), + sdkRuntimeSupported(true))); FakeAdbServer fakeAdbServer = new FakeAdbServer( /* hasInitialDeviceList= */ true, /* devices= */ ImmutableList.of(fakeDevice)); @@ -454,7 +458,7 @@ public void getDeviceSpec_deviceVersionIsSandboxMin_sdkRuntimeSupported() { } @Test - public void getDeviceSpec_deviceVersionNotSandboxMin_sdkRuntimeNotSupported() { + public void getDeviceSpec_sdkRuntimeNotSupported() { String deviceId = "id1"; FakeDevice fakeDevice = FakeDevice.fromDeviceSpec( @@ -464,7 +468,8 @@ public void getDeviceSpec_deviceVersionNotSandboxMin_sdkRuntimeNotSupported() { density(240), locales("en-US"), abis("x86"), - sdkVersion(SDK_SANDBOX_MIN_VERSION - 1))); + sdkVersion(33), + sdkRuntimeSupported(false))); FakeAdbServer fakeAdbServer = new FakeAdbServer( /* hasInitialDeviceList= */ true, /* devices= */ ImmutableList.of(fakeDevice)); diff --git a/src/test/java/com/android/tools/build/bundletool/device/DeviceSpecUtilsTest.java b/src/test/java/com/android/tools/build/bundletool/device/DeviceSpecUtilsTest.java index 9b7728f1..56cab95b 100644 --- a/src/test/java/com/android/tools/build/bundletool/device/DeviceSpecUtilsTest.java +++ b/src/test/java/com/android/tools/build/bundletool/device/DeviceSpecUtilsTest.java @@ -40,7 +40,6 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.sdkVersionTargeting; import static com.android.tools.build.bundletool.testing.TargetingUtils.textureCompressionTargeting; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.bundle.Devices.DeviceSpec; diff --git a/src/test/java/com/android/tools/build/bundletool/device/DeviceTargetingConfigEvaluatorTest.java b/src/test/java/com/android/tools/build/bundletool/device/DeviceTargetingConfigEvaluatorTest.java index 2c8d4097..4364d306 100644 --- a/src/test/java/com/android/tools/build/bundletool/device/DeviceTargetingConfigEvaluatorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/device/DeviceTargetingConfigEvaluatorTest.java @@ -17,7 +17,6 @@ package com.android.tools.build.bundletool.device; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.android.bundle.DeviceGroup; import com.android.bundle.DeviceProperties; diff --git a/src/test/java/com/android/tools/build/bundletool/device/VariantMatcherTest.java b/src/test/java/com/android/tools/build/bundletool/device/VariantMatcherTest.java index 107b5c1e..8c834e3b 100644 --- a/src/test/java/com/android/tools/build/bundletool/device/VariantMatcherTest.java +++ b/src/test/java/com/android/tools/build/bundletool/device/VariantMatcherTest.java @@ -44,7 +44,6 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.variantDensityTargeting; import static com.android.tools.build.bundletool.testing.TargetingUtils.variantSdkTargeting; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import com.android.bundle.Commands.BuildApksResult; diff --git a/src/test/java/com/android/tools/build/bundletool/device/activitymanager/ResourceConfigParserTest.java b/src/test/java/com/android/tools/build/bundletool/device/activitymanager/ResourceConfigParserTest.java index 51b3a284..3e0fe6ac 100644 --- a/src/test/java/com/android/tools/build/bundletool/device/activitymanager/ResourceConfigParserTest.java +++ b/src/test/java/com/android/tools/build/bundletool/device/activitymanager/ResourceConfigParserTest.java @@ -17,7 +17,6 @@ package com.android.tools.build.bundletool.device.activitymanager; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.android.tools.build.bundletool.device.activitymanager.ResourceConfigParser.ResourceConfigHandler; import com.google.auto.value.AutoValue; diff --git a/src/test/java/com/android/tools/build/bundletool/mergers/BundleModuleMergerTest.java b/src/test/java/com/android/tools/build/bundletool/mergers/BundleModuleMergerTest.java index f4f30525..54efe087 100644 --- a/src/test/java/com/android/tools/build/bundletool/mergers/BundleModuleMergerTest.java +++ b/src/test/java/com/android/tools/build/bundletool/mergers/BundleModuleMergerTest.java @@ -30,7 +30,6 @@ import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.withSplitNameActivity; import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.withSplitNameService; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/mergers/ModuleSplitsToShardMergerTest.java b/src/test/java/com/android/tools/build/bundletool/mergers/ModuleSplitsToShardMergerTest.java index 416a0153..bc022cfd 100644 --- a/src/test/java/com/android/tools/build/bundletool/mergers/ModuleSplitsToShardMergerTest.java +++ b/src/test/java/com/android/tools/build/bundletool/mergers/ModuleSplitsToShardMergerTest.java @@ -58,7 +58,6 @@ import static com.google.common.collect.ImmutableMap.toImmutableMap; import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; diff --git a/src/test/java/com/android/tools/build/bundletool/mergers/SameTargetingMergerTest.java b/src/test/java/com/android/tools/build/bundletool/mergers/SameTargetingMergerTest.java index 3875272a..7c43026a 100644 --- a/src/test/java/com/android/tools/build/bundletool/mergers/SameTargetingMergerTest.java +++ b/src/test/java/com/android/tools/build/bundletool/mergers/SameTargetingMergerTest.java @@ -34,7 +34,6 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/model/AndroidManifestTest.java b/src/test/java/com/android/tools/build/bundletool/model/AndroidManifestTest.java index a8462fb8..764a7dc8 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/AndroidManifestTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/AndroidManifestTest.java @@ -27,6 +27,7 @@ import static com.android.tools.build.bundletool.model.AndroidManifest.HAS_CODE_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.ICON_ATTRIBUTE_NAME; import static com.android.tools.build.bundletool.model.AndroidManifest.ICON_RESOURCE_ID; +import static com.android.tools.build.bundletool.model.AndroidManifest.INSTALL_LOCATION_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.IS_FEATURE_SPLIT_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.LABEL_ATTRIBUTE_NAME; import static com.android.tools.build.bundletool.model.AndroidManifest.LABEL_RESOURCE_ID; @@ -83,7 +84,6 @@ import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.xmlNode; import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.xmlResourceReferenceAttribute; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -387,6 +387,19 @@ public void getVersionCode() { assertThat(androidManifest.getVersionCode()).hasValue(123); } + @Test + public void getInstallLocation() { + AndroidManifest androidManifest = + AndroidManifest.create( + xmlNode( + xmlElement( + "manifest", + xmlDecimalIntegerAttribute( + ANDROID_NAMESPACE_URI, "installLocation", INSTALL_LOCATION_RESOURCE_ID, 0), + xmlNode(xmlElement("application"))))); + assertThat(androidManifest.getInstallLocationValue()).hasValue("auto"); + } + @Test public void getVersionCode_missing_isEmpty() { AndroidManifest androidManifest = diff --git a/src/test/java/com/android/tools/build/bundletool/model/AppBundleTest.java b/src/test/java/com/android/tools/build/bundletool/model/AppBundleTest.java index 92910b7e..3f895adb 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/AppBundleTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/AppBundleTest.java @@ -25,7 +25,6 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.targetedNativeDirectory; import static com.android.tools.build.bundletool.testing.TargetingUtils.toAbi; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/model/BundleMetadataTest.java b/src/test/java/com/android/tools/build/bundletool/model/BundleMetadataTest.java index 02f7cdde..90807811 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/BundleMetadataTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/BundleMetadataTest.java @@ -17,7 +17,6 @@ package com.android.tools.build.bundletool.model; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import com.android.tools.build.bundletool.model.ModuleEntry.ModuleEntryLocationInZipSource; diff --git a/src/test/java/com/android/tools/build/bundletool/model/BundleModuleTest.java b/src/test/java/com/android/tools/build/bundletool/model/BundleModuleTest.java index 6394c53b..35917b89 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/BundleModuleTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/BundleModuleTest.java @@ -38,7 +38,6 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.moduleMinSdkVersionTargeting; import static com.android.tools.build.bundletool.testing.TestUtils.createModuleEntryForFile; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static java.util.stream.Collectors.toList; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/model/DefaultSigningConfigurationProviderTest.java b/src/test/java/com/android/tools/build/bundletool/model/DefaultSigningConfigurationProviderTest.java index fb75df33..89395ef9 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/DefaultSigningConfigurationProviderTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/DefaultSigningConfigurationProviderTest.java @@ -23,7 +23,6 @@ import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.androidManifest; import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.withMinSdkVersion; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.android.apksig.SigningCertificateLineage; import com.android.bundle.Targeting.ApkTargeting; diff --git a/src/test/java/com/android/tools/build/bundletool/model/KeystorePropertiesTest.java b/src/test/java/com/android/tools/build/bundletool/model/KeystorePropertiesTest.java index 3a696a5a..3beab0a9 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/KeystorePropertiesTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/KeystorePropertiesTest.java @@ -21,7 +21,6 @@ import static com.android.tools.build.bundletool.model.KeystoreProperties.KEY_ALIAS_PROPERTY_NAME; import static com.android.tools.build.bundletool.model.KeystoreProperties.KEY_PASSWORD_PROPERTY_NAME; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/model/ManifestDeliveryElementTest.java b/src/test/java/com/android/tools/build/bundletool/model/ManifestDeliveryElementTest.java index e5cba033..e3842a61 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/ManifestDeliveryElementTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/ManifestDeliveryElementTest.java @@ -33,7 +33,6 @@ import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.withUnsupportedCondition; import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.withUserCountriesCondition; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import com.android.aapt.Resources.XmlNode; diff --git a/src/test/java/com/android/tools/build/bundletool/model/ManifestEditorTest.java b/src/test/java/com/android/tools/build/bundletool/model/ManifestEditorTest.java index c0a75cf0..173f1ffb 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/ManifestEditorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/ManifestEditorTest.java @@ -46,11 +46,13 @@ import static com.android.tools.build.bundletool.model.AndroidManifest.REQUIRED_BY_PRIVACY_SANDBOX_SDK_ATTRIBUTE_NAME; import static com.android.tools.build.bundletool.model.AndroidManifest.REQUIRED_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME; +import static com.android.tools.build.bundletool.model.AndroidManifest.REQUIRED_SPLIT_TYPES_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.SDK_VERSION_MAJOR_ATTRIBUTE_NAME; import static com.android.tools.build.bundletool.model.AndroidManifest.SERVICE_ELEMENT_NAME; import static com.android.tools.build.bundletool.model.AndroidManifest.SPLIT_NAME_ATTRIBUTE_NAME; import static com.android.tools.build.bundletool.model.AndroidManifest.SPLIT_NAME_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.SPLIT_TYPES_ATTRIBUTE_NAME; +import static com.android.tools.build.bundletool.model.AndroidManifest.SPLIT_TYPES_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.TARGET_SANDBOX_VERSION_RESOURCE_ID; import static com.android.tools.build.bundletool.model.AndroidManifest.THEME_ATTRIBUTE_NAME; import static com.android.tools.build.bundletool.model.AndroidManifest.THEME_RESOURCE_ID; @@ -74,7 +76,6 @@ import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.xmlResourceReferenceAttribute; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.aapt.Resources.XmlAttribute; @@ -531,10 +532,18 @@ public void setSplitsRequired_lastInvocationWins() throws Exception { public void setSplitTypes() throws Exception { AndroidManifest androidManifest = createManifestWithApplicationElement(); - AndroidManifest editedManifest = androidManifest.toEditor().setSplitTypes(SPLIT_NAMES).save(); + AndroidManifest editedManifest = + androidManifest + .toEditor() + .setSplitTypes(SPLIT_NAMES, /* enableSystemAttribute= */ true) + .save(); assertThat(editedManifest.getManifestElement().getAttributes()) .containsExactly( + XmlProtoAttributeBuilder.createAndroidAttribute( + SPLIT_TYPES_ATTRIBUTE_NAME, SPLIT_TYPES_RESOURCE_ID) + .setValueAsString("config,language") + .build(), XmlProtoAttributeBuilder.create(DISTRIBUTION_NAMESPACE_URI, SPLIT_TYPES_ATTRIBUTE_NAME) .setValueAsString("config,language") .build()); @@ -545,10 +554,18 @@ public void setSplitTypes_idempotent() throws Exception { AndroidManifest androidManifest = createManifestWithApplicationElement(); AndroidManifest editedManifest = - androidManifest.toEditor().setSplitTypes(SPLIT_NAMES).setSplitTypes(SPLIT_NAMES).save(); + androidManifest + .toEditor() + .setSplitTypes(SPLIT_NAMES, /* enableSystemAttribute= */ true) + .setSplitTypes(SPLIT_NAMES, /* enableSystemAttribute= */ true) + .save(); assertThat(editedManifest.getManifestElement().getAttributes()) .containsExactly( + XmlProtoAttributeBuilder.createAndroidAttribute( + SPLIT_TYPES_ATTRIBUTE_NAME, SPLIT_TYPES_RESOURCE_ID) + .setValueAsString("config,language") + .build(), XmlProtoAttributeBuilder.create(DISTRIBUTION_NAMESPACE_URI, SPLIT_TYPES_ATTRIBUTE_NAME) .setValueAsString("config,language") .build()); @@ -559,10 +576,18 @@ public void setSplitTypes_sorted() throws Exception { AndroidManifest androidManifest = createManifestWithApplicationElement(); AndroidManifest editedManifest = - androidManifest.toEditor().setSplitTypes(ImmutableList.of("language", "config")).save(); + androidManifest + .toEditor() + .setSplitTypes( + ImmutableList.of("language", "config"), /* enableSystemAttribute= */ true) + .save(); assertThat(editedManifest.getManifestElement().getAttributes()) .containsExactly( + XmlProtoAttributeBuilder.createAndroidAttribute( + SPLIT_TYPES_ATTRIBUTE_NAME, SPLIT_TYPES_RESOURCE_ID) + .setValueAsString("config,language") + .build(), XmlProtoAttributeBuilder.create(DISTRIBUTION_NAMESPACE_URI, SPLIT_TYPES_ATTRIBUTE_NAME) .setValueAsString("config,language") .build()); @@ -575,12 +600,16 @@ public void setSplitTypes_lastInvocationWins() throws Exception { AndroidManifest editedManifest = androidManifest .toEditor() - .setSplitTypes(ImmutableList.of("base,feature")) - .setSplitTypes(SPLIT_NAMES) + .setSplitTypes(ImmutableList.of("base,feature"), /* enableSystemAttribute= */ true) + .setSplitTypes(SPLIT_NAMES, /* enableSystemAttribute= */ true) .save(); assertThat(editedManifest.getManifestElement().getAttributes()) .containsExactly( + XmlProtoAttributeBuilder.createAndroidAttribute( + SPLIT_TYPES_ATTRIBUTE_NAME, SPLIT_TYPES_RESOURCE_ID) + .setValueAsString("config,language") + .build(), XmlProtoAttributeBuilder.create(DISTRIBUTION_NAMESPACE_URI, SPLIT_TYPES_ATTRIBUTE_NAME) .setValueAsString("config,language") .build()); @@ -591,10 +620,17 @@ public void setRequiredSplitTypes() throws Exception { AndroidManifest androidManifest = createManifestWithApplicationElement(); AndroidManifest editedManifest = - androidManifest.toEditor().setRequiredSplitTypes(SPLIT_NAMES).save(); + androidManifest + .toEditor() + .setRequiredSplitTypes(SPLIT_NAMES, /* enableSystemAttribute= */ true) + .save(); assertThat(editedManifest.getManifestElement().getAttributes()) .containsExactly( + XmlProtoAttributeBuilder.createAndroidAttribute( + REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME, REQUIRED_SPLIT_TYPES_RESOURCE_ID) + .setValueAsString("config,language") + .build(), XmlProtoAttributeBuilder.create( DISTRIBUTION_NAMESPACE_URI, REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME) .setValueAsString("config,language") @@ -608,12 +644,16 @@ public void setRequiredSplitTypes_idempotent() throws Exception { AndroidManifest editedManifest = androidManifest .toEditor() - .setRequiredSplitTypes(SPLIT_NAMES) - .setRequiredSplitTypes(SPLIT_NAMES) + .setRequiredSplitTypes(SPLIT_NAMES, /* enableSystemAttribute= */ true) + .setRequiredSplitTypes(SPLIT_NAMES, /* enableSystemAttribute= */ true) .save(); assertThat(editedManifest.getManifestElement().getAttributes()) .containsExactly( + XmlProtoAttributeBuilder.createAndroidAttribute( + REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME, REQUIRED_SPLIT_TYPES_RESOURCE_ID) + .setValueAsString("config,language") + .build(), XmlProtoAttributeBuilder.create( DISTRIBUTION_NAMESPACE_URI, REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME) .setValueAsString("config,language") @@ -627,11 +667,16 @@ public void setRequiredSplitTypes_sorted() throws Exception { AndroidManifest editedManifest = androidManifest .toEditor() - .setRequiredSplitTypes(ImmutableList.of("language", "config")) + .setRequiredSplitTypes( + ImmutableList.of("language", "config"), /* enableSystemAttribute= */ true) .save(); assertThat(editedManifest.getManifestElement().getAttributes()) .containsExactly( + XmlProtoAttributeBuilder.createAndroidAttribute( + REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME, REQUIRED_SPLIT_TYPES_RESOURCE_ID) + .setValueAsString("config,language") + .build(), XmlProtoAttributeBuilder.create( DISTRIBUTION_NAMESPACE_URI, REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME) .setValueAsString("config,language") @@ -645,12 +690,17 @@ public void setRequiredSplitTypes_lastInvocationWins() throws Exception { AndroidManifest editedManifest = androidManifest .toEditor() - .setRequiredSplitTypes(ImmutableList.of("base,feature")) - .setRequiredSplitTypes(SPLIT_NAMES) + .setRequiredSplitTypes( + ImmutableList.of("base,feature"), /* enableSystemAttribute= */ true) + .setRequiredSplitTypes(SPLIT_NAMES, /* enableSystemAttribute= */ true) .save(); assertThat(editedManifest.getManifestElement().getAttributes()) .containsExactly( + XmlProtoAttributeBuilder.createAndroidAttribute( + REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME, REQUIRED_SPLIT_TYPES_RESOURCE_ID) + .setValueAsString("config,language") + .build(), XmlProtoAttributeBuilder.create( DISTRIBUTION_NAMESPACE_URI, REQUIRED_SPLIT_TYPES_ATTRIBUTE_NAME) .setValueAsString("config,language") diff --git a/src/test/java/com/android/tools/build/bundletool/model/ManifestMutatorTest.java b/src/test/java/com/android/tools/build/bundletool/model/ManifestMutatorTest.java index 84888341..f52da33a 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/ManifestMutatorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/ManifestMutatorTest.java @@ -17,11 +17,9 @@ package com.android.tools.build.bundletool.model; import static com.android.tools.build.bundletool.model.ManifestMutator.withExtractNativeLibs; -import static com.android.tools.build.bundletool.model.ManifestMutator.withProvidedSplitTypes; -import static com.android.tools.build.bundletool.model.ManifestMutator.withRequiredSplitTypes; import static com.android.tools.build.bundletool.model.ManifestMutator.withSplitsRequired; import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.androidManifest; -import static com.google.common.truth.Truth8.assertThat; +import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableList; import org.junit.Test; @@ -57,26 +55,4 @@ public void setSplitsRequiredValue() throws Exception { editedManifest = editedManifest.applyMutators(ImmutableList.of(withSplitsRequired(true))); assertThat(editedManifest.getSplitsRequiredValue()).hasValue(true); } - - @Test - public void setProvidedSplitTypesValue() throws Exception { - AndroidManifest manifest = AndroidManifest.create(androidManifest("com.test.app")); - assertThat(manifest.getProvidedSplitTypesValue()).isEmpty(); - - AndroidManifest editedManifest = - manifest.applyMutators( - ImmutableList.of(withProvidedSplitTypes(ImmutableList.of("a", "b")))); - assertThat(editedManifest.getProvidedSplitTypesValue()).hasValue(ImmutableList.of("a", "b")); - } - - @Test - public void setRequiresSplitTypesValue() throws Exception { - AndroidManifest manifest = AndroidManifest.create(androidManifest("com.test.app")); - assertThat(manifest.getRequiredSplitTypesValue()).isEmpty(); - - AndroidManifest editedManifest = - manifest.applyMutators( - ImmutableList.of(withRequiredSplitTypes(ImmutableList.of("a", "b")))); - assertThat(editedManifest.getRequiredSplitTypesValue()).hasValue(ImmutableList.of("a", "b")); - } } diff --git a/src/test/java/com/android/tools/build/bundletool/model/ModuleAbiSanitizerTest.java b/src/test/java/com/android/tools/build/bundletool/model/ModuleAbiSanitizerTest.java index c041dab9..1b1153d7 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/ModuleAbiSanitizerTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/ModuleAbiSanitizerTest.java @@ -24,7 +24,6 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.nativeLibraries; import static com.android.tools.build.bundletool.testing.TargetingUtils.targetedNativeDirectory; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.bundle.Files.NativeLibraries; @@ -103,9 +102,7 @@ public void inconsistentNativeLibraries_libFilesFilteredAwayAndNativeTargetingAd BundleModule sanitizedModule = new ModuleAbiSanitizer().sanitize(testModule); assertThat( - sanitizedModule - .getEntries() - .stream() + sanitizedModule.getEntries().stream() .map(ModuleEntry::getPath) .filter(entryPath -> entryPath.startsWith(ZipPath.create("lib"))) .map(ZipPath::toString)) diff --git a/src/test/java/com/android/tools/build/bundletool/model/ModuleSplitTest.java b/src/test/java/com/android/tools/build/bundletool/model/ModuleSplitTest.java index d5c1f136..dc684fb9 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/ModuleSplitTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/ModuleSplitTest.java @@ -51,7 +51,6 @@ import static com.android.tools.build.bundletool.testing.TestUtils.extractPaths; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/model/RequiredSplitTypesInjectorTest.java b/src/test/java/com/android/tools/build/bundletool/model/RequiredSplitTypesInjectorTest.java index e309418e..698ffccf 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/RequiredSplitTypesInjectorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/RequiredSplitTypesInjectorTest.java @@ -68,7 +68,8 @@ public void writeSplitTypeValidationInManifest_setsRequiredSplitTypesForModule() ImmutableList.of(baseSplit.getModuleName(), featureSplit.getModuleName()); ImmutableList allSplits = ImmutableList.of(baseSplit, featureSplit); ImmutableList newSplits = - RequiredSplitTypesInjector.injectSplitTypeValidation(allSplits, requiredModules); + RequiredSplitTypesInjector.injectSplitTypeValidation( + allSplits, requiredModules, /* enableSystemAttribute= */ true); baseSplit = newSplits.get(0); assertThat(getProvidedSplitTypes(baseSplit)).isEmpty(); @@ -113,7 +114,8 @@ public void writeSplitTypeValidationInManifest_setsRequiredSplitTypesForTargetin ImmutableList requiredModules = ImmutableList.of(baseSplit.getModuleName()); ImmutableList allSplits = ImmutableList.of(baseSplit, otherSplit); ImmutableList newSplits = - RequiredSplitTypesInjector.injectSplitTypeValidation(allSplits, requiredModules); + RequiredSplitTypesInjector.injectSplitTypeValidation( + allSplits, requiredModules, /* enableSystemAttribute= */ true); baseSplit = newSplits.get(0); assertThat(getProvidedSplitTypes(baseSplit)).isEmpty(); diff --git a/src/test/java/com/android/tools/build/bundletool/model/SdkAsarTest.java b/src/test/java/com/android/tools/build/bundletool/model/SdkAsarTest.java index d78ec48d..fc0a0f7f 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/SdkAsarTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/SdkAsarTest.java @@ -21,7 +21,6 @@ import static com.android.tools.build.bundletool.testing.TestUtils.createZipBuilderForModules; import static com.android.tools.build.bundletool.testing.TestUtils.createZipBuilderForSdkAsarWithModules; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/model/SdkBundleTest.java b/src/test/java/com/android/tools/build/bundletool/model/SdkBundleTest.java index 340bd0fa..098b72cd 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/SdkBundleTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/SdkBundleTest.java @@ -20,7 +20,7 @@ import static com.android.tools.build.bundletool.testing.TestUtils.createZipBuilderForModules; import static com.android.tools.build.bundletool.testing.TestUtils.createZipBuilderForSdkAsarWithModules; import static com.android.tools.build.bundletool.testing.TestUtils.createZipBuilderForSdkBundleWithModules; -import static com.google.common.truth.Truth8.assertThat; +import static com.google.common.truth.Truth.assertThat; import com.android.tools.build.bundletool.io.ZipBuilder; import java.nio.file.Path; diff --git a/src/test/java/com/android/tools/build/bundletool/model/SizeConfigurationTest.java b/src/test/java/com/android/tools/build/bundletool/model/SizeConfigurationTest.java index 42b8c72c..9eda06ab 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/SizeConfigurationTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/SizeConfigurationTest.java @@ -42,7 +42,6 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.sdkVersionTargeting; import static com.android.tools.build.bundletool.testing.TargetingUtils.textureCompressionTargeting; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import com.android.bundle.Targeting.AbiTargeting; diff --git a/src/test/java/com/android/tools/build/bundletool/model/targeting/TargetingUtilsTest.java b/src/test/java/com/android/tools/build/bundletool/model/targeting/TargetingUtilsTest.java index 25c5011b..52bb4f4e 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/targeting/TargetingUtilsTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/targeting/TargetingUtilsTest.java @@ -35,7 +35,6 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.textureCompressionTargeting; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.bundle.Targeting.Abi.AbiAlias; diff --git a/src/test/java/com/android/tools/build/bundletool/model/utils/ResourcesUtilsTest.java b/src/test/java/com/android/tools/build/bundletool/model/utils/ResourcesUtilsTest.java index ee9864db..4262cb7a 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/utils/ResourcesUtilsTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/utils/ResourcesUtilsTest.java @@ -24,7 +24,6 @@ import static com.android.tools.build.bundletool.testing.ResourcesTableFactory.type; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.aapt.ConfigurationOuterClass.Configuration; diff --git a/src/test/java/com/android/tools/build/bundletool/model/utils/SdkToolsLocatorTest.java b/src/test/java/com/android/tools/build/bundletool/model/utils/SdkToolsLocatorTest.java index a3f65477..a5901a0c 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/utils/SdkToolsLocatorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/utils/SdkToolsLocatorTest.java @@ -17,7 +17,6 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.android.tools.build.bundletool.testing.FakeSystemEnvironmentProvider; import com.google.common.collect.ImmutableMap; diff --git a/src/test/java/com/android/tools/build/bundletool/model/utils/SplitsXmlInjectorTest.java b/src/test/java/com/android/tools/build/bundletool/model/utils/SplitsXmlInjectorTest.java index e55ccb4a..206eaaa6 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/utils/SplitsXmlInjectorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/utils/SplitsXmlInjectorTest.java @@ -29,7 +29,6 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.MoreCollectors.onlyElement; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; diff --git a/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoElementBuilderTest.java b/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoElementBuilderTest.java index 27b14a5e..1d5541b9 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoElementBuilderTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoElementBuilderTest.java @@ -18,7 +18,6 @@ import static com.android.tools.build.bundletool.model.AndroidManifest.ANDROID_NAMESPACE_URI; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.aapt.Resources.SourcePosition; diff --git a/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoElementTest.java b/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoElementTest.java index cd87b47b..c0787876 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoElementTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoElementTest.java @@ -16,7 +16,6 @@ package com.android.tools.build.bundletool.model.utils.xmlproto; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoNodeBuilderTest.java b/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoNodeBuilderTest.java index 0a6525e1..5f5a61b7 100644 --- a/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoNodeBuilderTest.java +++ b/src/test/java/com/android/tools/build/bundletool/model/utils/xmlproto/XmlProtoNodeBuilderTest.java @@ -17,7 +17,6 @@ import static com.google.common.collect.MoreCollectors.onlyElement; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.aapt.Resources.XmlElement; diff --git a/src/test/java/com/android/tools/build/bundletool/optimizations/ApkOptimizationsTest.java b/src/test/java/com/android/tools/build/bundletool/optimizations/ApkOptimizationsTest.java index b3b09647..17bc9189 100644 --- a/src/test/java/com/android/tools/build/bundletool/optimizations/ApkOptimizationsTest.java +++ b/src/test/java/com/android/tools/build/bundletool/optimizations/ApkOptimizationsTest.java @@ -109,6 +109,52 @@ public void getDefaultOptimizations_0_2_0_onlySplitsByAbiDensityAndLanguage() { .build()); } + @Test + public void + getDefaultOptimizations_1_15_7_onlySplitsByAbiDensityTextureLanguageUncompressNativeLibsUncompressedDexDeviceTiersCountrySet() { + ApkOptimizations defaultOptimizations = + ApkOptimizations.getDefaultOptimizationsForVersion(Version.of("1.15.7")); + assertThat(defaultOptimizations) + .isEqualTo( + ApkOptimizations.builder() + .setSplitDimensions( + ImmutableSet.of( + ABI, + SCREEN_DENSITY, + TEXTURE_COMPRESSION_FORMAT, + LANGUAGE, + DEVICE_TIER, + COUNTRY_SET)) + .setUncompressNativeLibraries(true) + .setStandaloneDimensions(ImmutableSet.of(ABI, SCREEN_DENSITY)) + .setUncompressDexFiles(true) + .setUncompressedDexTargetSdk(UncompressedDexTargetSdk.SDK_31) + .build()); + } + + @Test + public void + getDefaultOptimizations_1_16_0_sameAs_1_15_7_uncompressedDexOnQPlus() { + ApkOptimizations defaultOptimizations = + ApkOptimizations.getDefaultOptimizationsForVersion(Version.of("1.16.0")); + assertThat(defaultOptimizations) + .isEqualTo( + ApkOptimizations.builder() + .setSplitDimensions( + ImmutableSet.of( + ABI, + SCREEN_DENSITY, + TEXTURE_COMPRESSION_FORMAT, + LANGUAGE, + DEVICE_TIER, + COUNTRY_SET)) + .setUncompressNativeLibraries(true) + .setStandaloneDimensions(ImmutableSet.of(ABI, SCREEN_DENSITY)) + .setUncompressDexFiles(true) + .setUncompressedDexTargetSdk(UncompressedDexTargetSdk.UNSPECIFIED) + .build()); + } + @Test public void getSplitDimensionsForAssetModules_returnsDimensionsSupportedByAssetModules() { ApkOptimizations optimizations = diff --git a/src/test/java/com/android/tools/build/bundletool/shards/ShardedApksFacadeTest.java b/src/test/java/com/android/tools/build/bundletool/shards/ShardedApksFacadeTest.java index c1b0721d..a8d70434 100644 --- a/src/test/java/com/android/tools/build/bundletool/shards/ShardedApksFacadeTest.java +++ b/src/test/java/com/android/tools/build/bundletool/shards/ShardedApksFacadeTest.java @@ -47,7 +47,6 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static org.mockito.Mockito.mock; diff --git a/src/test/java/com/android/tools/build/bundletool/shards/StandaloneApksGeneratorTest.java b/src/test/java/com/android/tools/build/bundletool/shards/StandaloneApksGeneratorTest.java index 5ea18aea..3a19ef28 100644 --- a/src/test/java/com/android/tools/build/bundletool/shards/StandaloneApksGeneratorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/shards/StandaloneApksGeneratorTest.java @@ -63,7 +63,6 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.MoreCollectors.onlyElement; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static org.junit.Assert.fail; diff --git a/src/test/java/com/android/tools/build/bundletool/shards/SuffixStripperTest.java b/src/test/java/com/android/tools/build/bundletool/shards/SuffixStripperTest.java index e55f6120..008c6f6c 100644 --- a/src/test/java/com/android/tools/build/bundletool/shards/SuffixStripperTest.java +++ b/src/test/java/com/android/tools/build/bundletool/shards/SuffixStripperTest.java @@ -33,7 +33,6 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.variantTextureTargeting; import static com.android.tools.build.bundletool.testing.TestUtils.createModuleEntryForFile; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.bundle.Config.SplitDimension; diff --git a/src/test/java/com/android/tools/build/bundletool/shards/SystemApksGeneratorTest.java b/src/test/java/com/android/tools/build/bundletool/shards/SystemApksGeneratorTest.java index d4d1ab33..f75d586f 100644 --- a/src/test/java/com/android/tools/build/bundletool/shards/SystemApksGeneratorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/shards/SystemApksGeneratorTest.java @@ -66,7 +66,6 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.MoreCollectors.onlyElement; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.bundle.Config.BundleConfig; diff --git a/src/test/java/com/android/tools/build/bundletool/splitters/AssetModuleSplitterTest.java b/src/test/java/com/android/tools/build/bundletool/splitters/AssetModuleSplitterTest.java index 9cbd9a56..81b963d1 100644 --- a/src/test/java/com/android/tools/build/bundletool/splitters/AssetModuleSplitterTest.java +++ b/src/test/java/com/android/tools/build/bundletool/splitters/AssetModuleSplitterTest.java @@ -38,7 +38,6 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.textureCompressionTargeting; import static com.android.tools.build.bundletool.testing.TestUtils.extractPaths; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.bundle.Config.SuffixStripping; diff --git a/src/test/java/com/android/tools/build/bundletool/splitters/AssetSlicesGeneratorTest.java b/src/test/java/com/android/tools/build/bundletool/splitters/AssetSlicesGeneratorTest.java index 29c34b62..fb10c551 100644 --- a/src/test/java/com/android/tools/build/bundletool/splitters/AssetSlicesGeneratorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/splitters/AssetSlicesGeneratorTest.java @@ -29,7 +29,6 @@ import static com.android.tools.build.bundletool.testing.TargetingUtils.targetedAssetsDirectory; import static com.android.tools.build.bundletool.testing.TestUtils.extractPaths; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.bundle.Targeting.ApkTargeting; diff --git a/src/test/java/com/android/tools/build/bundletool/splitters/BinaryArtProfilesInjectorTest.java b/src/test/java/com/android/tools/build/bundletool/splitters/BinaryArtProfilesInjectorTest.java index 38d7b446..474cb92f 100644 --- a/src/test/java/com/android/tools/build/bundletool/splitters/BinaryArtProfilesInjectorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/splitters/BinaryArtProfilesInjectorTest.java @@ -22,7 +22,6 @@ import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.androidManifest; import static com.google.common.collect.MoreCollectors.toOptional; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import com.android.bundle.Targeting.ApkTargeting; import com.android.bundle.Targeting.VariantTargeting; diff --git a/src/test/java/com/android/tools/build/bundletool/splitters/CodeTransparencyInjectorTest.java b/src/test/java/com/android/tools/build/bundletool/splitters/CodeTransparencyInjectorTest.java index c2c903f2..a46a5d59 100644 --- a/src/test/java/com/android/tools/build/bundletool/splitters/CodeTransparencyInjectorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/splitters/CodeTransparencyInjectorTest.java @@ -17,7 +17,7 @@ import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.androidManifest; import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.androidManifestForFeature; -import static com.google.common.truth.Truth8.assertThat; +import static com.google.common.truth.Truth.assertThat; import com.android.bundle.Targeting.ApkTargeting; import com.android.bundle.Targeting.VariantTargeting; diff --git a/src/test/java/com/android/tools/build/bundletool/splitters/LanguageResourcesSplitterTest.java b/src/test/java/com/android/tools/build/bundletool/splitters/LanguageResourcesSplitterTest.java index 79d99929..da9e8c26 100644 --- a/src/test/java/com/android/tools/build/bundletool/splitters/LanguageResourcesSplitterTest.java +++ b/src/test/java/com/android/tools/build/bundletool/splitters/LanguageResourcesSplitterTest.java @@ -36,7 +36,6 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.MoreCollectors.onlyElement; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static junit.framework.TestCase.fail; diff --git a/src/test/java/com/android/tools/build/bundletool/splitters/ModuleSplitterTest.java b/src/test/java/com/android/tools/build/bundletool/splitters/ModuleSplitterTest.java index 0ca1f24e..24ef8cff 100644 --- a/src/test/java/com/android/tools/build/bundletool/splitters/ModuleSplitterTest.java +++ b/src/test/java/com/android/tools/build/bundletool/splitters/ModuleSplitterTest.java @@ -102,7 +102,6 @@ import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.collect.MoreCollectors.onlyElement; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static junit.framework.TestCase.fail; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/android/tools/build/bundletool/splitters/ScreenDensityResourcesSplitterTest.java b/src/test/java/com/android/tools/build/bundletool/splitters/ScreenDensityResourcesSplitterTest.java index e3930004..e95bc391 100644 --- a/src/test/java/com/android/tools/build/bundletool/splitters/ScreenDensityResourcesSplitterTest.java +++ b/src/test/java/com/android/tools/build/bundletool/splitters/ScreenDensityResourcesSplitterTest.java @@ -54,7 +54,6 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.MoreCollectors.onlyElement; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import static junit.framework.TestCase.fail; @@ -80,7 +79,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; -import com.google.common.truth.Truth8; import com.google.protobuf.ByteString; import java.util.Collection; import java.util.List; @@ -620,7 +618,7 @@ public void densityBucket_neighbouringResources_edgeCase() throws Exception { ModuleSplit xxhdpiSplit = findModuleSplitWithScreenDensityTargeting( densitySplits, ScreenDensity.newBuilder().setDensityAlias(DensityAlias.XXHDPI).build()); - Truth8.assertThat(xxhdpiSplit.getResourceTable()).isPresent(); + assertThat(xxhdpiSplit.getResourceTable()).isPresent(); ResourceTable xxHdpiResourceTable = xxhdpiSplit.getResourceTable().get(); assertThat(xxHdpiResourceTable) diff --git a/src/test/java/com/android/tools/build/bundletool/splitters/SplitApksGeneratorTest.java b/src/test/java/com/android/tools/build/bundletool/splitters/SplitApksGeneratorTest.java index 3c1e8f66..89e8aecc 100644 --- a/src/test/java/com/android/tools/build/bundletool/splitters/SplitApksGeneratorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/splitters/SplitApksGeneratorTest.java @@ -55,11 +55,11 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.MoreCollectors.onlyElement; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; import com.android.aapt.ConfigurationOuterClass.Configuration; import com.android.aapt.Resources.ResourceTable; +import com.android.bundle.FeatureModulesConfigProto.FeatureModulesCustomConfig; import com.android.bundle.RuntimeEnabledSdkConfigProto.RuntimeEnabledSdk; import com.android.bundle.RuntimeEnabledSdkConfigProto.RuntimeEnabledSdkConfig; import com.android.bundle.SdkModulesConfigOuterClass.SdkModulesConfig; @@ -200,8 +200,7 @@ public void simpleMultipleModules_withRequiredSplitTypes() throws Exception { ImmutableList moduleSplits = splitApksGenerator.generateSplits( - bundleModule, - ApkGenerationConfiguration.builder().setEnableRequiredSplitTypes(true).build()); + bundleModule, ApkGenerationConfiguration.getDefaultInstance()); assertThat(moduleSplits).hasSize(2); ImmutableMap moduleSplitMap = @@ -218,6 +217,66 @@ public void simpleMultipleModules_withRequiredSplitTypes() throws Exception { assertConsistentRequiredSplitTypes(moduleSplits); } + @Test + public void simpleMultipleModules_withRequiredSplitTypes_experimentalTPlusVariant() + throws Exception { + TestComponent.useTestModule(this, TestModule.builder().build()); + ImmutableList bundleModule = + ImmutableList.of( + new BundleModuleBuilder("base") + .addFile("assets/leftover.txt") + .setManifest(androidManifest("com.test.app")) + .build(), + new BundleModuleBuilder("test") + .addFile("assets/test.txt") + .setManifest(androidManifest("com.test.app")) + .build()); + + ImmutableList moduleSplits = + splitApksGenerator.generateSplits( + bundleModule, + ApkGenerationConfiguration.builder().setEnableRequiredSplitTypes(true).build()); + + assertThat(moduleSplits).hasSize(4); + ImmutableMap moduleSplitMap = + Maps.uniqueIndex( + moduleSplits, + split -> + String.format( + "%s:%s", + split.getModuleName().getName(), + split + .getVariantTargeting() + .getSdkVersionTargeting() + .getValue(0) + .getMin() + .getValue())); + + assertThat(moduleSplitMap.keySet()).containsExactly("base:21", "test:21", "base:33", "test:33"); + + ModuleSplit baseModule = moduleSplitMap.get("base:21"); + assertThat(baseModule).isNotNull(); + assertThat(getRequiredSplitTypes(baseModule)).containsExactly("test__module"); + assertThat(getProvidedSplitTypes(baseModule)).isEmpty(); + + ModuleSplit testModule = moduleSplitMap.get("test:21"); + assertThat(testModule).isNotNull(); + assertThat(getRequiredSplitTypes(testModule)).isEmpty(); + assertThat(getProvidedSplitTypes(testModule)).containsExactly("test__module"); + + // TODO(b/199376532): Remove once system required split type attributes are enabled. + ModuleSplit baseModuleTPlus = moduleSplitMap.get("base:33"); + assertThat(baseModuleTPlus).isNotNull(); + assertThat(getRequiredSplitTypes(baseModuleTPlus)).containsExactly("test__module"); + assertThat(getProvidedSplitTypes(baseModuleTPlus)).isEmpty(); + ModuleSplit testModuleTPlus = moduleSplitMap.get("test:33"); + assertThat(testModuleTPlus).isNotNull(); + assertThat(getRequiredSplitTypes(testModuleTPlus)).isEmpty(); + assertThat(getProvidedSplitTypes(testModuleTPlus)).containsExactly("test__module"); + + assertConsistentRequiredSplitTypes(moduleSplits); + } + @Test public void simpleMultipleModules_withoutRequiredSplitTypes() throws Exception { TestComponent.useTestModule(this, TestModule.builder().build()); @@ -277,7 +336,6 @@ public void multipleModules_withOnlyBaseModuleWithNativeLibraries() throws Excep bundleModule, ApkGenerationConfiguration.builder() .setEnableUncompressedNativeLibraries(true) - .setEnableRequiredSplitTypes(true) .build()); VariantTargeting lVariantTargeting = @@ -352,7 +410,6 @@ public void multipleModules_multipleVariants_withTransparency() throws Exception bundleModule, ApkGenerationConfiguration.builder() .setOptimizationDimensions(ImmutableSet.of(OptimizationDimension.ABI)) - .setEnableRequiredSplitTypes(true) .build()); ApkTargeting minSdkLTargeting = apkMinSdkTargeting(/* minSdkVersion= */ ANDROID_L_API_VERSION); @@ -873,7 +930,6 @@ public void appBundleWithSdkDependencyModuleAndDensityTargeting_noDensitySplitsF appBundleWithRuntimeEnabledSdkDeps.getModules().values().asList(), ApkGenerationConfiguration.builder() .setOptimizationDimensions(ImmutableSet.of(OptimizationDimension.SCREEN_DENSITY)) - .setEnableRequiredSplitTypes(true) .build()); assertThat( @@ -1054,7 +1110,6 @@ public void appBundleWithAllSplitTargeting_requiredSplitTypesSet() { OptimizationDimension.TEXTURE_COMPRESSION_FORMAT, OptimizationDimension.DEVICE_TIER, OptimizationDimension.COUNTRY_SET)) - .setEnableRequiredSplitTypes(true) .build()); ModuleSplit baseModule = getModuleSplit(moduleSplits, "base", Optional.empty()); @@ -1110,6 +1165,119 @@ public void appBundleWithAllSplitTargeting_requiredSplitTypesSet() { assertConsistentRequiredSplitTypes(moduleSplits); } + @Test + public void appBundle_withAllSplitTargeting_andFeatureModulesConfig() { + ResourceTable appResourceTable = + resourceTable( + pkg( + USER_PACKAGE_OFFSET, + "com.test.app", + type( + 0x01, + "drawable", + entry( + 0x01, + "title_image", + fileReference("res/drawable-hdpi/title_image.jpg", HDPI), + fileReference( + "res/drawable/title_image.jpg", Configuration.getDefaultInstance()))))); + AppBundle appBundle = + new AppBundleBuilder() + .addModule( + new BundleModuleBuilder("base") + .setManifest(androidManifest("com.test.app")) + .setResourceTable(appResourceTable) + .setResourcesPackageId(2) + .addFile("assets/languages#lang_es/strings.xml") + .addFile("assets/textures#tcf_atc/textures.dat") + .addFile("assets/textures#tier_0/textures.dat") + .addFile("assets/content#countries_latam/strings.xml") + .setAssetsConfig( + assets( + targetedAssetsDirectory( + "assets/languages#lang_es", + assetsDirectoryTargeting(languageTargeting("es"))), + targetedAssetsDirectory( + "assets/textures#tcf_atc", + assetsDirectoryTargeting( + textureCompressionTargeting( + TextureCompressionFormatAlias.ATC))), + targetedAssetsDirectory( + "assets/textures#tier_0", + assetsDirectoryTargeting(deviceTierTargeting(/* value= */ 0))), + targetedAssetsDirectory( + "assets/content#countries_latam", + assetsDirectoryTargeting(countrySetTargeting("latam"))))) + .setNativeConfig( + nativeLibraries( + targetedNativeDirectory( + "lib/x86_64", nativeDirectoryTargeting(AbiAlias.X86_64)))) + .build()) + .addModule( + new BundleModuleBuilder("test") + .addFile("assets/test.txt") + .setManifest(androidManifest("com.test.app")) + .addFile("assets/languages#lang_es/strings.xml") + .addFile("assets/textures#tcf_atc/textures.dat") + .addFile("assets/textures#tier_0/textures.dat") + .addFile("assets/content#countries_latam/strings.xml") + .setAssetsConfig( + assets( + targetedAssetsDirectory( + "assets/languages#lang_es", + assetsDirectoryTargeting(languageTargeting("es"))), + targetedAssetsDirectory( + "assets/textures#tcf_atc", + assetsDirectoryTargeting( + textureCompressionTargeting( + TextureCompressionFormatAlias.ATC))), + targetedAssetsDirectory( + "assets/textures#tier_0", + assetsDirectoryTargeting(deviceTierTargeting(/* value= */ 0))), + targetedAssetsDirectory( + "assets/content#countries_latam", + assetsDirectoryTargeting(countrySetTargeting("latam"))))) + .setNativeConfig( + nativeLibraries( + targetedNativeDirectory( + "lib/x86_64", nativeDirectoryTargeting(AbiAlias.X86_64)))) + .build()) + .build(); + FeatureModulesCustomConfig featureModulesCustomConfig = + FeatureModulesCustomConfig.newBuilder().addDisableConfigSplitsModules("test").build(); + TestComponent.useTestModule( + this, + TestModule.builder() + .withAppBundle(appBundle) + .withFeatureModulesCustomConfig(Optional.of(featureModulesCustomConfig)) + .build()); + + ImmutableList moduleSplits = + splitApksGenerator.generateSplits( + appBundle.getModules().values().asList(), + ApkGenerationConfiguration.builder() + .setOptimizationDimensions( + ImmutableSet.of( + OptimizationDimension.SCREEN_DENSITY, + OptimizationDimension.ABI, + OptimizationDimension.LANGUAGE, + OptimizationDimension.TEXTURE_COMPRESSION_FORMAT, + OptimizationDimension.DEVICE_TIER, + OptimizationDimension.COUNTRY_SET)) + .build()); + + ImmutableList testModuleSplits = + moduleSplits.stream() + .filter(moduleSplit -> moduleSplit.getModuleName().getName().equals("test")) + .collect(toImmutableList()); + ImmutableList baseModuleSplits = + moduleSplits.stream() + .filter(moduleSplit -> moduleSplit.getModuleName().getName().equals("base")) + .collect(toImmutableList()); + assertThat(testModuleSplits).hasSize(1); + assertThat(baseModuleSplits.size()).isGreaterThan(1); + } + private static ModuleSplit getModuleSplit( ImmutableList moduleSplits, VariantTargeting variantTargeting, diff --git a/src/test/java/com/android/tools/build/bundletool/testing/ApksArchiveHelpers.java b/src/test/java/com/android/tools/build/bundletool/testing/ApksArchiveHelpers.java index 95538c19..20017fb7 100644 --- a/src/test/java/com/android/tools/build/bundletool/testing/ApksArchiveHelpers.java +++ b/src/test/java/com/android/tools/build/bundletool/testing/ApksArchiveHelpers.java @@ -137,7 +137,13 @@ public static Path createApksDirectory(BuildApksResult result, Path location, To } public static Variant createVariant(VariantTargeting variantTargeting, ApkSet... apkSets) { + return createVariant(/* variantNumber= */ 0, variantTargeting, apkSets); + } + + public static Variant createVariant( + int variantNumber, VariantTargeting variantTargeting, ApkSet... apkSets) { return Variant.newBuilder() + .setVariantNumber(variantNumber) .setTargeting(variantTargeting) .addAllApkSet(Arrays.asList(apkSets)) .build(); diff --git a/src/test/java/com/android/tools/build/bundletool/testing/FakeDevice.java b/src/test/java/com/android/tools/build/bundletool/testing/FakeDevice.java index 7ff29ecf..1452db99 100644 --- a/src/test/java/com/android/tools/build/bundletool/testing/FakeDevice.java +++ b/src/test/java/com/android/tools/build/bundletool/testing/FakeDevice.java @@ -61,6 +61,7 @@ public class FakeDevice extends Device { private final String serialNumber; private final ImmutableMap properties; private final Map commandInjections = new HashMap<>(); + private final boolean hasPrivacySandbox; private Optional> installApksSideEffect = Optional.empty(); private Optional> pushSideEffect = Optional.empty(); private Optional removeRemotePathSideEffect = Optional.empty(); @@ -78,7 +79,8 @@ public class FakeDevice extends Device { ImmutableList features, ImmutableList glExtensions, ImmutableMap properties, - Optional androidVersionCodeName) { + Optional androidVersionCodeName, + boolean hasPrivacySandbox) { this.state = state; this.androidVersion = new AndroidVersion(sdkVersion, androidVersionCodeName.orElse(null)); this.abis = abis; @@ -87,6 +89,7 @@ public class FakeDevice extends Device { this.properties = properties; this.glExtensions = glExtensions; this.features = features; + this.hasPrivacySandbox = hasPrivacySandbox; } public static FakeDevice fromDeviceSpecWithProperties( @@ -106,7 +109,8 @@ public static FakeDevice fromDeviceSpecWithProperties( properties, deviceSpec.getCodename().isEmpty() ? Optional.empty() - : Optional.of(deviceSpec.getCodename())); + : Optional.of(deviceSpec.getCodename()), + deviceSpec.getSdkRuntime().getSupported()); device.injectShellCommandOutput( "pm list features", () -> @@ -181,7 +185,8 @@ public static FakeDevice inDisconnectedState(String deviceId, DeviceState device ImmutableList.of(), ImmutableList.of(), ImmutableMap.of(), - Optional.empty()); + Optional.empty(), + /* hasPrivacySandbox= */ false); } @Override @@ -284,6 +289,11 @@ public void pull(ImmutableList files) { } } + @Override + public boolean supportsPrivacySandbox() { + return hasPrivacySandbox; + } + public void setInstallApksSideEffect(SideEffect sideEffect) { installApksSideEffect = Optional.of(sideEffect); } diff --git a/src/test/java/com/android/tools/build/bundletool/testing/ManifestProtoUtils.java b/src/test/java/com/android/tools/build/bundletool/testing/ManifestProtoUtils.java index 6e852d52..43116de5 100644 --- a/src/test/java/com/android/tools/build/bundletool/testing/ManifestProtoUtils.java +++ b/src/test/java/com/android/tools/build/bundletool/testing/ManifestProtoUtils.java @@ -628,11 +628,18 @@ private static ManifestMutator withDeeplink( XmlProtoAttributeBuilder.createAndroidAttribute(NAME_ATTRIBUTE_NAME, NAME_RESOURCE_ID) .setValueAsString("android.intent.action.VIEW")); - intentFilter - .getOrCreateChildElement(CATEGORY_ELEMENT_NAME) - .addAttribute( - XmlProtoAttributeBuilder.createAndroidAttribute(NAME_ATTRIBUTE_NAME, NAME_RESOURCE_ID) - .setValueAsString("android.intent.category.BROWSABLE")); + intentFilter.addChildElement( + XmlProtoElementBuilder.create(CATEGORY_ELEMENT_NAME) + .addAttribute( + XmlProtoAttributeBuilder.createAndroidAttribute( + NAME_ATTRIBUTE_NAME, NAME_RESOURCE_ID) + .setValueAsString("android.intent.category.DEFAULT"))); + intentFilter.addChildElement( + XmlProtoElementBuilder.create(CATEGORY_ELEMENT_NAME) + .addAttribute( + XmlProtoAttributeBuilder.createAndroidAttribute( + NAME_ATTRIBUTE_NAME, NAME_RESOURCE_ID) + .setValueAsString("android.intent.category.BROWSABLE"))); intentFilter .getOrCreateChildElement(DATA_ELEMENT_NAME) @@ -642,10 +649,7 @@ private static ManifestMutator withDeeplink( .addAttribute( XmlProtoAttributeBuilder.createAndroidAttribute(HOST_NAME, HOST_RESOURCE_ID) .setValueAsString(host)) - .addAttribute(pathAttributeBuilder) - .addAttribute( - XmlProtoAttributeBuilder.createAndroidAttribute(SCHEME_NAME, SCHEME_RESOURCE_ID) - .setValueAsString(scheme)); + .addAttribute(pathAttributeBuilder); }; } @@ -759,12 +763,12 @@ public static ManifestMutator withVersionName(String versionName) { .setValueAsString(versionName); } - public static ManifestMutator withInstallLocation(String installLocation) { + public static ManifestMutator withInstallLocation(int installLocation) { return manifestElement -> manifestElement .getOrCreateAndroidAttribute( INSTALL_LOCATION_ATTRIBUTE_NAME, INSTALL_LOCATION_RESOURCE_ID) - .setValueAsString(installLocation); + .setValueAsDecimalInteger(installLocation); } public static ManifestMutator withUsesSplit(String... splitIds) { diff --git a/src/test/java/com/android/tools/build/bundletool/testing/ResourcesUtilsTest.java b/src/test/java/com/android/tools/build/bundletool/testing/ResourcesUtilsTest.java index ea161df2..96aa6fb4 100644 --- a/src/test/java/com/android/tools/build/bundletool/testing/ResourcesUtilsTest.java +++ b/src/test/java/com/android/tools/build/bundletool/testing/ResourcesUtilsTest.java @@ -15,7 +15,7 @@ */ package com.android.tools.build.bundletool.testing; -import static com.google.common.truth.Truth8.assertThat; +import static com.google.common.truth.Truth.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import com.android.aapt.Resources.ResourceTable; diff --git a/src/test/java/com/android/tools/build/bundletool/testing/TestModule.java b/src/test/java/com/android/tools/build/bundletool/testing/TestModule.java index f2b34e7b..f5fc459c 100644 --- a/src/test/java/com/android/tools/build/bundletool/testing/TestModule.java +++ b/src/test/java/com/android/tools/build/bundletool/testing/TestModule.java @@ -21,6 +21,7 @@ import com.android.bundle.Config.BundleConfig; import com.android.bundle.Config.Bundletool; import com.android.bundle.Devices.DeviceSpec; +import com.android.bundle.FeatureModulesConfigProto.FeatureModulesCustomConfig; import com.android.tools.build.bundletool.commands.BuildApksCommand; import com.android.tools.build.bundletool.commands.BuildApksCommand.ApkBuildMode; import com.android.tools.build.bundletool.commands.BuildSdkApksCommand; @@ -41,12 +42,14 @@ import com.android.tools.build.bundletool.model.version.BundleToolVersion; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import dagger.Module; import dagger.Provides; import java.io.IOException; import java.io.PrintStream; import java.io.UncheckedIOException; import java.nio.file.Path; +import java.util.Optional; import java.util.function.Consumer; import java.util.zip.ZipFile; import javax.annotation.Nullable; @@ -135,6 +138,7 @@ public static class Builder { @Nullable private SourceStamp sourceStamp; private Boolean enableRequiredSplitTypes = true; private BundleMetadata bundleMetadata = DEFAULT_BUNDLE_METADATA; + Optional featureModulesCustomConfig = Optional.empty(); public Builder withAppBundle(AppBundle appBundle) { this.bundle = appBundle; @@ -267,6 +271,13 @@ public Builder withEnableRequiredSplitTypes(boolean enableRequiredSplitTypes) { return this; } + @CanIgnoreReturnValue + public Builder withFeatureModulesCustomConfig( + Optional featureModulesCustomConfig) { + this.featureModulesCustomConfig = featureModulesCustomConfig; + return this; + } + public TestModule build() { try { if (tempDirectory == null) { @@ -324,7 +335,8 @@ public TestModule build() { BuildApksCommand.builder() .setAapt2Command(Aapt2Helper.getAapt2Command()) .setBundlePath(bundlePath) - .setOutputFile(outputPath); + .setOutputFile(outputPath) + .setFeatureModulesCustomConfig(featureModulesCustomConfig); BuildSdkApksCommand.Builder sdkCommand = BuildSdkApksCommand.builder() diff --git a/src/test/java/com/android/tools/build/bundletool/testing/TestUtils.java b/src/test/java/com/android/tools/build/bundletool/testing/TestUtils.java index fe7312be..f6222dae 100644 --- a/src/test/java/com/android/tools/build/bundletool/testing/TestUtils.java +++ b/src/test/java/com/android/tools/build/bundletool/testing/TestUtils.java @@ -266,8 +266,7 @@ public static XmlNode createSdkAndroidManifest() { } public static XmlNode createInvalidSdkAndroidManifest() { - return androidManifest( - PACKAGE_NAME, withMinSdkVersion(32), withInstallLocation("preferExternal")); + return androidManifest(PACKAGE_NAME, withMinSdkVersion(32), withInstallLocation(2)); } private static SdkMetadata getSdkMetadata() { diff --git a/src/test/java/com/android/tools/build/bundletool/validation/SdkAndroidManifestValidatorTest.java b/src/test/java/com/android/tools/build/bundletool/validation/SdkAndroidManifestValidatorTest.java index 3a25a0f8..ec356ae9 100644 --- a/src/test/java/com/android/tools/build/bundletool/validation/SdkAndroidManifestValidatorTest.java +++ b/src/test/java/com/android/tools/build/bundletool/validation/SdkAndroidManifestValidatorTest.java @@ -98,7 +98,7 @@ public void manifest_withSdkPatchVersionProperty_throws() { public void manifest_withPreferExternal_throws() { BundleModule module = new BundleModuleBuilder(BASE_MODULE_NAME) - .setManifest(androidManifest(PKG_NAME, withInstallLocation("preferExternal"))) + .setManifest(androidManifest(PKG_NAME, withInstallLocation(2))) .build(); Throwable exception = diff --git a/src/test/java/com/android/tools/build/bundletool/validation/ValidatorRunnerTest.java b/src/test/java/com/android/tools/build/bundletool/validation/ValidatorRunnerTest.java index 1f0b1564..6b8fd219 100644 --- a/src/test/java/com/android/tools/build/bundletool/validation/ValidatorRunnerTest.java +++ b/src/test/java/com/android/tools/build/bundletool/validation/ValidatorRunnerTest.java @@ -19,7 +19,6 @@ import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.androidManifest; import static com.android.tools.build.bundletool.testing.ManifestProtoUtils.withSplitId; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth8.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce;