Merge "Support empty strings in bp2build"
diff --git a/android/Android.bp b/android/Android.bp
index cfa2be3..a20aedc 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -113,6 +113,7 @@
         "paths_test.go",
         "prebuilt_test.go",
         "rule_builder_test.go",
+        "sdk_version_test.go",
         "sdk_test.go",
         "singleton_module_test.go",
         "soong_config_modules_test.go",
diff --git a/android/apex.go b/android/apex.go
index 6b4054d..461faf7 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -878,12 +878,8 @@
 	"kotlinx-coroutines-android-nodeps":                        30,
 	"kotlinx-coroutines-core":                                  28,
 	"kotlinx-coroutines-core-nodeps":                           30,
-	"libasyncio":                                               30,
 	"libbrotli":                                                30,
-	"libbuildversion":                                          30,
 	"libcrypto_static":                                         30,
-	"libcrypto_utils":                                          30,
-	"libdiagnose_usb":                                          30,
 	"libeigen":                                                 30,
 	"liblz4":                                                   30,
 	"libmdnssd":                                                30,
@@ -893,7 +889,6 @@
 	"libprocpartition":                                         30,
 	"libprotobuf-java-lite":                                    30,
 	"libprotoutil":                                             30,
-	"libsync":                                                  30,
 	"libtextclassifier_hash_headers":                           30,
 	"libtextclassifier_hash_static":                            30,
 	"libtflite_kernel_utils":                                   30,
diff --git a/android/api_levels.go b/android/api_levels.go
index c1b3ba2..1fbbc15 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -192,8 +192,8 @@
 // * "30" -> "30"
 // * "R" -> "30"
 // * "S" -> "S"
-func ReplaceFinalizedCodenames(ctx PathContext, raw string) string {
-	num, ok := getFinalCodenamesMap(ctx.Config())[raw]
+func ReplaceFinalizedCodenames(config Config, raw string) string {
+	num, ok := getFinalCodenamesMap(config)[raw]
 	if !ok {
 		return raw
 	}
@@ -201,7 +201,7 @@
 	return strconv.Itoa(num)
 }
 
-// Converts the given string `raw` to an ApiLevel, possibly returning an error.
+// ApiLevelFromUser converts the given string `raw` to an ApiLevel, possibly returning an error.
 //
 // `raw` must be non-empty. Passing an empty string results in a panic.
 //
@@ -216,6 +216,12 @@
 // Inputs that are not "current", known previews, or convertible to an integer
 // will return an error.
 func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) {
+	return ApiLevelFromUserWithConfig(ctx.Config(), raw)
+}
+
+// ApiLevelFromUserWithConfig implements ApiLevelFromUser, see comments for
+// ApiLevelFromUser for more details.
+func ApiLevelFromUserWithConfig(config Config, raw string) (ApiLevel, error) {
 	if raw == "" {
 		panic("API level string must be non-empty")
 	}
@@ -224,13 +230,13 @@
 		return FutureApiLevel, nil
 	}
 
-	for _, preview := range ctx.Config().PreviewApiLevels() {
+	for _, preview := range config.PreviewApiLevels() {
 		if raw == preview.String() {
 			return preview, nil
 		}
 	}
 
-	canonical := ReplaceFinalizedCodenames(ctx, raw)
+	canonical := ReplaceFinalizedCodenames(config, raw)
 	asInt, err := strconv.Atoi(canonical)
 	if err != nil {
 		return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", canonical)
diff --git a/android/config.go b/android/config.go
index ed63ddf..ddad1f5 100644
--- a/android/config.go
+++ b/android/config.go
@@ -765,6 +765,16 @@
 	return levels
 }
 
+func (c *config) LatestPreviewApiLevel() ApiLevel {
+	level := NoneApiLevel
+	for _, l := range c.PreviewApiLevels() {
+		if l.GreaterThan(level) {
+			level = l
+		}
+	}
+	return level
+}
+
 func (c *config) AllSupportedApiLevels() []ApiLevel {
 	var levels []ApiLevel
 	levels = append(levels, c.FinalApiLevels()...)
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 1813e7e..2004c92 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -117,7 +117,7 @@
 	return false
 }
 
-// PrebuiltSdkAvailableForUnbundledBuilt tells whether this SdkSpec can have a prebuilt SDK
+// PrebuiltSdkAvailableForUnbundledBuild tells whether this SdkSpec can have a prebuilt SDK
 // that can be used for unbundled builds.
 func (s SdkSpec) PrebuiltSdkAvailableForUnbundledBuild() bool {
 	// "", "none", and "core_platform" are not available for unbundled build
@@ -212,6 +212,10 @@
 )
 
 func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec {
+	return SdkSpecFromWithConfig(ctx.Config(), str)
+}
+
+func SdkSpecFromWithConfig(config Config, str string) SdkSpec {
 	switch str {
 	// special cases first
 	case "":
@@ -252,7 +256,7 @@
 			return SdkSpec{SdkInvalid, NoneApiLevel, str}
 		}
 
-		apiLevel, err := ApiLevelFromUser(ctx, versionString)
+		apiLevel, err := ApiLevelFromUserWithConfig(config, versionString)
 		if err != nil {
 			return SdkSpec{SdkInvalid, apiLevel, str}
 		}
diff --git a/android/sdk_version_test.go b/android/sdk_version_test.go
new file mode 100644
index 0000000..ec81782
--- /dev/null
+++ b/android/sdk_version_test.go
@@ -0,0 +1,89 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// 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 android
+
+import (
+	"testing"
+)
+
+func TestSdkSpecFrom(t *testing.T) {
+	testCases := []struct {
+		input    string
+		expected string
+	}{
+		{
+			input:    "",
+			expected: "private_current",
+		},
+		{
+			input:    "none",
+			expected: "none_(no version)",
+		},
+		{
+			input:    "core_platform",
+			expected: "core_platform_current",
+		},
+		{
+			input:    "_",
+			expected: "invalid_(no version)",
+		},
+		{
+			input:    "_31",
+			expected: "invalid_(no version)",
+		},
+		{
+			input:    "system_R",
+			expected: "system_30",
+		},
+		{
+			input:    "test_31",
+			expected: "test_31",
+		},
+		{
+			input:    "module_current",
+			expected: "module-lib_current",
+		},
+		{
+			input:    "31",
+			expected: "public_31",
+		},
+		{
+			input:    "S",
+			expected: "public_31",
+		},
+		{
+			input:    "current",
+			expected: "public_current",
+		},
+		{
+			input:    "Tiramisu",
+			expected: "public_Tiramisu",
+		},
+	}
+
+	config := NullConfig("", "")
+
+	config.productVariables = productVariables{
+		Platform_sdk_version:              intPtr(31),
+		Platform_sdk_codename:             stringPtr("Tiramisu"),
+		Platform_version_active_codenames: []string{"Tiramisu"},
+	}
+
+	for _, tc := range testCases {
+		if got := SdkSpecFromWithConfig(config, tc.input).String(); tc.expected != got {
+			t.Errorf("Expected %v, got %v", tc.expected, got)
+		}
+	}
+}
diff --git a/apex/apex.go b/apex/apex.go
index 01da1da..75cff7d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -111,6 +111,9 @@
 	// List of java libraries that are embedded inside this APEX bundle.
 	Java_libs []string
 
+	// List of sh binaries that are embedded inside this APEX bundle.
+	Sh_binaries []string
+
 	// List of platform_compat_config files that are embedded inside this APEX bundle.
 	Compat_configs []string
 
@@ -618,6 +621,7 @@
 	sharedLibTag    = dependencyTag{name: "sharedLib", payload: true}
 	testForTag      = dependencyTag{name: "test for"}
 	testTag         = dependencyTag{name: "test", payload: true}
+	shBinaryTag     = dependencyTag{name: "shBinary", payload: true}
 )
 
 // TODO(jiyong): shorten this function signature
@@ -762,6 +766,10 @@
 		for _, d := range depsList {
 			addDependenciesForNativeModules(ctx, d, target, imageVariation)
 		}
+		ctx.AddFarVariationDependencies([]blueprint.Variation{
+			{Mutator: "os", Variation: target.OsVariation()},
+			{Mutator: "arch", Variation: target.ArchVariation()},
+		}, shBinaryTag, a.properties.Sh_binaries...)
 	}
 
 	// Common-arch dependencies come next
@@ -1482,6 +1490,9 @@
 
 func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile {
 	dirInApex := filepath.Join("bin", sh.SubDir())
+	if sh.Target().NativeBridge == android.NativeBridgeEnabled {
+		dirInApex = filepath.Join(dirInApex, sh.Target().NativeBridgeRelativePath)
+	}
 	fileToCopy := sh.OutputFile()
 	af := newApexFile(ctx, fileToCopy, sh.BaseModuleName(), dirInApex, shBinary, sh)
 	af.symlinks = sh.Symlinks()
@@ -1723,8 +1734,6 @@
 				if cc, ok := child.(*cc.Module); ok {
 					filesInfo = append(filesInfo, apexFileForExecutable(ctx, cc))
 					return true // track transitive dependencies
-				} else if sh, ok := child.(*sh.ShBinary); ok {
-					filesInfo = append(filesInfo, apexFileForShBinary(ctx, sh))
 				} else if py, ok := child.(*python.Module); ok && py.HostToolPath().Valid() {
 					filesInfo = append(filesInfo, apexFileForPyBinary(ctx, py))
 				} else if gb, ok := child.(bootstrap.GoBinaryTool); ok && a.Host() {
@@ -1733,7 +1742,13 @@
 					filesInfo = append(filesInfo, apexFileForRustExecutable(ctx, rust))
 					return true // track transitive dependencies
 				} else {
-					ctx.PropertyErrorf("binaries", "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, (host) bootstrap_go_binary, nor sh_binary", depName)
+					ctx.PropertyErrorf("binaries", "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, nor (host) bootstrap_go_binary", depName)
+				}
+			case shBinaryTag:
+				if sh, ok := child.(*sh.ShBinary); ok {
+					filesInfo = append(filesInfo, apexFileForShBinary(ctx, sh))
+				} else {
+					ctx.PropertyErrorf("sh_binaries", "%q is not a sh_binary module", depName)
 				}
 			case bcpfTag:
 				{
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 130581c..e2ca234 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -4250,7 +4250,7 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
-			binaries: ["myscript"],
+			sh_binaries: ["myscript"],
 			updatable: false,
 		}
 
diff --git a/build_test.bash b/build_test.bash
index b039285..b6d00e2 100755
--- a/build_test.bash
+++ b/build_test.bash
@@ -50,7 +50,9 @@
 
 echo
 echo "Free disk space:"
-df -h
+# Ignore df errors because it errors out on gvfsd file systems
+# but still displays most of the useful info we need
+df -h || true
 
 echo
 echo "Running Bazel smoke test..."
diff --git a/cc/libbuildversion/Android.bp b/cc/libbuildversion/Android.bp
index 4debb1c..2cff994 100644
--- a/cc/libbuildversion/Android.bp
+++ b/cc/libbuildversion/Android.bp
@@ -14,6 +14,7 @@
             enabled: true,
         },
     },
+    min_sdk_version: "26",
     apex_available: [
         "//apex_available:platform",
         "//apex_available:anyapex",
diff --git a/cc/library_headers_test.go b/cc/library_headers_test.go
index 9789ab0..3e448ba 100644
--- a/cc/library_headers_test.go
+++ b/cc/library_headers_test.go
@@ -16,7 +16,6 @@
 
 import (
 	"fmt"
-	"strings"
 	"testing"
 
 	"android/soong/android"
@@ -25,44 +24,37 @@
 )
 
 func TestLibraryHeaders(t *testing.T) {
-	ctx := testCc(t, `
-	cc_library_headers {
-		name: "headers",
-		export_include_dirs: ["my_include"],
-	}
-	cc_library_static {
-		name: "lib",
-		srcs: ["foo.c"],
-		header_libs: ["headers"],
-	}
-	`)
+	bp := `
+		%s {
+			name: "headers",
+			export_include_dirs: ["my_include"],
+		}
+		cc_library_static {
+			name: "lib",
+			srcs: ["foo.c"],
+			header_libs: ["headers"],
+		}
+	`
 
-	// test if header search paths are correctly added
-	cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
-	cflags := cc.Args["cFlags"]
-	if !strings.Contains(cflags, " -Imy_include ") {
-		t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
-	}
-}
+	for _, headerModule := range []string{"cc_library_headers", "cc_prebuilt_library_headers"} {
+		t.Run(headerModule, func(t *testing.T) {
+			ctx := testCc(t, fmt.Sprintf(bp, headerModule))
 
-func TestPrebuiltLibraryHeaders(t *testing.T) {
-	ctx := testCc(t, `
-	cc_prebuilt_library_headers {
-		name: "headers",
-		export_include_dirs: ["my_include"],
-	}
-	cc_library_static {
-		name: "lib",
-		srcs: ["foo.c"],
-		header_libs: ["headers"],
-	}
-	`)
+			// test if header search paths are correctly added
+			cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
+			android.AssertStringDoesContain(t, "cFlags for lib module", cc.Args["cFlags"], " -Imy_include ")
 
-	// test if header search paths are correctly added
-	cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
-	cflags := cc.Args["cFlags"]
-	if !strings.Contains(cflags, " -Imy_include ") {
-		t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
+			// Test that there's a valid AndroidMk entry.
+			headers := ctx.ModuleForTests("headers", "android_arm64_armv8-a").Module()
+			e := android.AndroidMkEntriesForTest(t, ctx, headers)[0]
+
+			// This duplicates the tests done in AndroidMkEntries.write. It would be
+			// better to test its output, but there are no test functions that capture that.
+			android.AssertBoolEquals(t, "AndroidMkEntries.Disabled", false, e.Disabled)
+			android.AssertBoolEquals(t, "AndroidMkEntries.OutputFile.Valid()", true, e.OutputFile.Valid())
+
+			android.AssertStringListContains(t, "LOCAL_EXPORT_CFLAGS for headers module", e.EntryMap["LOCAL_EXPORT_CFLAGS"], "-Imy_include")
+		})
 	}
 }
 
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index a279054..c303fda 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -197,7 +197,13 @@
 	if p.header() {
 		ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
 
-		return nil
+		// Need to return an output path so that the AndroidMk logic doesn't skip
+		// the prebuilt header. For compatibility, in case Android.mk files use a
+		// header lib in LOCAL_STATIC_LIBRARIES, create an empty ar file as
+		// placeholder, just like non-prebuilt header modules do in linkStatic().
+		ph := android.PathForModuleOut(ctx, ctx.ModuleName()+staticLibraryExtension)
+		transformObjToStaticLib(ctx, nil, nil, builderFlags{}, ph, nil, nil)
+		return ph
 	}
 
 	return nil
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 324e6dd..93d4b4c 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -43,7 +43,6 @@
 		"-fno-omit-frame-pointer",
 		"-Wno-frame-larger-than=",
 		"-fsanitize-hwaddress-abi=platform",
-		"-mllvm", "-hwasan-use-after-scope=1",
 	}
 
 	// ThinLTO performs codegen during link time, thus these flags need to
diff --git a/java/base.go b/java/base.go
index d9b1260..2f90db2 100644
--- a/java/base.go
+++ b/java/base.go
@@ -197,6 +197,10 @@
 	// Defaults to sdk_version if not set. See sdk_version for possible values.
 	Min_sdk_version *string
 
+	// if not blank, set the maximum version of the sdk that the compiled artifacts will run against.
+	// Defaults to empty string "". See sdk_version for possible values.
+	Max_sdk_version *string
+
 	// if not blank, set the targetSdkVersion in the AndroidManifest.xml.
 	// Defaults to sdk_version if not set. See sdk_version for possible values.
 	Target_sdk_version *string
@@ -460,6 +464,7 @@
 
 	sdkVersion    android.SdkSpec
 	minSdkVersion android.SdkSpec
+	maxSdkVersion android.SdkSpec
 }
 
 func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
@@ -617,6 +622,13 @@
 	return j.SdkVersion(ctx)
 }
 
+func (j *Module) MaxSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+	maxSdkVersion := proptools.StringDefault(j.deviceProperties.Max_sdk_version, "")
+	// SdkSpecFrom returns SdkSpecPrivate for this, which may be confusing.
+	// TODO(b/208456999): ideally MaxSdkVersion should be an ApiLevel and not SdkSpec.
+	return android.SdkSpecFrom(ctx, maxSdkVersion)
+}
+
 func (j *Module) MinSdkVersionString() string {
 	return j.minSdkVersion.Raw
 }
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index d1d9e73..0c792d8 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -85,11 +85,10 @@
 
 // Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
 type classpathJar struct {
-	path      string
-	classpath classpathType
-	// TODO(satayev): propagate min/max sdk versions for the jars
-	minSdkVersion int32
-	maxSdkVersion int32
+	path          string
+	classpath     classpathType
+	minSdkVersion string
+	maxSdkVersion string
 }
 
 // gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the
@@ -121,10 +120,32 @@
 	jars := make([]classpathJar, 0, len(paths)*len(classpaths))
 	for i := 0; i < len(paths); i++ {
 		for _, classpathType := range classpaths {
-			jars = append(jars, classpathJar{
+			jar := classpathJar{
 				classpath: classpathType,
 				path:      paths[i],
+			}
+			ctx.VisitDirectDepsIf(func(m android.Module) bool {
+				return m.Name() == configuredJars.Jar(i)
+			}, func(m android.Module) {
+				if s, ok := m.(*SdkLibrary); ok {
+					// TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
+					if s.minSdkVersion.Specified() {
+						if s.minSdkVersion.ApiLevel.IsCurrent() {
+							jar.minSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
+						} else {
+							jar.minSdkVersion = s.minSdkVersion.ApiLevel.String()
+						}
+					}
+					if s.maxSdkVersion.Specified() {
+						if s.maxSdkVersion.ApiLevel.IsCurrent() {
+							jar.maxSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
+						} else {
+							jar.maxSdkVersion = s.maxSdkVersion.ApiLevel.String()
+						}
+					}
+				}
 			})
+			jars = append(jars, jar)
 		}
 	}
 	return jars
@@ -162,6 +183,7 @@
 
 func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
 	var content strings.Builder
+
 	fmt.Fprintf(&content, "{\n")
 	fmt.Fprintf(&content, "\"jars\": [\n")
 	for idx, jar := range jars {
@@ -170,6 +192,20 @@
 		fmt.Fprintf(&content, "\"path\": \"%s\",\n", jar.path)
 		fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath)
 
+		if jar.minSdkVersion != "" {
+			fmt.Fprintf(&content, ",\n")
+			fmt.Fprintf(&content, "\"minSdkVersion\": \"%s\"\n", jar.minSdkVersion)
+		} else {
+			fmt.Fprintf(&content, "\n")
+		}
+
+		if jar.maxSdkVersion != "" {
+			fmt.Fprintf(&content, ",\n")
+			fmt.Fprintf(&content, "\"maxSdkVersion\": \"%s\"\n", jar.maxSdkVersion)
+		} else {
+			fmt.Fprintf(&content, "\n")
+		}
+
 		if idx < len(jars)-1 {
 			fmt.Fprintf(&content, "},\n")
 		} else {
@@ -178,6 +214,7 @@
 	}
 	fmt.Fprintf(&content, "]\n")
 	fmt.Fprintf(&content, "}\n")
+
 	android.WriteFileRule(ctx, output, content.String())
 }
 
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 7c081b6..f3a53ee 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -122,13 +122,7 @@
 }
 
 func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
-	global := dexpreopt.GetGlobalConfig(ctx)
-
-	if global.DisablePreopt {
-		return true
-	}
-
-	if inList(moduleName(ctx), global.DisablePreoptModules) {
+	if !ctx.Device() {
 		return true
 	}
 
@@ -144,7 +138,17 @@
 		return true
 	}
 
-	if ctx.Host() {
+	if !android.IsModulePreferred(ctx.Module()) {
+		return true
+	}
+
+	global := dexpreopt.GetGlobalConfig(ctx)
+
+	if global.DisablePreopt {
+		return true
+	}
+
+	if inList(moduleName(ctx), global.DisablePreoptModules) {
 		return true
 	}
 
@@ -161,10 +165,6 @@
 		}
 	}
 
-	if !android.IsModulePreferred(ctx.Module()) {
-		return true
-	}
-
 	// TODO: contains no java code
 
 	return false
diff --git a/java/java.go b/java/java.go
index 2f9e03a..a9f3d1a 100644
--- a/java/java.go
+++ b/java/java.go
@@ -447,6 +447,7 @@
 	JAVA_VERSION_7           = 7
 	JAVA_VERSION_8           = 8
 	JAVA_VERSION_9           = 9
+	JAVA_VERSION_11          = 11
 )
 
 func (v javaVersion) String() string {
@@ -459,6 +460,8 @@
 		return "1.8"
 	case JAVA_VERSION_9:
 		return "1.9"
+	case JAVA_VERSION_11:
+		return "11"
 	default:
 		return "unsupported"
 	}
@@ -479,8 +482,10 @@
 		return JAVA_VERSION_8
 	case "1.9", "9":
 		return JAVA_VERSION_9
-	case "10", "11":
-		ctx.PropertyErrorf("java_version", "Java language levels above 9 are not supported")
+	case "11":
+		return JAVA_VERSION_11
+	case "10":
+		ctx.PropertyErrorf("java_version", "Java language levels 10 is not supported")
 		return JAVA_VERSION_UNSUPPORTED
 	default:
 		ctx.PropertyErrorf("java_version", "Unrecognized Java language level")
@@ -545,6 +550,7 @@
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.sdkVersion = j.SdkVersion(ctx)
 	j.minSdkVersion = j.MinSdkVersion(ctx)
+	j.maxSdkVersion = j.MaxSdkVersion(ctx)
 
 	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
 	if !apexInfo.IsForPlatform() {
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 9fec08a..1e27238 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -68,7 +68,6 @@
 func platformBootclasspathFactory() android.SingletonModule {
 	m := &platformBootclasspathModule{}
 	m.AddProperties(&m.properties)
-	// TODO(satayev): split apex jars into separate configs.
 	initClasspathFragment(m, BOOTCLASSPATH)
 	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
 	return m