/** Builds a list of modules that will be delivered on installation. */ private ImmutableSet<String> buildModulesDeliveredInstallTime(Variant variant) { // Module dependency resolution can be skipped because install-time modules can't depend on // on-demand modules. return variant.getApkSetList().stream() .map(ApkSet::getModuleMetadata) .filter(this::willBeDeliveredInstallTime) .map(ModuleMetadata::getName) .collect(toImmutableSet()); }
public static boolean isStandaloneApkVariant(Variant variant) { return variant .getApkSetList() .stream() .flatMap(apkSet -> apkSet.getApkDescriptionList().stream()) .allMatch(ApkDescription::hasStandaloneApkMetadata); }
private static boolean isVariantInstant(Variant variant) { return variant.getApkSetList().stream() .flatMap(apkSet -> apkSet.getApkDescriptionList().stream()) .allMatch(ApkDescription::hasInstantApkMetadata); }
private ConfigurationSizes getSizeStandaloneVariant() { checkState( !getSizeRequest.getInstant(), "Standalone Variants cant be selected when instant flag is set"); // When modules are specified we ignore standalone variants. if (getSizeRequest.getModules().isPresent()) { return ConfigurationSizes.create(ImmutableMap.of(), ImmutableMap.of()); } VariantTargeting variantTargeting = variant.getTargeting(); SizeConfiguration sizeConfiguration = mergeWithDeviceSpec( getSizeConfiguration( variantTargeting.getSdkVersionTargeting(), variantTargeting.getAbiTargeting(), variantTargeting.getScreenDensityTargeting(), LanguageTargeting.getDefaultInstance()), getSizeRequest.getDeviceSpec()); // Variants of standalone APKs have only one APK each. long compressedSize = sizeByApkPaths.get( Iterables.getOnlyElement( Iterables.getOnlyElement(variant.getApkSetList()).getApkDescriptionList()) .getPath()); ImmutableMap<SizeConfiguration, Long> sizeConfigurationMap = ImmutableMap.of(sizeConfiguration, compressedSize); return ConfigurationSizes.create(sizeConfigurationMap, sizeConfigurationMap); }
ImmutableList<String> apkPaths = variants.stream() .flatMap(variant -> variant.getApkSetList().stream()) .flatMap(apkSet -> apkSet.getApkDescriptionList().stream()) .map(ApkDescription::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); } }
@Test public void deviceSpec_correctSplitsGenerated() throws Exception { DeviceSpec deviceSpec = lDeviceWithDensity(XHDPI); bundleSerializer.writeToDisk(createLdpiHdpiAppBundle(), bundlePath); BuildApksCommand command = BuildApksCommand.builder() .setBundlePath(bundlePath) .setOutputFile(outputFilePath) .setDeviceSpec(deviceSpec) .build(); Path apksArchive = command.execute(); ZipFile apksZipFile = new ZipFile(apksArchive.toFile()); assertThat(apksZipFile) .containsExactlyEntries("toc.pb", "splits/base-master.apk", "splits/base-xhdpi.apk"); BuildApksResult result = extractTocFromApkSetFile(apksZipFile, outputDir); assertThat(result.getVariantList()).hasSize(1); Variant variant = result.getVariant(0); assertThat(variant.getApkSetList()).hasSize(1); ApkSet apkSet = variant.getApkSet(0); // One master and one density split. assertThat(apkSet.getApkDescriptionList()).hasSize(2); assertThat(apkNamesInSet(apkSet)) .containsExactly("splits/base-master.apk", "splits/base-xhdpi.apk"); }
@Test public void deviceSpec_correctStandaloneGenerated() throws Exception { DeviceSpec deviceSpec = mergeSpecs(sdkVersion(19), abis("x86"), locales("en-US"), density(HDPI)); bundleSerializer.writeToDisk(createLdpiHdpiAppBundle(), bundlePath); BuildApksCommand command = BuildApksCommand.builder() .setBundlePath(bundlePath) .setOutputFile(outputFilePath) .setDeviceSpec(deviceSpec) .build(); Path apksArchive = command.execute(); ZipFile apksZipFile = new ZipFile(apksArchive.toFile()); assertThat(apksZipFile).containsExactlyEntries("toc.pb", "standalones/standalone-hdpi.apk"); BuildApksResult result = extractTocFromApkSetFile(apksZipFile, outputDir); assertThat(result.getVariantList()).hasSize(1); Variant variant = result.getVariant(0); assertThat(variant.getApkSetList()).hasSize(1); ApkSet apkSet = variant.getApkSet(0); // One standalone APK. assertThat(apkSet.getApkDescriptionList()).hasSize(1); assertThat(apkNamesInSet(apkSet)).containsExactly("standalones/standalone-hdpi.apk"); }
private void validateVariant(Variant variant) { if (requestedModuleNames.isPresent()) { Set<String> unknownModules = Sets.difference( requestedModuleNames.get(), variant .getApkSetList() .stream() .map(ApkSet::getModuleMetadata) .map(ModuleMetadata::getName) .collect(toImmutableSet())); if (!unknownModules.isEmpty()) { throw ValidationException.builder() .withMessage( "The APK Set archive does not contain the following modules: %s", unknownModules) .build(); } } }
/** 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(); }
private void assertThatApksAreSigned( BuildApksResult result, ZipFile apkSetFile, X509Certificate expectedCertificate) throws Exception { for (Variant variant : result.getVariantList()) { for (ApkSet apkSet : variant.getApkSetList()) { for (ApkDescription apkDescription : apkSet.getApkDescriptionList()) { File apk = extractFromApkSetFile(apkSetFile, apkDescription.getPath(), outputDir); ApkVerifier.Result verifierResult = new ApkVerifier.Builder(apk).build().verify(); assertThat(verifierResult.isVerified()).isTrue(); assertThat(verifierResult.getSignerCertificates()).containsExactly(expectedCertificate); } } } }
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(); }
private ConfigurationSizes getSizeNonStandaloneVariant() { ImmutableList<ApkDescription> apkDescriptions = variant.getApkSetList().stream() .flatMap(apkSet -> apkSet.getApkDescriptionList().stream()) .collect(toImmutableList()); ImmutableSet<AbiTargeting> abiTargetingOptions = getAllAbiTargetings(apkDescriptions); ImmutableSet<LanguageTargeting> languageTargetingOptions = getAllLanguageTargetings(apkDescriptions); ImmutableSet<ScreenDensityTargeting> screenDensityTargetingOptions = getAllScreenDensityTargetings(apkDescriptions); return getSizesPerConfiguration( abiTargetingOptions, languageTargetingOptions, screenDensityTargetingOptions); }
public static Path createApksDirectory(BuildApksResult result, Path location) throws Exception { ImmutableList<ApkDescription> apkDescriptions = result.getVariantList().stream() .flatMap(variant -> variant.getApkSetList().stream()) .flatMap(apkSet -> apkSet.getApkDescriptionList().stream()) .collect(toImmutableList()); for (ApkDescription apkDescription : apkDescriptions) { Path apkPath = location.resolve(apkDescription.getPath()); Files.createDirectories(apkPath.getParent()); Files.write(apkPath, DUMMY_BYTES); } Files.write(location.resolve("toc.pb"), result.toByteArray()); return location; }
public static Path createApksArchiveFile(BuildApksResult result, Path location) throws Exception { ZipBuilder archiveBuilder = new ZipBuilder(); result.getVariantList().stream() .flatMap(variant -> variant.getApkSetList().stream()) .flatMap(apkSet -> apkSet.getApkDescriptionList().stream()) .forEach( apkDesc -> archiveBuilder.addFileWithContent(ZipPath.create(apkDesc.getPath()), DUMMY_BYTES)); archiveBuilder.addFileWithProtoContent(ZipPath.create("toc.pb"), result); return archiveBuilder.writeTo(location); }
private static ImmutableList<String> apkNamesInVariant(Variant variant) { return variant.getApkSetList().stream() .flatMap(apkSet -> apkSet.getApkDescriptionList().stream()) // Get just the filename. .map(ApkDescription::getPath) .map(ZipPath::create) .map(ZipPath::getFileName) .map(ZipPath::toString) .collect(toImmutableList()); }
private static ImmutableList<ApkDescription> apkDescriptions(Variant variant) { return variant.getApkSetList().stream() .flatMap(apkSet -> apkSet.getApkDescriptionList().stream()) .collect(toImmutableList()); }
public static boolean isSystemApkVariant(Variant variant) { return variant.getApkSetList().stream() .flatMap(apkSet -> apkSet.getApkDescriptionList().stream()) .allMatch(ApkDescription::hasSystemApkMetadata); }
public static boolean isSplitApkVariant(Variant variant) { return variant .getApkSetList() .stream() .flatMap(apkSet -> apkSet.getApkDescriptionList().stream()) .allMatch(ApkDescription::hasSplitApkMetadata); }
public static boolean isInstantApkVariant(Variant variant) { return variant .getApkSetList() .stream() .flatMap(apkSet -> apkSet.getApkDescriptionList().stream()) .allMatch(ApkDescription::hasInstantApkMetadata); }