/** Builds a map of module dependencies. */ private static ImmutableMultimap<String, String> buildAdjacencyMap(Variant variant) { ImmutableMultimap.Builder<String, String> moduleDependenciesMap = ImmutableMultimap.builder(); variant .getApkSetList() .stream() .map(ApkSet::getModuleMetadata) .forEach( moduleMetadata -> { moduleDependenciesMap.putAll( moduleMetadata.getName(), moduleMetadata.getDependenciesList()); moduleDependenciesMap.put(moduleMetadata.getName(), "base"); }); return moduleDependenciesMap.build(); }
List<ApkSet> splitApkSetList = splitApkVariants(result).get(0).getApkSetList(); Map<String, ApkSet> modules = Maps.uniqueIndex(splitApkSetList, apkSet -> apkSet.getModuleMetadata().getName()); assertThat(modules.keySet()).containsExactly("base", "feature");
.collect( toImmutableMap( apkSet -> apkSet.getModuleMetadata().getName(), apkSet -> apkSet.getApkDescriptionList())); assertThat(splitApksByModule.keySet())
ImmutableMap<String, ApkSet> splitApkSetByModuleName = Maps.uniqueIndex( splitApkVariant.getApkSetList(), apkSet -> apkSet.getModuleMetadata().getName()); assertThat(splitApkSetByModuleName).hasSize(4); assertThat(baseSplits.getModuleMetadata().getDependenciesList()).isEmpty(); assertThat(feature1Splits.getModuleMetadata().getDependenciesList()).isEmpty(); assertThat(feature2Splits.getModuleMetadata().getDependenciesList()) .containsExactly("feature1"); assertThat(feature3Splits.getModuleMetadata().getDependenciesList()) .containsExactly("feature1", "feature2"); List<ApkSet> apkSetList = standaloneApkVariants(result).get(0).getApkSetList(); assertThat(apkSetList).hasSize(1); assertThat(apkSetList.get(0).getModuleMetadata().getDependenciesList()).isEmpty();
assertThat(standaloneApkVariant.getApkSetList()).hasSize(1); ApkSet shards = standaloneApkVariant.getApkSet(0); assertThat(shards.getModuleMetadata().getName()).isEqualTo("base"); assertThat(shards.getApkDescriptionList()).hasSize(1);
ImmutableMap<String, ApkSet> splitApkSetByModuleName = Maps.uniqueIndex( splitApkVariant.getApkSetList(), apkSet -> apkSet.getModuleMetadata().getName()); assertThat(splitApkSetByModuleName).hasSize(2); assertThat(baseSplits.getModuleMetadata().getName()).isEqualTo("base"); assertThat(baseSplits.getModuleMetadata().getOnDemand()).isFalse(); assertThat(baseSplits.getApkDescriptionList()).hasSize(1); assertThat(apkSetFile).hasFile(baseSplits.getApkDescription(0).getPath()); assertThat(onDemandSplits.getModuleMetadata().getName()).isEqualTo("onDemand"); assertThat(onDemandSplits.getModuleMetadata().getOnDemand()).isTrue(); assertThat(onDemandSplits.getApkDescriptionList()).hasSize(1); assertThat(apkSetFile).hasFile(onDemandSplits.getApkDescription(0).getPath());
assertThat(variant.getApkSetList()).hasSize(1); ApkSet apkSet = variant.getApkSetList().get(0); assertThat(apkSet.getModuleMetadata().getIsInstant()).isTrue(); assertThat(apkSetFile).hasFile(apkSet.getApkDescription(0).getPath()); assertThat(variant.getApkSetList()).hasSize(1); apkSet = variant.getApkSetList().get(0); assertThat(apkSet.getModuleMetadata().getIsInstant()).isTrue(); assertThat(apkSetFile).hasFile(apkSet.getApkDescription(0).getPath());
@Test public void buildApksCommand_standalone_oneModuleOneVariant() throws Exception { bundlePath = FileUtils.getRandomFilePath(tmp, "bundle-", ".aab"); AppBundle appBundle = new AppBundleBuilder() .addModule( "base", builder -> builder.addFile("dex/classes.dex").setManifest(androidManifest("com.test.app"))) .build(); bundleSerializer.writeToDisk(appBundle, bundlePath); BuildApksCommand command = BuildApksCommand.builder() .setBundlePath(bundlePath) .setOutputFile(outputFilePath) .setAapt2Command(aapt2Command) .build(); Path apkSetFilePath = execute(command); ZipFile apkSetFile = new ZipFile(apkSetFilePath.toFile()); BuildApksResult result = extractTocFromApkSetFile(apkSetFile, outputDir); assertThat(standaloneApkVariants(result)).hasSize(1); Variant standaloneApkVariant = standaloneApkVariants(result).get(0); assertThat(standaloneApkVariant.getApkSetList()).hasSize(1); ApkSet shards = standaloneApkVariant.getApkSet(0); assertThat(shards.getModuleMetadata().getName()).isEqualTo("base"); assertThat(shards.getApkDescriptionList()).hasSize(1); assertThat(ZipPath.create(shards.getApkDescription(0).getPath()).getFileName()) .isEqualTo(ZipPath.create("standalone.apk")); assertThat(apkSetFile).hasFile(shards.getApkDescription(0).getPath()); }
@VisibleForTesting ImmutableList<Path> execute(PrintStream output) { validateInput(); BuildApksResult toc = ResultUtils.readTableOfContents(getApksArchivePath()); Optional<ImmutableSet<String>> requestedModuleNames = getModules() .map( modules -> modules.contains(ALL_MODULES_SHORTCUT) ? toc.getVariantList().stream() .flatMap(variant -> variant.getApkSetList().stream()) .map(apkSet -> apkSet.getModuleMetadata().getName()) .collect(toImmutableSet()) : modules); ApkMatcher apkMatcher = new ApkMatcher(getDeviceSpec(), requestedModuleNames, getInstant()); ImmutableList<ZipPath> matchedApks = apkMatcher.getMatchingApks(toc); if (Files.isDirectory(getApksArchivePath())) { return matchedApks.stream() .map(matchedApk -> getApksArchivePath().resolve(matchedApk.toString())) .collect(toImmutableList()); } else { return extractMatchedApksFromApksArchive(matchedApks); } }
public static Variant standaloneVariant( VariantTargeting variantTargeting, ApkTargeting apkTargeting, ZipPath apkPath) { // A standalone variant has only a single APK with module named "base". return createVariant( variantTargeting, ApkSet.newBuilder() .setModuleMetadata(ModuleMetadata.newBuilder().setName("base")) .addApkDescription( ApkDescription.newBuilder() .setTargeting(apkTargeting) .setPath(apkPath.toString()) // Contents of the standalone APK metadata is not important for these tests // as long as the field is set. .setStandaloneApkMetadata(StandaloneApkMetadata.getDefaultInstance())) .build()); }
public ImmutableList<ZipPath> getMatchingApksFromVariant(Variant variant) { ImmutableList.Builder<ZipPath> matchedApksBuilder = ImmutableList.builder(); Predicate<String> moduleNameMatcher = getModuleNameMatcher(variant); for (ApkSet apkSet : variant.getApkSetList()) { String moduleName = apkSet.getModuleMetadata().getName(); for (ApkDescription apkDescription : apkSet.getApkDescriptionList()) { ApkTargeting apkTargeting = apkDescription.getTargeting(); boolean isSplit = !apkDescription.hasStandaloneApkMetadata(); checkCompatibleWithApkTargeting(apkTargeting); if (matchesApk(apkTargeting, isSplit, moduleName, moduleNameMatcher)) { matchedApksBuilder.add(ZipPath.create(apkDescription.getPath())); } } } return matchedApksBuilder.build(); }
public static ApkSet createSystemApkSet(ApkTargeting apkTargeting, Path apkPath) { // Note: System APK is represented as a module named "base". return ApkSet.newBuilder() .setModuleMetadata(ModuleMetadata.newBuilder().setName("base")) .addApkDescription( ApkDescription.newBuilder() .setPath(apkPath.toString()) .setTargeting(apkTargeting) .setSystemApkMetadata( SystemApkMetadata.newBuilder() .addFusedModuleName("base") .setSystemApkType(SystemApkType.SYSTEM))) .build(); } }
@Test public void getModuleMetadata_targeting_presentIfConditionsUsed() throws Exception { BundleModule bundleModule = createMinimalModuleBuilder() .setAndroidManifestProto( androidManifest( "com.test.app", withFeatureCondition("com.android.hardware.feature"), withMinSdkCondition(24))) .build(); assertThat(bundleModule.getModuleMetadata().getTargeting()) .isEqualTo( mergeModuleTargeting( moduleFeatureTargeting("com.android.hardware.feature"), moduleMinSdkVersionTargeting(/* minSdkVersion= */ 24))); }
public static ApkSet createSplitApkSet( String moduleName, boolean onDemand, ImmutableList<String> moduleDependencies, ApkDescription... apkDescription) { return ApkSet.newBuilder() .setModuleMetadata( ModuleMetadata.newBuilder() .setName(moduleName) .setOnDemand(onDemand) .addAllDependencies(moduleDependencies)) .addAllApkDescription(Arrays.asList(apkDescription)) .build(); }
public static ApkSet splitApkSet( String moduleName, boolean onDemand, ImmutableList<String> moduleDependencies, ApkDescription... apkDescriptions) { return ApkSet.newBuilder() .setModuleMetadata( ModuleMetadata.newBuilder() .setName(moduleName) .setOnDemand(onDemand) .addAllDependencies(moduleDependencies)) .addAllApkDescription(Arrays.asList(apkDescriptions)) .build(); }
private boolean willBeDeliveredInstallTime(ModuleMetadata moduleMetadata) { return !moduleMetadata.getOnDemand() && moduleMatcher.matchesModuleTargeting(moduleMetadata.getTargeting()); }
public static ApkSet createStandaloneApkSet(ApkTargeting apkTargeting, Path apkPath) { // Note: Standalone APK is represented as a module named "base". return ApkSet.newBuilder() .setModuleMetadata(ModuleMetadata.newBuilder().setName("base")) .addApkDescription( ApkDescription.newBuilder() .setPath(apkPath.toString()) .setTargeting(apkTargeting) .setStandaloneApkMetadata( StandaloneApkMetadata.newBuilder().addFusedModuleName("base"))) .build(); }
public static ApkSet createConditionalApkSet( String moduleName, ModuleTargeting moduleTargeting, ApkDescription... apkDescriptions) { return ApkSet.newBuilder() .setModuleMetadata( ModuleMetadata.newBuilder() .setName(moduleName) .setTargeting(moduleTargeting) .setOnDemand(false)) .addAllApkDescription(Arrays.asList(apkDescriptions)) .build(); }
@Test public void getModuleMetadata_targeting_emptyIfNoConditions() throws Exception { BundleModule bundleModule = createMinimalModuleBuilder() .setAndroidManifestProto(androidManifest("com.test.app")) .build(); assertThat(bundleModule.getModuleMetadata().getTargeting()).isEqualToDefaultInstance(); }
/** Creates an instant apk set with the given module name, ApkTargeting, and path for the apk. */ public static ApkSet createInstantApkSet( String moduleName, ApkTargeting apkTargeting, Path apkPath) { return ApkSet.newBuilder() .setModuleMetadata(ModuleMetadata.newBuilder().setName(moduleName).setIsInstant(true)) .addApkDescription( ApkDescription.newBuilder() .setPath(apkPath.toString()) .setTargeting(apkTargeting) .setInstantApkMetadata(SplitApkMetadata.newBuilder().setIsMasterSplit(true))) .build(); }