Merge "Export header check allows WholeStaticLibs"
diff --git a/android/apex.go b/android/apex.go
index 257bdad..7f9f0f5 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -803,60 +803,73 @@
 	}
 	return list
 }(map[string]int{
-	"adbd":                           30,
-	"android.net.ipsec.ike":          30,
-	"apache-commons-compress":        29,
-	"bouncycastle_ike_digests":       30,
-	"brotli-java":                    29,
-	"captiveportal-lib":              28,
-	"flatbuffer_headers":             30,
-	"framework-permission":           30,
-	"gemmlowp_headers":               30,
-	"ike-internals":                  30,
-	"kotlinx-coroutines-android":     28,
-	"kotlinx-coroutines-core":        28,
-	"libadb_crypto":                  30,
-	"libadb_pairing_auth":            30,
-	"libadb_pairing_connection":      30,
-	"libadb_pairing_server":          30,
-	"libadb_protos":                  30,
-	"libadb_tls_connection":          30,
-	"libadbconnection_client":        30,
-	"libadbconnection_server":        30,
-	"libadbd_core":                   30,
-	"libadbd_services":               30,
-	"libadbd":                        30,
-	"libapp_processes_protos_lite":   30,
-	"libasyncio":                     30,
-	"libbrotli":                      30,
-	"libbuildversion":                30,
-	"libcrypto_static":               30,
-	"libcrypto_utils":                30,
-	"libdiagnose_usb":                30,
-	"libeigen":                       30,
-	"liblz4":                         30,
-	"libmdnssd":                      30,
-	"libneuralnetworks_common":       30,
-	"libneuralnetworks_headers":      30,
-	"libneuralnetworks":              30,
-	"libprocpartition":               30,
-	"libprotobuf-java-lite":          30,
-	"libprotoutil":                   30,
-	"libqemu_pipe":                   30,
-	"libsync":                        30,
-	"libtextclassifier_hash_headers": 30,
-	"libtextclassifier_hash_static":  30,
-	"libtflite_kernel_utils":         30,
-	"libwatchdog":                    29,
-	"libzstd":                        30,
-	"metrics-constants-protos":       28,
-	"net-utils-framework-common":     29,
-	"permissioncontroller-statsd":    28,
-	"philox_random_headers":          30,
-	"philox_random":                  30,
-	"service-permission":             30,
-	"tensorflow_headers":             30,
-	"xz-java":                        29,
+	"adbd":                                                     30,
+	"android.net.ipsec.ike":                                    30,
+	"androidx.annotation_annotation-nodeps":                    29,
+	"androidx.arch.core_core-common-nodeps":                    29,
+	"androidx.collection_collection-nodeps":                    29,
+	"androidx.collection_collection-ktx-nodeps":                30,
+	"androidx.concurrent_concurrent-futures-nodeps":            30,
+	"androidx.lifecycle_lifecycle-common-java8-nodeps":         30,
+	"androidx.lifecycle_lifecycle-common-nodeps":               29,
+	"androidx.room_room-common-nodeps":                         30,
+	"androidx-constraintlayout_constraintlayout-solver-nodeps": 29,
+	"apache-commons-compress":                                  29,
+	"bouncycastle_ike_digests":                                 30,
+	"brotli-java":                                              29,
+	"captiveportal-lib":                                        28,
+	"error_prone_annotations":                                  30,
+	"flatbuffer_headers":                                       30,
+	"framework-permission":                                     30,
+	"gemmlowp_headers":                                         30,
+	"guava-listenablefuture-prebuilt-jar":                      30,
+	"ike-internals":                                            30,
+	"kotlinx-coroutines-android":                               28,
+	"kotlinx-coroutines-android-nodeps":                        30,
+	"kotlinx-coroutines-core":                                  28,
+	"kotlinx-coroutines-core-nodeps":                           30,
+	"libadb_crypto":                                            30,
+	"libadb_pairing_auth":                                      30,
+	"libadb_pairing_connection":                                30,
+	"libadb_pairing_server":                                    30,
+	"libadb_protos":                                            30,
+	"libadb_tls_connection":                                    30,
+	"libadbconnection_client":                                  30,
+	"libadbconnection_server":                                  30,
+	"libadbd_core":                                             30,
+	"libadbd_services":                                         30,
+	"libadbd":                                                  30,
+	"libapp_processes_protos_lite":                             30,
+	"libasyncio":                                               30,
+	"libbrotli":                                                30,
+	"libbuildversion":                                          30,
+	"libcrypto_static":                                         30,
+	"libcrypto_utils":                                          30,
+	"libdiagnose_usb":                                          30,
+	"libeigen":                                                 30,
+	"liblz4":                                                   30,
+	"libmdnssd":                                                30,
+	"libneuralnetworks_common":                                 30,
+	"libneuralnetworks_headers":                                30,
+	"libneuralnetworks":                                        30,
+	"libprocpartition":                                         30,
+	"libprotobuf-java-lite":                                    30,
+	"libprotoutil":                                             30,
+	"libqemu_pipe":                                             30,
+	"libsync":                                                  30,
+	"libtextclassifier_hash_headers":                           30,
+	"libtextclassifier_hash_static":                            30,
+	"libtflite_kernel_utils":                                   30,
+	"libwatchdog":                                              29,
+	"libzstd":                                                  30,
+	"metrics-constants-protos":                                 28,
+	"net-utils-framework-common":                               29,
+	"permissioncontroller-statsd":                              28,
+	"philox_random_headers":                                    30,
+	"philox_random":                                            30,
+	"service-permission":                                       30,
+	"tensorflow_headers":                                       30,
+	"xz-java":                                                  29,
 })
 
 // Function called while walking an APEX's payload dependencies.
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 0caad13..98b40fd 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -1836,6 +1836,30 @@
 			min_sdk_version: "30",
 		}
 	`)
+
+	testApexError(t, `module "libfoo".*: should support min_sdk_version\(29\)`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			java_libs: ["libfoo"],
+			min_sdk_version: "29",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		java_import {
+			name: "libfoo",
+			jars: ["libfoo.jar"],
+			apex_available: [
+				"myapex",
+			],
+			min_sdk_version: "30",
+		}
+	`)
 }
 
 func TestApexMinSdkVersion_Okay(t *testing.T) {
@@ -1873,7 +1897,10 @@
 			name: "libbar",
 			sdk_version: "current",
 			srcs: ["a.java"],
-			static_libs: ["libbar_dep"],
+			static_libs: [
+				"libbar_dep",
+				"libbar_import_dep",
+			],
 			apex_available: ["myapex"],
 			min_sdk_version: "29",
 		}
@@ -1885,6 +1912,13 @@
 			apex_available: ["myapex"],
 			min_sdk_version: "29",
 		}
+
+		java_import {
+			name: "libbar_import_dep",
+			jars: ["libbar.jar"],
+			apex_available: ["myapex"],
+			min_sdk_version: "29",
+		}
 	`)
 }
 
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 787222d..6b47cd1 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -19,12 +19,13 @@
 	ruleShims map[string]RuleShim,
 	buildToTargets map[string]BazelTargets,
 	mode CodegenMode) []BazelFile {
-	files := make([]BazelFile, 0, len(ruleShims)+len(buildToTargets)+numAdditionalFiles)
 
-	// Write top level files: WORKSPACE. These files are empty.
-	files = append(files, newFile("", "WORKSPACE", ""))
+	var files []BazelFile
 
 	if mode == QueryView {
+		// Write top level WORKSPACE.
+		files = append(files, newFile("", "WORKSPACE", ""))
+
 		// Used to denote that the top level directory is a package.
 		files = append(files, newFile("", GeneratedBuildFileName, ""))
 
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index a115ddc..9fd6817 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -24,36 +24,6 @@
 	basename string
 }
 
-func assertFilecountsAreEqual(t *testing.T, actual []BazelFile, expected []filepath) {
-	if a, e := len(actual), len(expected); a != e {
-		t.Errorf("Expected %d files, got %d", e, a)
-	}
-}
-
-func assertFileContent(t *testing.T, actual []BazelFile, expected []filepath) {
-	for i := range actual {
-		if g, w := actual[i], expected[i]; g.Dir != w.dir || g.Basename != w.basename {
-			t.Errorf("Did not find expected file %s/%s", g.Dir, g.Basename)
-		} else if g.Basename == "BUILD" || g.Basename == "WORKSPACE" {
-			if g.Contents != "" {
-				t.Errorf("Expected %s to have no content.", g)
-			}
-		} else if g.Contents == "" {
-			t.Errorf("Contents of %s unexpected empty.", g)
-		}
-	}
-}
-
-func sortFiles(files []BazelFile) {
-	sort.Slice(files, func(i, j int) bool {
-		if dir1, dir2 := files[i].Dir, files[j].Dir; dir1 == dir2 {
-			return files[i].Basename < files[j].Basename
-		} else {
-			return dir1 < dir2
-		}
-	})
-}
-
 func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
 	files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
 	expectedFilePaths := []filepath{
@@ -79,21 +49,39 @@
 		},
 	}
 
-	assertFilecountsAreEqual(t, files, expectedFilePaths)
-	sortFiles(files)
-	assertFileContent(t, files, expectedFilePaths)
-}
-
-func TestCreateBazelFiles_Bp2Build_AddsTopLevelFiles(t *testing.T) {
-	files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, Bp2Build)
-	expectedFilePaths := []filepath{
-		{
-			dir:      "",
-			basename: "WORKSPACE",
-		},
+	// Compare number of files
+	if a, e := len(files), len(expectedFilePaths); a != e {
+		t.Errorf("Expected %d files, got %d", e, a)
 	}
 
-	assertFilecountsAreEqual(t, files, expectedFilePaths)
-	sortFiles(files)
-	assertFileContent(t, files, expectedFilePaths)
+	// Sort the files to be deterministic
+	sort.Slice(files, func(i, j int) bool {
+		if dir1, dir2 := files[i].Dir, files[j].Dir; dir1 == dir2 {
+			return files[i].Basename < files[j].Basename
+		} else {
+			return dir1 < dir2
+		}
+	})
+
+	// Compare the file contents
+	for i := range files {
+		actualFile, expectedFile := files[i], expectedFilePaths[i]
+
+		if actualFile.Dir != expectedFile.dir || actualFile.Basename != expectedFile.basename {
+			t.Errorf("Did not find expected file %s/%s", actualFile.Dir, actualFile.Basename)
+		} else if actualFile.Basename == "BUILD" || actualFile.Basename == "WORKSPACE" {
+			if actualFile.Contents != "" {
+				t.Errorf("Expected %s to have no content.", actualFile)
+			}
+		} else if actualFile.Contents == "" {
+			t.Errorf("Contents of %s unexpected empty.", actualFile)
+		}
+	}
+}
+
+func TestCreateBazelFiles_Bp2Build_CreatesNoFilesWithNoTargets(t *testing.T) {
+	files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, Bp2Build)
+	if len(files) != 0 {
+		t.Errorf("Expected no files, got %d", len(files))
+	}
 }
diff --git a/cc/builder.go b/cc/builder.go
index 4771b89..8c9743f 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -182,11 +182,11 @@
 		blueprint.RuleParams{
 			Depfile:     "${out}.d",
 			Deps:        blueprint.DepsGCC,
-			Command:     "CROSS_COMPILE=$crossCompile $tocPath $format -i ${in} -o ${out} -d ${out}.d",
+			Command:     "CLANG_BIN=$clangBin $tocPath $format -i ${in} -o ${out} -d ${out}.d",
 			CommandDeps: []string{"$tocPath"},
 			Restat:      true,
 		},
-		"crossCompile", "format")
+		"clangBin", "format")
 
 	// Rule for invoking clang-tidy (a clang-based linter).
 	clangTidy, clangTidyRE = pctx.RemoteStaticRules("clangTidy",
@@ -918,16 +918,12 @@
 	outputFile android.WritablePath, flags builderFlags) {
 
 	var format string
-	var crossCompile string
 	if ctx.Darwin() {
 		format = "--macho"
-		crossCompile = "${config.MacToolPath}"
 	} else if ctx.Windows() {
 		format = "--pe"
-		crossCompile = gccCmd(flags.toolchain, "")
 	} else {
 		format = "--elf"
-		crossCompile = gccCmd(flags.toolchain, "")
 	}
 
 	ctx.Build(pctx, android.BuildParams{
@@ -936,8 +932,8 @@
 		Output:      outputFile,
 		Input:       inputFile,
 		Args: map[string]string{
-			"crossCompile": crossCompile,
-			"format":       format,
+			"clangBin": "${config.ClangBin}",
+			"format":   format,
 		},
 	})
 }
diff --git a/cc/stl.go b/cc/stl.go
index 75fab17..594231d 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -188,12 +188,7 @@
 		if needsLibAndroidSupport(ctx) {
 			deps.StaticLibs = append(deps.StaticLibs, "ndk_libandroid_support")
 		}
-		// TODO: Switch the NDK over to the LLVM unwinder for non-arm32 architectures.
-		if ctx.Arch().ArchType == android.Arm {
-			deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind")
-		} else {
-			deps.StaticLibs = append(deps.StaticLibs, "libgcc_stripped")
-		}
+		deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind")
 	default:
 		panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl))
 	}
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index e2fc78c..3abf978 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -24,7 +24,6 @@
 	"time"
 
 	"android/soong/shared"
-
 	"github.com/google/blueprint/bootstrap"
 
 	"android/soong/android"
@@ -65,16 +64,10 @@
 	return android.NewNameResolver(exportFilter)
 }
 
-// bazelConversionRequested checks that the user is intending to convert
-// Blueprint to Bazel BUILD files.
-func bazelConversionRequested(configuration android.Config) bool {
-	return configuration.IsEnvTrue("GENERATE_BAZEL_FILES")
-}
-
-func newContext(configuration android.Config) *android.Context {
+func newContext(configuration android.Config, prepareBuildActions bool) *android.Context {
 	ctx := android.NewContext(configuration)
 	ctx.Register()
-	if !shouldPrepareBuildActions(configuration) {
+	if !prepareBuildActions {
 		configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
 	}
 	ctx.SetNameInterface(newNameResolver(configuration))
@@ -91,6 +84,84 @@
 	return configuration
 }
 
+// Bazel-enabled mode. Soong runs in two passes.
+// First pass: Analyze the build tree, but only store all bazel commands
+// needed to correctly evaluate the tree in the second pass.
+// TODO(cparsons): Don't output any ninja file, as the second pass will overwrite
+// the incorrect results from the first pass, and file I/O is expensive.
+func runMixedModeBuild(configuration android.Config, firstCtx *android.Context, extraNinjaDeps []string) {
+	configuration.SetStopBefore(bootstrap.StopBeforeWriteNinja)
+	bootstrap.Main(firstCtx.Context, configuration, false, extraNinjaDeps...)
+	// Invoke bazel commands and save results for second pass.
+	if err := configuration.BazelContext.InvokeBazel(); err != nil {
+		fmt.Fprintf(os.Stderr, "%s", err)
+		os.Exit(1)
+	}
+	// Second pass: Full analysis, using the bazel command results. Output ninja file.
+	secondPassConfig, err := android.ConfigForAdditionalRun(configuration)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "%s", err)
+		os.Exit(1)
+	}
+	secondCtx := newContext(secondPassConfig, true)
+	bootstrap.Main(secondCtx.Context, secondPassConfig, false, extraNinjaDeps...)
+}
+
+// Run the code-generation phase to convert BazelTargetModules to BUILD files.
+func runQueryView(configuration android.Config, ctx *android.Context) {
+	codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.QueryView)
+	absoluteQueryViewDir := shared.JoinPath(topDir, bazelQueryViewDir)
+	if err := createBazelQueryView(codegenContext, absoluteQueryViewDir); err != nil {
+		fmt.Fprintf(os.Stderr, "%s", err)
+		os.Exit(1)
+	}
+}
+
+func runSoongDocs(configuration android.Config, extraNinjaDeps []string) {
+	ctx := newContext(configuration, false)
+	bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...)
+	if err := writeDocs(ctx, configuration, docFile); err != nil {
+		fmt.Fprintf(os.Stderr, "%s", err)
+		os.Exit(1)
+	}
+}
+
+func writeMetrics(configuration android.Config) {
+	metricsFile := filepath.Join(bootstrap.CmdlineBuildDir(), "soong_build_metrics.pb")
+	err := android.WriteMetrics(configuration, metricsFile)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
+		os.Exit(1)
+	}
+}
+
+func doChosenActivity(configuration android.Config, extraNinjaDeps []string) {
+	bazelConversionRequested := configuration.IsEnvTrue("GENERATE_BAZEL_FILES")
+	mixedModeBuild := configuration.BazelContext.BazelEnabled()
+	generateQueryView := bazelQueryViewDir != ""
+
+	if bazelConversionRequested {
+		// Run the alternate pipeline of bp2build mutators and singleton to convert
+		// Blueprint to BUILD files before everything else.
+		runBp2Build(configuration, extraNinjaDeps)
+		return
+	}
+
+	ctx := newContext(configuration, !generateQueryView)
+	if mixedModeBuild {
+		runMixedModeBuild(configuration, ctx, extraNinjaDeps)
+	} else {
+		bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...)
+	}
+
+	// Convert the Soong module graph into Bazel BUILD files.
+	if generateQueryView {
+		runQueryView(configuration, ctx)
+		return
+	}
+	writeMetrics(configuration)
+}
+
 func main() {
 	flag.Parse()
 
@@ -101,7 +172,6 @@
 	usedVariablesFile := shared.JoinPath(outDir, "soong.environment.used")
 	// The top-level Blueprints file is passed as the first argument.
 	srcDir := filepath.Dir(flag.Arg(0))
-	var ctx *android.Context
 	configuration := newConfig(srcDir)
 	extraNinjaDeps := []string{
 		configuration.ProductVariablesFileName,
@@ -122,72 +192,17 @@
 		extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.BuildDir(), "always_rerun_for_delve"))
 	}
 
-	bazelConversionRequested := bazelConversionRequested(configuration)
-	if bazelConversionRequested {
-		// Run the alternate pipeline of bp2build mutators and singleton to convert Blueprint to BUILD files
-		// before everything else.
-		runBp2Build(srcDir, configuration, extraNinjaDeps)
-	} else if configuration.BazelContext.BazelEnabled() {
-		// Bazel-enabled mode. Soong runs in two passes.
-		// First pass: Analyze the build tree, but only store all bazel commands
-		// needed to correctly evaluate the tree in the second pass.
-		// TODO(cparsons): Don't output any ninja file, as the second pass will overwrite
-		// the incorrect results from the first pass, and file I/O is expensive.
-		firstCtx := newContext(configuration)
-		configuration.SetStopBefore(bootstrap.StopBeforeWriteNinja)
-		bootstrap.Main(firstCtx.Context, configuration, false, extraNinjaDeps...)
-		// Invoke bazel commands and save results for second pass.
-		if err := configuration.BazelContext.InvokeBazel(); err != nil {
-			fmt.Fprintf(os.Stderr, "%s", err)
-			os.Exit(1)
-		}
-		// Second pass: Full analysis, using the bazel command results. Output ninja file.
-		secondPassConfig, err := android.ConfigForAdditionalRun(configuration)
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "%s", err)
-			os.Exit(1)
-		}
-		ctx = newContext(secondPassConfig)
-		bootstrap.Main(ctx.Context, secondPassConfig, false, extraNinjaDeps...)
-	} else {
-		ctx = newContext(configuration)
-		bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...)
+	if docFile != "" {
+		// We don't write an used variables file when generating documentation
+		// because that is done from within the actual builds as a Ninja action and
+		// thus it would overwrite the actual used variables file so this is
+		// special-cased.
+		runSoongDocs(configuration, extraNinjaDeps)
+		return
 	}
 
-	// Convert the Soong module graph into Bazel BUILD files.
-	if !bazelConversionRequested && bazelQueryViewDir != "" {
-		// Run the code-generation phase to convert BazelTargetModules to BUILD files.
-		codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.QueryView)
-		absoluteQueryViewDir := shared.JoinPath(topDir, bazelQueryViewDir)
-		if err := createBazelQueryView(codegenContext, absoluteQueryViewDir); err != nil {
-			fmt.Fprintf(os.Stderr, "%s", err)
-			os.Exit(1)
-		}
-	}
-
-	if !bazelConversionRequested && docFile != "" {
-		if err := writeDocs(ctx, configuration, docFile); err != nil {
-			fmt.Fprintf(os.Stderr, "%s", err)
-			os.Exit(1)
-		}
-	}
-
-	// TODO(ccross): make this a command line argument.  Requires plumbing through blueprint
-	//  to affect the command line of the primary builder.
-	if !bazelConversionRequested && shouldPrepareBuildActions(configuration) {
-		metricsFile := filepath.Join(bootstrap.CmdlineBuildDir(), "soong_build_metrics.pb")
-		err := android.WriteMetrics(configuration, metricsFile)
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
-			os.Exit(1)
-		}
-	}
-
-	if docFile == "" {
-		// Let's not overwrite the used variables file when generating
-		// documentation
-		writeUsedVariablesFile(shared.JoinPath(topDir, usedVariablesFile), configuration)
-	}
+	doChosenActivity(configuration, extraNinjaDeps)
+	writeUsedVariablesFile(shared.JoinPath(topDir, usedVariablesFile), configuration)
 }
 
 func writeUsedVariablesFile(path string, configuration android.Config) {
@@ -218,7 +233,7 @@
 // Run Soong in the bp2build mode. This creates a standalone context that registers
 // an alternate pipeline of mutators and singletons specifically for generating
 // Bazel BUILD files instead of Ninja files.
-func runBp2Build(srcDir string, configuration android.Config, extraNinjaDeps []string) {
+func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
 	// Register an alternate set of singletons and mutators for bazel
 	// conversion for Bazel conversion.
 	bp2buildCtx := android.NewContext(configuration)
@@ -233,7 +248,7 @@
 	// configurations or variables, since those will generate different BUILD
 	// files based on how the user has configured their tree.
 	bp2buildCtx.SetModuleListFile(bootstrap.CmdlineModuleListFile())
-	modulePaths, err := bp2buildCtx.ListModulePaths(srcDir)
+	modulePaths, err := bp2buildCtx.ListModulePaths(configuration.SrcDir())
 	if err != nil {
 		panic(err)
 	}
@@ -283,20 +298,3 @@
 		[]byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFileName, extraNinjaDepsString)),
 		0666)
 }
-
-// shouldPrepareBuildActions reads configuration and flags if build actions
-// should be generated.
-func shouldPrepareBuildActions(configuration android.Config) bool {
-	// Generating Soong docs
-	if docFile != "" {
-		return false
-	}
-
-	// Generating a directory for Soong query (queryview)
-	if bazelQueryViewDir != "" {
-		return false
-	}
-
-	// Generating a directory for converted Bazel BUILD files
-	return !bazelConversionRequested(configuration)
-}
diff --git a/java/config/kotlin.go b/java/config/kotlin.go
index fd8e3db..6cb61f3 100644
--- a/java/config/kotlin.go
+++ b/java/config/kotlin.go
@@ -35,11 +35,16 @@
 	pctx.SourcePathVariable("KotlinAnnotationJar", "external/kotlinc/lib/annotations-13.0.jar")
 	pctx.SourcePathVariable("KotlinStdlibJar", KotlinStdlibJar)
 
-	// These flags silence "Illegal reflective access" warnings when running kotlinc in OpenJDK9
-	pctx.StaticVariable("KotlincSuppressJDK9Warnings", strings.Join([]string{
+	// These flags silence "Illegal reflective access" warnings when running kapt in OpenJDK9+
+	pctx.StaticVariable("KaptSuppressJDK9Warnings", strings.Join([]string{
 		"-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
 		"-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
 		"-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
 		"-J--add-opens=java.base/sun.net.www.protocol.jar=ALL-UNNAMED",
 	}, " "))
+
+	// These flags silence "Illegal reflective access" warnings when running kotlinc in OpenJDK9+
+	pctx.StaticVariable("KotlincSuppressJDK9Warnings", strings.Join([]string{
+		"-J--add-opens=java.base/java.util=ALL-UNNAMED", // https://youtrack.jetbrains.com/issue/KT-43704
+	}, " "))
 }
diff --git a/java/java.go b/java/java.go
index 70ad879..3ffe572 100644
--- a/java/java.go
+++ b/java/java.go
@@ -776,7 +776,7 @@
 func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if j.testProperties.Test_options.Unit_test == nil && ctx.Host() {
 		// TODO(b/): Clean temporary heuristic to avoid unexpected onboarding.
-		defaultUnitTest := !inList("tradefed", j.properties.Static_libs) && !inList("tradefed", j.properties.Libs) && !inList("cts", j.testProperties.Test_suites)
+		defaultUnitTest := !inList("tradefed", j.properties.Libs) && !inList("cts", j.testProperties.Test_suites)
 		j.testProperties.Test_options.Unit_test = proptools.BoolPtr(defaultUnitTest)
 	}
 	j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template,
@@ -1074,8 +1074,14 @@
 type ImportProperties struct {
 	Jars []string `android:"path,arch_variant"`
 
+	// The version of the SDK that the source prebuilt file was built against. Defaults to the
+	// current version if not specified.
 	Sdk_version *string
 
+	// The minimum version of the SDK that this module supports. Defaults to sdk_version if not
+	// specified.
+	Min_sdk_version *string
+
 	Installable *bool
 
 	// List of shared java libs that this module has dependencies to
@@ -1139,6 +1145,9 @@
 }
 
 func (j *Import) minSdkVersion() sdkSpec {
+	if j.properties.Min_sdk_version != nil {
+		return sdkSpecFrom(*j.properties.Min_sdk_version)
+	}
 	return j.sdkVersion()
 }
 
@@ -1350,7 +1359,20 @@
 // Implements android.ApexModule
 func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
-	// Do not check for prebuilts against the min_sdk_version of enclosing APEX
+	sdkSpec := j.minSdkVersion()
+	if !sdkSpec.specified() {
+		return fmt.Errorf("min_sdk_version is not specified")
+	}
+	if sdkSpec.kind == sdkCore {
+		return nil
+	}
+	ver, err := sdkSpec.effectiveVersion(ctx)
+	if err != nil {
+		return err
+	}
+	if ver.ApiLevel(ctx).GreaterThan(sdkVersion) {
+		return fmt.Errorf("newer SDK(%v)", ver)
+	}
 	return nil
 }
 
diff --git a/java/kotlin.go b/java/kotlin.go
index 2960f81..3a6fc0f 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -34,8 +34,9 @@
 			`${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
 			` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
 			` $commonSrcFilesArg --out "$kotlinBuildFile" && ` +
-			`${config.KotlincCmd} ${config.JavacHeapFlags} $kotlincFlags ` +
-			`-jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile -kotlin-home $emptyDir && ` +
+			`${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` +
+			`$kotlincFlags -jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile ` +
+			`-kotlin-home $emptyDir && ` +
 			`${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` +
 			`rm -rf "$srcJarDir"`,
 		CommandDeps: []string{
@@ -123,8 +124,8 @@
 			`${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
 			` --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
 			` $commonSrcFilesArg --out "$kotlinBuildFile" && ` +
-			`${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} $kotlincFlags ` +
-			`-Xplugin=${config.KotlinKaptJar} ` +
+			`${config.KotlincCmd} ${config.KaptSuppressJDK9Warnings} ${config.KotlincSuppressJDK9Warnings} ` +
+			`${config.JavacHeapFlags} $kotlincFlags -Xplugin=${config.KotlinKaptJar} ` +
 			`-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` +
 			`-P plugin:org.jetbrains.kotlin.kapt3:classes=$kaptDir/classes ` +
 			`-P plugin:org.jetbrains.kotlin.kapt3:stubs=$kaptDir/stubs ` +
diff --git a/scripts/toc.sh b/scripts/toc.sh
index 8b1d25f..af8bece 100755
--- a/scripts/toc.sh
+++ b/scripts/toc.sh
@@ -17,7 +17,7 @@
 # Script to handle generating a .toc file from a .so file
 # Inputs:
 #  Environment:
-#   CROSS_COMPILE: prefix added to readelf tool
+#   CLANG_BIN: path to the clang bin directory
 #  Arguments:
 #   -i ${file}: input file (required)
 #   -o ${file}: output file (required)
@@ -35,34 +35,34 @@
 }
 
 do_elf() {
-    ("${CROSS_COMPILE}readelf" -d "${infile}" | grep SONAME || echo "No SONAME for ${infile}") > "${outfile}.tmp"
-    "${CROSS_COMPILE}readelf" --dyn-syms "${infile}" | awk '{$2=""; $3=""; print}' >> "${outfile}.tmp"
+    ("${CLANG_BIN}/llvm-readelf" -d "${infile}" | grep SONAME || echo "No SONAME for ${infile}") > "${outfile}.tmp"
+    "${CLANG_BIN}/llvm-readelf" --dyn-syms "${infile}" | awk '{$2=""; $3=""; print}' >> "${outfile}.tmp"
 
     cat <<EOF > "${depsfile}"
 ${outfile}: \\
-  ${CROSS_COMPILE}readelf \\
+  ${CLANG_BIN}/llvm-readelf \\
 EOF
 }
 
 do_macho() {
-    "${CROSS_COMPILE}/otool" -l "${infile}" | grep LC_ID_DYLIB -A 5 > "${outfile}.tmp"
-    "${CROSS_COMPILE}/nm" -gP "${infile}" | cut -f1-2 -d" " | (grep -v 'U$' >> "${outfile}.tmp" || true)
+    "${CLANG_BIN}/llvm-objdump" -p "${infile}" | grep LC_ID_DYLIB -A 5 > "${outfile}.tmp"
+    "${CLANG_BIN}/llvm-nm" -gP "${infile}" | cut -f1-2 -d" " | (grep -v 'U$' >> "${outfile}.tmp" || true)
 
     cat <<EOF > "${depsfile}"
 ${outfile}: \\
-  ${CROSS_COMPILE}/otool \\
-  ${CROSS_COMPILE}/nm \\
+  ${CLANG_BIN}/llvm-objdump \\
+  ${CLANG_BIN}/llvm-nm \\
 EOF
 }
 
 do_pe() {
-    "${CROSS_COMPILE}objdump" -x "${infile}" | grep "^Name" | cut -f3 -d" " > "${outfile}.tmp"
-    "${CROSS_COMPILE}nm" -g -f p "${infile}" | cut -f1-2 -d" " >> "${outfile}.tmp"
+    "${CLANG_BIN}/llvm-objdump" -x "${infile}" | grep "^Name" | cut -f3 -d" " > "${outfile}.tmp"
+    "${CLANG_BIN}/llvm-nm" -g -f p "${infile}" | cut -f1-2 -d" " >> "${outfile}.tmp"
 
     cat <<EOF > "${depsfile}"
 ${outfile}: \\
-  ${CROSS_COMPILE}objdump \\
-  ${CROSS_COMPILE}nm \\
+  ${CLANG_BIN}/llvm-objdump \\
+  ${CLANG_BIN}/llvm-nm \\
 EOF
 }
 
@@ -98,8 +98,8 @@
     usage
 fi
 
-if [ -z "${CROSS_COMPILE:-}" ]; then
-    echo "CROSS_COMPILE environment variable must be set"
+if [ -z "${CLANG_BIN:-}" ]; then
+    echo "CLANG_BIN environment variable must be set"
     usage
 fi
 
@@ -107,7 +107,7 @@
 
 cat <<EOF > "${depsfile}"
 ${outfile}: \\
-  ${CROSS_COMPILE}readelf \\
+  ${CLANG_BIN}/llvm-readelf \\
 EOF
 
 if [ -n "${elf:-}" ]; then