Skip to content

Commit

Permalink
Prepare for release 0.10.1.
Browse files Browse the repository at this point in the history
  • Loading branch information
plecesne committed Jul 12, 2019
1 parent 5ac94cb commit b2542c9
Show file tree
Hide file tree
Showing 15 changed files with 227 additions and 25 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ https://developer.android.com/studio/command-line/bundletool

## Releases

Latest release: [0.10.0](https://github.com/google/bundletool/releases)
Latest release: [0.10.1](https://github.com/google/bundletool/releases)
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
release_version = 0.10.0
release_version = 0.10.1
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
public class DeviceFeaturesParser {

private static final String EXPECTED_LINE_PREFIX = "feature:";
private static final String WARNING_LINE_PREFIX = "WARNING:";

/** Parses the "pm list features" command output. */
public ImmutableList<String> parse(ImmutableList<String> packageManagerListOutput) {
Expand All @@ -32,6 +33,9 @@ public ImmutableList<String> parse(ImmutableList<String> packageManagerListOutpu
if (line.isEmpty()) {
continue;
}
if (line.startsWith(WARNING_LINE_PREFIX)) {
continue;
}
if (!line.startsWith(EXPECTED_LINE_PREFIX)) {
throw ParseException.builder()
.withMessage("Unexpected output of 'pm list features' command: '%s'", line)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public abstract class AndroidManifest {
public static final String SPLIT_NAME_ATTRIBUTE_NAME = "splitName";
public static final String VERSION_NAME_ATTRIBUTE_NAME = "versionName";
public static final String INSTALL_LOCATION_ATTRIBUTE_NAME = "installLocation";
public static final String IS_SPLIT_REQUIRED_ATTRIBUTE_NAME = "isSplitRequired";

public static final String MODULE_TYPE_FEATURE_VALUE = "feature";
public static final String MODULE_TYPE_ASSET_VALUE = "asset-pack";
Expand All @@ -107,6 +108,7 @@ public abstract class AndroidManifest {
public static final int TARGET_SANDBOX_VERSION_RESOURCE_ID = 0x0101054c;
public static final int SPLIT_NAME_RESOURCE_ID = 0x01010549;
public static final int INSTALL_LOCATION_RESOURCE_ID = 0x010102b7;
public static final int IS_SPLIT_REQUIRED_RESOURCE_ID = 0x01010591;

// 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package com.android.tools.build.bundletool.model;

import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
Expand Down Expand Up @@ -232,7 +231,11 @@ private static ImmutableList<BundleModule> extractModules(

private static BundleConfig readBundleConfig(ZipFile bundleFile) {
ZipEntry bundleConfigEntry = bundleFile.getEntry(BUNDLE_CONFIG_FILE_NAME);
checkState(bundleConfigEntry != null, "File '%s' was not found.", BUNDLE_CONFIG_FILE_NAME);
if (bundleConfigEntry == null) {
throw ValidationException.builder()
.withMessage("File '%s' was not found.", BUNDLE_CONFIG_FILE_NAME)
.build();
}

try (InputStream is = BufferedIo.inputStream(bundleFile, bundleConfigEntry)) {
return BundleConfig.parseFrom(is);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,10 @@ public abstract static class Builder {

public abstract Builder setResourceTable(ResourceTable resourceTable);

public Builder setAndroidManifest(AndroidManifest androidManifest) {
return setAndroidManifestProto(androidManifest.getManifestRoot().getProto());
}

public abstract Builder setAndroidManifestProto(XmlNode manifestProto);

public abstract Builder setAssetsConfig(Assets assetsConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import static com.android.tools.build.bundletool.model.AndroidManifest.GL_VERSION_ATTRIBUTE_NAME;
import static com.android.tools.build.bundletool.model.AndroidManifest.HAS_CODE_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.IS_SPLIT_REQUIRED_ATTRIBUTE_NAME;
import static com.android.tools.build.bundletool.model.AndroidManifest.IS_SPLIT_REQUIRED_RESOURCE_ID;
import static com.android.tools.build.bundletool.model.AndroidManifest.MAX_SDK_VERSION_ATTRIBUTE_NAME;
import static com.android.tools.build.bundletool.model.AndroidManifest.MAX_SDK_VERSION_RESOURCE_ID;
import static com.android.tools.build.bundletool.model.AndroidManifest.META_DATA_ELEMENT_NAME;
Expand Down Expand Up @@ -213,13 +215,26 @@ public ManifestEditor setFusedModuleNames(ImmutableList<String> moduleNames) {
/**
* Sets a flag whether the app is able to run without any config splits.
*
* <p>The information is stored as a {@code <meta-data android:name="..." android:value="..."/>}
* element inside the {@code <application>} element.
* <p>The information is stored as:
*
* <ul>
* <li>{@code <meta-data android:name="..." android:value="..."/>} element inside the {@code
* <application>} element (read by the PlayCore library).
* <li>{@code <application android:isSplitRequired="..."/>} attribute (read by the Android
* Platform since Q).
* </ul>
*/
public ManifestEditor setSplitsRequired(boolean value) {
setMetadataValue(
META_DATA_KEY_SPLITS_REQUIRED,
createAndroidAttribute("value", VALUE_RESOURCE_ID).setValueAsBoolean(value));

manifestElement
.getOrCreateChildElement(APPLICATION_ELEMENT_NAME)
.getOrCreateAndroidAttribute(
IS_SPLIT_REQUIRED_ATTRIBUTE_NAME, IS_SPLIT_REQUIRED_RESOURCE_ID)
.setValueAsBoolean(value);

return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
*/
public final class BundleToolVersion {

private static final String CURRENT_VERSION = "0.10.0";
private static final String CURRENT_VERSION = "0.10.1";

/** Returns the version of BundleTool being run. */
public static Version getCurrentVersion() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import com.android.bundle.Targeting.ModuleTargeting;
import com.android.tools.build.bundletool.model.AndroidManifest;
import com.android.tools.build.bundletool.model.AppBundle;
import com.android.tools.build.bundletool.model.BundleModule;
import com.android.tools.build.bundletool.model.BundleModule.ModuleDeliveryType;
import com.android.tools.build.bundletool.model.BundleModule.ModuleType;
Expand All @@ -42,6 +43,7 @@
import com.android.tools.build.bundletool.model.exceptions.manifest.ManifestSdkTargetingException.MinSdkInvalidException;
import com.android.tools.build.bundletool.model.exceptions.manifest.ManifestVersionCodeConflictException;
import com.android.tools.build.bundletool.model.utils.xmlproto.XmlProtoAttribute;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
Expand All @@ -50,6 +52,8 @@
/** Validates {@code AndroidManifest.xml} file of each module. */
public class AndroidManifestValidator extends SubValidator {

private static final int UPFRONT_ASSET_PACK_MIN_SDK_VERSION = 21;

@Override
public void validateAllModules(ImmutableList<BundleModule> modules) {
validateSameVersionCode(modules);
Expand Down Expand Up @@ -109,6 +113,20 @@ public void validateModule(BundleModule module) {
validateInstantAndPersistentDeliveryCombinationsForAssetModules(module);
}

@Override
public void validateBundle(AppBundle appBundle) {
int minSdkVersion = appBundle.getBaseModule().getAndroidManifest().getEffectiveMinSdkVersion();
if (hasUpfrontModule(appBundle.getAssetModules().values())
&& minSdkVersion < UPFRONT_ASSET_PACK_MIN_SDK_VERSION) {
throw ValidationException.builder()
.withMessage(
"Asset packs with install time delivery are not supported in SDK %s. Please set"
+ " minimum supported SDK to at least %s.",
minSdkVersion, UPFRONT_ASSET_PACK_MIN_SDK_VERSION)
.build();
}
}

private void validateInstant(ImmutableList<BundleModule> modules) {
// If any module is 'instant' validate that 'base' is instant too.
BundleModule baseModule =
Expand Down Expand Up @@ -352,4 +370,12 @@ private void validateInstantAndPersistentDeliveryCombinationsForAssetModules(
.build();
}
}

private static boolean hasUpfrontModule(ImmutableCollection<BundleModule> bundleModules) {
return bundleModules.stream()
.anyMatch(
module ->
module.getModuleType().equals(ModuleType.ASSET_MODULE)
&& module.getDeliveryType().equals(ModuleDeliveryType.ALWAYS_INITIAL_INSTALL));
}
}
16 changes: 8 additions & 8 deletions src/main/proto/app_dependencies.proto
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
syntax = "proto3";
syntax = "proto2";

package android.bundle;

Expand All @@ -19,13 +19,13 @@ message AppDependencies {
// List of dependencies of a given library.
message LibraryDependencies {
// Indices correspond to the pool of libraries defined in AppDependencies.
int32 library_index = 1;
optional int32 library_index = 1;
repeated int32 library_dep_index = 2;
}

// Lists the dependencies of a given module.
message ModuleDependencies {
string module_name = 1;
optional string module_name = 1;
// Direct module dependencies.
// Index is from the pool of libraries defined in AppDependencies.
repeated int32 dependency_index = 2;
Expand All @@ -39,9 +39,9 @@ message Library {
}

message MavenLibrary {
string groupId = 1;
string artifactId = 2;
string packaging = 3;
string classifier = 4;
string version = 5;
optional string groupId = 1;
optional string artifactId = 2;
optional string packaging = 3;
optional string classifier = 4;
optional string version = 5;
}
51 changes: 51 additions & 0 deletions src/main/proto/app_integrity_config.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
syntax = "proto3";

package android.bundle;

option java_package = "com.android.bundle";

// Specifies integrity protection options that should be applied to an app
// bundle.
// Next tag: 6.
message AppIntegrityConfig {
bool enabled = 1;
LicenseCheck license_check = 2;
InstallerCheck installer_check = 3;
DebuggerCheck debugger_check = 4;
EmulatorCheck emulator_check = 5;
}

// Next tag: 4.
message LicenseCheck {
bool enabled = 1;
bool online_only = 2;
Policy policy = 3;
}

// Next tag: 4.
message InstallerCheck {
bool enabled = 1;
Policy policy = 2;
repeated string additional_install_source = 3;
}

// Next tag: 2
message DebuggerCheck {
bool enabled = 1;
}

// Next tag: 2
message EmulatorCheck {
bool enabled = 1;
}

// Next tag: 2
message Policy {
enum Action {
UNSPECIFIED = 0;
WARN = 1;
DISABLE = 2;
WARN_THEN_DISABLE = 3;
}
Action action = 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2173,7 +2173,7 @@ public void buildApksCommand_inconsistentAbis_discarded() throws Exception {
}

@Test
public void buildApksCommand_apexBundle() throws Exception {
public void buildApksCommand_apkNotificationMessageKeyApexBundle() throws Exception {
ApexImages apexConfig =
apexImages(
targetedApexImage("apex/x86_64.x86.img", apexImageTargeting("x86_64", "x86")),
Expand Down Expand Up @@ -2270,7 +2270,8 @@ public void buildApksCommand_apexBundle() throws Exception {
}

@Test
public void buildApksCommand_apexBundle_previewTargetSdk() throws Exception {
public void buildApksCommand_apkNotificationMessageKeyApexBundle_previewTargetSdk()
throws Exception {
ApexImages apexConfig =
apexImages(
targetedApexImage("apex/x86_64.img", apexImageTargeting("x86_64")),
Expand Down Expand Up @@ -2331,7 +2332,8 @@ public void buildApksCommand_apexBundle_previewTargetSdk() throws Exception {
}

@Test
public void buildApksCommand_apexBundle_hasRightSuffix() throws Exception {
public void buildApksCommand_apkNotificationMessageKeyApexBundle_hasRightSuffix()
throws Exception {
ApexImages apexConfig =
apexImages(
targetedApexImage("apex/x86_64.img", apexImageTargeting("x86_64")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ public void simpleOutput_emptyLinesIgnored() {
.containsExactly("android.hardware.camera.any", "android.hardware.fingerprint");
}

@Test
public void simpleOutput_warningsIgnored() {
ImmutableList<String> packageManagerCommandOutput =
ImmutableList.of("WARNING: don't do this", "feature:android.hardware.fingerprint");
ImmutableList<String> features = new DeviceFeaturesParser().parse(packageManagerCommandOutput);
assertThat(features).containsExactly("android.hardware.fingerprint");
}

@Test
public void invalidOutput_throws() {
ImmutableList<String> packageManagerCommandOutput =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import static com.android.tools.build.bundletool.model.AndroidManifest.ACTIVITY_ELEMENT_NAME;
import static com.android.tools.build.bundletool.model.AndroidManifest.HAS_CODE_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.IS_SPLIT_REQUIRED_ATTRIBUTE_NAME;
import static com.android.tools.build.bundletool.model.AndroidManifest.IS_SPLIT_REQUIRED_RESOURCE_ID;
import static com.android.tools.build.bundletool.model.AndroidManifest.MAX_SDK_VERSION_RESOURCE_ID;
import static com.android.tools.build.bundletool.model.AndroidManifest.MIN_SDK_VERSION_RESOURCE_ID;
import static com.android.tools.build.bundletool.model.AndroidManifest.NAME_ATTRIBUTE_NAME;
Expand Down Expand Up @@ -463,6 +465,13 @@ public void setSplitsRequired() throws Exception {
editedManifest,
"com.android.vending.splits.required",
xmlBooleanAttribute(ANDROID_NAMESPACE_URI, "value", VALUE_RESOURCE_ID, true));
assertThat(getApplicationElement(editedManifest).getAttributeList())
.containsExactly(
xmlBooleanAttribute(
ANDROID_NAMESPACE_URI,
IS_SPLIT_REQUIRED_ATTRIBUTE_NAME,
IS_SPLIT_REQUIRED_RESOURCE_ID,
true));
}

@Test
Expand All @@ -477,6 +486,13 @@ public void setSplitsRequired_idempotent() throws Exception {
editedManifest,
"com.android.vending.splits.required",
xmlBooleanAttribute(ANDROID_NAMESPACE_URI, "value", VALUE_RESOURCE_ID, true));
assertThat(getApplicationElement(editedManifest).getAttributeList())
.containsExactly(
xmlBooleanAttribute(
ANDROID_NAMESPACE_URI,
IS_SPLIT_REQUIRED_ATTRIBUTE_NAME,
IS_SPLIT_REQUIRED_RESOURCE_ID,
true));
}

@Test
Expand All @@ -491,6 +507,13 @@ public void setSplitsRequired_lastInvocationWins() throws Exception {
editedManifest,
"com.android.vending.splits.required",
xmlBooleanAttribute(ANDROID_NAMESPACE_URI, "value", VALUE_RESOURCE_ID, false));
assertThat(getApplicationElement(editedManifest).getAttributeList())
.containsExactly(
xmlBooleanAttribute(
ANDROID_NAMESPACE_URI,
IS_SPLIT_REQUIRED_ATTRIBUTE_NAME,
IS_SPLIT_REQUIRED_RESOURCE_ID,
false));
}

@Test
Expand Down Expand Up @@ -673,13 +696,7 @@ public void addMetadataResourceReference() {

private static void assertOnlyMetadataElement(
AndroidManifest manifest, String name, XmlAttribute valueAttr) {
XmlNode manifestRoot = manifest.getManifestRoot().getProto();
XmlElement manifestElement = manifestRoot.getElement();
assertThat(manifestElement.getName()).isEqualTo("manifest");
assertThat(manifestElement.getChildCount()).isEqualTo(1);
XmlNode applicationNode = manifestElement.getChild(0);
XmlElement applicationElement = applicationNode.getElement();
assertThat(applicationElement.getName()).isEqualTo("application");
XmlElement applicationElement = getApplicationElement(manifest);
assertThat(applicationElement.getChildCount()).isEqualTo(1);
XmlNode metadataNode = applicationElement.getChild(0);
XmlElement metadataElement = metadataNode.getElement();
Expand All @@ -688,4 +705,15 @@ private static void assertOnlyMetadataElement(
.containsExactly(
xmlAttribute(ANDROID_NAMESPACE_URI, "name", NAME_RESOURCE_ID, name), valueAttr);
}

private static XmlElement getApplicationElement(AndroidManifest manifest) {
XmlNode manifestRoot = manifest.getManifestRoot().getProto();
XmlElement manifestElement = manifestRoot.getElement();
assertThat(manifestElement.getName()).isEqualTo("manifest");
assertThat(manifestElement.getChildCount()).isEqualTo(1);
XmlNode applicationNode = manifestElement.getChild(0);
XmlElement applicationElement = applicationNode.getElement();
assertThat(applicationElement.getName()).isEqualTo("application");
return applicationElement;
}
}
Loading

0 comments on commit b2542c9

Please sign in to comment.