Merge changes I4e7a7ac5,I0c73361b

* changes:
  Record the actual APEXes that a module is part of.
  Rename InApexes -> InApexVariants
diff --git a/android/bazel.go b/android/bazel.go
index 4f8392d..cb3abff 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -160,8 +160,6 @@
 	// Per-module denylist to always opt modules out of both bp2build and mixed builds.
 	bp2buildModuleDoNotConvertList = []string{
 		// Things that transitively depend on unconverted libc_* modules.
-		"libc_nomalloc", // http://b/186825031, cc_library_static, depends on //bionic/libc:libc_common (http://b/186821517)
-
 		"libbionic_spawn_benchmark", // http://b/186824595, cc_library_static, depends on //external/google-benchmark (http://b/186822740)
 		//                                                                also depends on //system/logging/liblog:liblog (http://b/186822772)
 
@@ -180,11 +178,10 @@
 		"liblinker_malloc", // http://b/186826466, cc_library_static, depends on //external/zlib:libz (http://b/186823782)
 		//                                                       also depends on //system/libziparchive:libziparchive (http://b/186823656)
 		//                                                       also depends on //system/logging/liblog:liblog (http://b/186822772)
-		"libc_jemalloc_wrapper", // http://b/187012490, cc_library_static, depends on //external/jemalloc_new:libjemalloc5 (http://b/186828626)
-		"libc_ndk",              // http://b/187013218, cc_library_static, depends on //bionic/libm:libm (http://b/183064661)
-		"libc",                  // http://b/183064430, cc_library, depends on //external/jemalloc_new:libjemalloc5 (http://b/186828626)
-		"libc_malloc_hooks",     // http://b/187016307, cc_library, ld.lld: error: undefined symbol: __malloc_hook
-		"libm",                  // http://b/183064661, cc_library, math.h:25:16: error: unexpected token in argument list
+		"libc_ndk",          // http://b/187013218, cc_library_static, depends on //bionic/libm:libm (http://b/183064661)
+		"libc",              // http://b/183064430, cc_library, depends on //external/jemalloc_new:libjemalloc5 (http://b/186828626)
+		"libc_malloc_hooks", // http://b/187016307, cc_library, ld.lld: error: undefined symbol: __malloc_hook
+		"libm",              // http://b/183064661, cc_library, math.h:25:16: error: unexpected token in argument list
 
 		// http://b/186823769: Needs C++ STL support, includes from unconverted standard libraries in //external/libcxx
 		// c++_static
@@ -204,7 +201,6 @@
 		"note_memtag_heap_async", // http://b/185127353: cc_library_static, error: feature.h not found
 		"note_memtag_heap_sync",  // http://b/185127353: cc_library_static, error: feature.h not found
 
-		"libjemalloc5",           // cc_library, ld.lld: error: undefined symbol: memset
 		"gwp_asan_crash_handler", // cc_library, ld.lld: error: undefined symbol: memset
 
 		// Tests. Handle later.
@@ -217,13 +213,14 @@
 	// Per-module denylist of cc_library modules to only generate the static
 	// variant if their shared variant isn't ready or buildable by Bazel.
 	bp2buildCcLibraryStaticOnlyList = []string{
-		"libstdc++", // http://b/186822597, cc_library, ld.lld: error: undefined symbol: __errno
+		"libstdc++",    // http://b/186822597, cc_library, ld.lld: error: undefined symbol: __errno
+		"libjemalloc5", // http://b/188503688, cc_library, `target: { android: { enabled: false } }` for android targets.
 	}
 
 	// Per-module denylist to opt modules out of mixed builds. Such modules will
 	// still be generated via bp2build.
 	mixedBuildsDisabledList = []string{
-		"libc_bionic_ndk",                  // cparsons@, http://b/183213331, Handle generated headers in mixed builds.
+		"libc_bionic_ndk",                  // cparsons@ cc_library_static, depends on //bionic/libc:libsystemproperties
 		"libc_common",                      // cparsons@ cc_library_static, depends on //bionic/libc:libc_nopthread
 		"libc_common_static",               // cparsons@ cc_library_static, depends on //bionic/libc:libc_common
 		"libc_common_shared",               // cparsons@ cc_library_static, depends on //bionic/libc:libc_common
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 8cddbb2..63145bf 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -333,7 +333,7 @@
 	// The actual platform values here may be overridden by configuration
 	// transitions from the buildroot.
 	cmdFlags = append(cmdFlags,
-		fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_x86_64"))
+		fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_arm"))
 	cmdFlags = append(cmdFlags,
 		fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"))
 	// This should be parameterized on the host OS, but let's restrict to linux
diff --git a/android/module.go b/android/module.go
index c9a1662..69572dd 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1809,8 +1809,8 @@
 	if m.Enabled() {
 		// ensure all direct android.Module deps are enabled
 		ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) {
-			if _, ok := bm.(Module); ok {
-				ctx.validateAndroidModule(bm, ctx.baseModuleContext.strictVisitDeps)
+			if m, ok := bm.(Module); ok {
+				ctx.validateAndroidModule(bm, ctx.OtherModuleDependencyTag(m), ctx.baseModuleContext.strictVisitDeps)
 			}
 		})
 
@@ -2234,7 +2234,12 @@
 	}
 }
 
-func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, strict bool) Module {
+type AllowDisabledModuleDependency interface {
+	blueprint.DependencyTag
+	AllowDisabledModuleDependency(target Module) bool
+}
+
+func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module {
 	aModule, _ := module.(Module)
 
 	if !strict {
@@ -2247,10 +2252,12 @@
 	}
 
 	if !aModule.Enabled() {
-		if b.Config().AllowMissingDependencies() {
-			b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
-		} else {
-			b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
+		if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) {
+			if b.Config().AllowMissingDependencies() {
+				b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
+			} else {
+				b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
+			}
 		}
 		return nil
 	}
@@ -2343,7 +2350,7 @@
 
 func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) {
 	b.bp.VisitDirectDeps(func(module blueprint.Module) {
-		if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
 			visit(aModule)
 		}
 	})
@@ -2351,7 +2358,7 @@
 
 func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
 	b.bp.VisitDirectDeps(func(module blueprint.Module) {
-		if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
 			if b.bp.OtherModuleDependencyTag(aModule) == tag {
 				visit(aModule)
 			}
@@ -2363,7 +2370,7 @@
 	b.bp.VisitDirectDepsIf(
 		// pred
 		func(module blueprint.Module) bool {
-			if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
 				return pred(aModule)
 			} else {
 				return false
@@ -2377,7 +2384,7 @@
 
 func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
 	b.bp.VisitDepsDepthFirst(func(module blueprint.Module) {
-		if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
 			visit(aModule)
 		}
 	})
@@ -2387,7 +2394,7 @@
 	b.bp.VisitDepsDepthFirstIf(
 		// pred
 		func(module blueprint.Module) bool {
-			if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
 				return pred(aModule)
 			} else {
 				return false
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 7bb3ff6..7f5e15c 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -433,6 +433,14 @@
 	result := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
 		prepareForTestWithMyapex,
+		// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
+		java.FixtureConfigureBootJars("myapex:foo", "myapex:bar"),
+		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
+		// is disabled.
+		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("foo"),
 	).RunTestWithBp(t, `
 		apex {
 			name: "myapex",
@@ -449,10 +457,11 @@
 			private_key: "testkey.pem",
 		}
 
-		java_library {
+		java_sdk_library {
 			name: "foo",
 			srcs: ["b.java"],
-			installable: true,
+			shared_library: false,
+			public: {enabled: true},
 			apex_available: [
 				"myapex",
 			],
@@ -491,6 +500,27 @@
 		`myapex.key`,
 		`mybootclasspathfragment`,
 	})
+
+	apex := result.ModuleForTests("myapex", "android_common_myapex_image")
+	apexRule := apex.Rule("apexRule")
+	copyCommands := apexRule.Args["copy_commands"]
+
+	// Make sure that the fragment provides the hidden API encoded dex jars to the APEX.
+	fragment := result.Module("mybootclasspathfragment", "android_common_apex10000")
+
+	info := result.ModuleProvider(fragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
+
+	checkFragmentExportedDexJar := func(name string, expectedDexJar string) {
+		module := result.Module(name, "android_common_apex10000")
+		dexJar := info.DexBootJarPathForContentModule(module)
+		android.AssertPathRelativeToTopEquals(t, name+" dex", expectedDexJar, dexJar)
+
+		expectedCopyCommand := fmt.Sprintf("&& cp -f %s out/soong/.intermediates/myapex/android_common_myapex_image/image.apex/javalib/%s.jar", expectedDexJar, name)
+		android.AssertStringDoesContain(t, name+" apex copy command", copyCommands, expectedCopyCommand)
+	}
+
+	checkFragmentExportedDexJar("foo", "out/soong/.intermediates/foo/android_common_apex10000/hiddenapi/foo.jar")
+	checkFragmentExportedDexJar("bar", "out/soong/.intermediates/bar/android_common_apex10000/hiddenapi/bar.jar")
 }
 
 // TODO(b/177892522) - add test for host apex.
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 52b1689..ce12f46 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -20,6 +20,7 @@
 	"android/soong/android"
 	"android/soong/java"
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 // Contains tests for platform_bootclasspath logic from java/platform_bootclasspath.go that requires
@@ -174,6 +175,141 @@
 	})
 }
 
+// TestPlatformBootclasspath_AlwaysUsePrebuiltSdks verifies that the build does not fail when
+// AlwaysUsePrebuiltSdk() returns true. The structure of the modules in this test matches what
+// currently exists in some places in the Android build but it is not the intended structure. It is
+// in fact an invalid structure that should cause build failures. However, fixing that structure
+// will take too long so in the meantime this tests the workarounds to avoid build breakages.
+//
+// The main issues with this structure are:
+// 1. There is no prebuilt_bootclasspath_fragment referencing the "foo" java_sdk_library_import.
+// 2. There is no prebuilt_apex/apex_set which makes the dex implementation jar available to the
+//    prebuilt_bootclasspath_fragment and the "foo" java_sdk_library_import.
+//
+// Together these cause the following symptoms:
+// 1. The "foo" java_sdk_library_import does not have a dex implementation jar.
+// 2. The "foo" java_sdk_library_import does not have a myapex variant.
+//
+// TODO(b/179354495): Fix the structure in this test once the main Android build has been fixed.
+func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForTestWithPlatformBootclasspath,
+		prepareForTestWithMyapex,
+		// Configure two libraries, the first is a java_sdk_library whose prebuilt will be used because
+		// of AlwaysUsePrebuiltsSdk() but does not have an appropriate apex variant and does not provide
+		// a boot dex jar. The second is a normal library that is unaffected. The order matters because
+		// if the dependency on myapex:foo is filtered out because of either of those conditions then
+		// the dependencies resolved by the platform_bootclasspath will not match the configured list
+		// and so will fail the test.
+		java.FixtureConfigureUpdatableBootJars("myapex:foo", "myapex:bar"),
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
+		}),
+		java.FixtureWithPrebuiltApis(map[string][]string{
+			"current": {},
+			"30":      {"foo"},
+		}),
+	).RunTestWithBp(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			bootclasspath_fragments: [
+				"mybootclasspath-fragment",
+			],
+			updatable: false,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		java_library {
+			name: "bar",
+			srcs: ["b.java"],
+			installable: true,
+			apex_available: ["myapex"],
+			permitted_packages: ["bar"],
+		}
+
+		java_sdk_library {
+			name: "foo",
+			srcs: ["b.java"],
+			shared_library: false,
+			public: {
+				enabled: true,
+			},
+			apex_available: ["myapex"],
+			permitted_packages: ["foo"],
+		}
+
+		// A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
+		// because AlwaysUsePrebuiltSdks() is true.
+		java_sdk_library_import {
+			name: "foo",
+			prefer: false,
+			shared_library: false,
+			public: {
+				jars: ["sdk_library/public/foo-stubs.jar"],
+				stub_srcs: ["sdk_library/public/foo_stub_sources"],
+				current_api: "sdk_library/public/foo.txt",
+				removed_api: "sdk_library/public/foo-removed.txt",
+				sdk_version: "current",
+			},
+			apex_available: ["myapex"],
+		}
+
+		// This always depends on the source foo module, its dependencies are not affected by the
+		// AlwaysUsePrebuiltSdks().
+		bootclasspath_fragment {
+			name: "mybootclasspath-fragment",
+			apex_available: [
+				"myapex",
+			],
+			contents: [
+				"foo", "bar",
+			],
+		}
+
+		platform_bootclasspath {
+			name: "myplatform-bootclasspath",
+		}
+`,
+	)
+
+	java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
+		// The configured contents of BootJars.
+		"platform:prebuilt_foo", // Note: This is the platform not myapex variant.
+		"myapex:bar",
+	})
+
+	// Make sure that the myplatform-bootclasspath has the correct dependencies.
+	CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+		// The following are stubs.
+		"platform:prebuilt_sdk_public_current_android",
+		"platform:prebuilt_sdk_system_current_android",
+		"platform:prebuilt_sdk_test_current_android",
+
+		// Not a prebuilt as no prebuilt existed when it was added.
+		"platform:legacy.core.platform.api.stubs",
+
+		// Needed for generating the boot image.
+		`platform:dex2oatd`,
+
+		// The platform_bootclasspath intentionally adds dependencies on both source and prebuilt
+		// modules when available as it does not know which one will be preferred.
+		//
+		// The source module has an APEX variant but the prebuilt does not.
+		"myapex:foo",
+		"platform:prebuilt_foo",
+
+		// Only a source module exists.
+		"myapex:bar",
+	})
+}
+
 // CheckModuleDependencies checks the dependencies of the selected module against the expected list.
 //
 // The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 555f1dc..bda3a1a 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -81,23 +81,30 @@
 	Mnemonic    string
 }
 
-// AqueryBuildStatements returns an array of BuildStatements which should be registered (and output
-// to a ninja file) to correspond one-to-one with the given action graph json proto (from a bazel
-// aquery invocation).
-func AqueryBuildStatements(aqueryJsonProto []byte) ([]BuildStatement, error) {
-	buildStatements := []BuildStatement{}
+// A helper type for aquery processing which facilitates retrieval of path IDs from their
+// less readable Bazel structures (depset and path fragment).
+type aqueryArtifactHandler struct {
+	// Maps middleman artifact Id to input artifact depset ID.
+	// Middleman artifacts are treated as "substitute" artifacts for mixed builds. For example,
+	// if we find a middleman action which has outputs [foo, bar], and output [baz_middleman], then,
+	// for each other action which has input [baz_middleman], we add [foo, bar] to the inputs for
+	// that action instead.
+	middlemanIdToDepsetIds map[int][]int
+	// Maps depset Id to depset struct.
+	depsetIdToDepset map[int]depSetOfFiles
+	// depsetIdToArtifactIdsCache is a memoization of depset flattening, because flattening
+	// may be an expensive operation.
+	depsetIdToArtifactIdsCache map[int][]int
+	// Maps artifact Id to fully expanded path.
+	artifactIdToPath map[int]string
+}
 
-	var aqueryResult actionGraphContainer
-	err := json.Unmarshal(aqueryJsonProto, &aqueryResult)
-
-	if err != nil {
-		return nil, err
-	}
-
+func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler, error) {
 	pathFragments := map[int]pathFragment{}
 	for _, pathFragment := range aqueryResult.PathFragments {
 		pathFragments[pathFragment.Id] = pathFragment
 	}
+
 	artifactIdToPath := map[int]string{}
 	for _, artifact := range aqueryResult.Artifacts {
 		artifactPath, err := expandPathFragment(artifact.PathFragmentId, pathFragments)
@@ -112,22 +119,87 @@
 		depsetIdToDepset[depset.Id] = depset
 	}
 
-	// depsetIdToArtifactIdsCache is a memoization of depset flattening, because flattening
-	// may be an expensive operation.
-	depsetIdToArtifactIdsCache := map[int][]int{}
-
 	// Do a pass through all actions to identify which artifacts are middleman artifacts.
-	// These will be omitted from the inputs of other actions.
-	// TODO(b/180945500): Handle middleman actions; without proper handling, depending on generated
-	// headers may cause build failures.
-	middlemanArtifactIds := map[int]bool{}
+	middlemanIdToDepsetIds := map[int][]int{}
 	for _, actionEntry := range aqueryResult.Actions {
 		if actionEntry.Mnemonic == "Middleman" {
 			for _, outputId := range actionEntry.OutputIds {
-				middlemanArtifactIds[outputId] = true
+				middlemanIdToDepsetIds[outputId] = actionEntry.InputDepSetIds
 			}
 		}
 	}
+	return &aqueryArtifactHandler{
+		middlemanIdToDepsetIds:     middlemanIdToDepsetIds,
+		depsetIdToDepset:           depsetIdToDepset,
+		depsetIdToArtifactIdsCache: map[int][]int{},
+		artifactIdToPath:           artifactIdToPath,
+	}, nil
+}
+
+func (a *aqueryArtifactHandler) getInputPaths(depsetIds []int) ([]string, error) {
+	inputPaths := []string{}
+
+	for _, inputDepSetId := range depsetIds {
+		inputArtifacts, err := a.artifactIdsFromDepsetId(inputDepSetId)
+		if err != nil {
+			return nil, err
+		}
+		for _, inputId := range inputArtifacts {
+			if middlemanInputDepsetIds, isMiddlemanArtifact := a.middlemanIdToDepsetIds[inputId]; isMiddlemanArtifact {
+				// Add all inputs from middleman actions which created middleman artifacts which are
+				// in the inputs for this action.
+				swappedInputPaths, err := a.getInputPaths(middlemanInputDepsetIds)
+				if err != nil {
+					return nil, err
+				}
+				inputPaths = append(inputPaths, swappedInputPaths...)
+			} else {
+				inputPath, exists := a.artifactIdToPath[inputId]
+				if !exists {
+					return nil, fmt.Errorf("undefined input artifactId %d", inputId)
+				}
+				inputPaths = append(inputPaths, inputPath)
+			}
+		}
+	}
+	return inputPaths, nil
+}
+
+func (a *aqueryArtifactHandler) artifactIdsFromDepsetId(depsetId int) ([]int, error) {
+	if result, exists := a.depsetIdToArtifactIdsCache[depsetId]; exists {
+		return result, nil
+	}
+	if depset, exists := a.depsetIdToDepset[depsetId]; exists {
+		result := depset.DirectArtifactIds
+		for _, childId := range depset.TransitiveDepSetIds {
+			childArtifactIds, err := a.artifactIdsFromDepsetId(childId)
+			if err != nil {
+				return nil, err
+			}
+			result = append(result, childArtifactIds...)
+		}
+		a.depsetIdToArtifactIdsCache[depsetId] = result
+		return result, nil
+	} else {
+		return nil, fmt.Errorf("undefined input depsetId %d", depsetId)
+	}
+}
+
+// AqueryBuildStatements returns an array of BuildStatements which should be registered (and output
+// to a ninja file) to correspond one-to-one with the given action graph json proto (from a bazel
+// aquery invocation).
+func AqueryBuildStatements(aqueryJsonProto []byte) ([]BuildStatement, error) {
+	buildStatements := []BuildStatement{}
+
+	var aqueryResult actionGraphContainer
+	err := json.Unmarshal(aqueryJsonProto, &aqueryResult)
+	if err != nil {
+		return nil, err
+	}
+	aqueryHandler, err := newAqueryHandler(aqueryResult)
+	if err != nil {
+		return nil, err
+	}
 
 	for _, actionEntry := range aqueryResult.Actions {
 		if shouldSkipAction(actionEntry) {
@@ -136,7 +208,7 @@
 		outputPaths := []string{}
 		var depfile *string
 		for _, outputId := range actionEntry.OutputIds {
-			outputPath, exists := artifactIdToPath[outputId]
+			outputPath, exists := aqueryHandler.artifactIdToPath[outputId]
 			if !exists {
 				return nil, fmt.Errorf("undefined outputId %d", outputId)
 			}
@@ -151,25 +223,11 @@
 				outputPaths = append(outputPaths, outputPath)
 			}
 		}
-		inputPaths := []string{}
-		for _, inputDepSetId := range actionEntry.InputDepSetIds {
-			inputArtifacts, err :=
-				artifactIdsFromDepsetId(depsetIdToDepset, depsetIdToArtifactIdsCache, inputDepSetId)
-			if err != nil {
-				return nil, err
-			}
-			for _, inputId := range inputArtifacts {
-				if _, isMiddlemanArtifact := middlemanArtifactIds[inputId]; isMiddlemanArtifact {
-					// Omit middleman artifacts.
-					continue
-				}
-				inputPath, exists := artifactIdToPath[inputId]
-				if !exists {
-					return nil, fmt.Errorf("undefined input artifactId %d", inputId)
-				}
-				inputPaths = append(inputPaths, inputPath)
-			}
+		inputPaths, err := aqueryHandler.getInputPaths(actionEntry.InputDepSetIds)
+		if err != nil {
+			return nil, err
 		}
+
 		buildStatement := BuildStatement{
 			Command:     strings.Join(proptools.ShellEscapeList(actionEntry.Arguments), " "),
 			Depfile:     depfile,
@@ -192,8 +250,9 @@
 	if a.Mnemonic == "Symlink" || a.Mnemonic == "SourceSymlinkManifest" || a.Mnemonic == "SymlinkTree" {
 		return true
 	}
-	// TODO(b/180945500): Handle middleman actions; without proper handling, depending on generated
-	// headers may cause build failures.
+	// Middleman actions are not handled like other actions; they are handled separately as a
+	// preparatory step so that their inputs may be relayed to actions depending on middleman
+	// artifacts.
 	if a.Mnemonic == "Middleman" {
 		return true
 	}
@@ -209,28 +268,6 @@
 	return false
 }
 
-func artifactIdsFromDepsetId(depsetIdToDepset map[int]depSetOfFiles,
-	depsetIdToArtifactIdsCache map[int][]int, depsetId int) ([]int, error) {
-	if result, exists := depsetIdToArtifactIdsCache[depsetId]; exists {
-		return result, nil
-	}
-	if depset, exists := depsetIdToDepset[depsetId]; exists {
-		result := depset.DirectArtifactIds
-		for _, childId := range depset.TransitiveDepSetIds {
-			childArtifactIds, err :=
-				artifactIdsFromDepsetId(depsetIdToDepset, depsetIdToArtifactIdsCache, childId)
-			if err != nil {
-				return nil, err
-			}
-			result = append(result, childArtifactIds...)
-		}
-		depsetIdToArtifactIdsCache[depsetId] = result
-		return result, nil
-	} else {
-		return nil, fmt.Errorf("undefined input depsetId %d", depsetId)
-	}
-}
-
 func expandPathFragment(id int, pathFragmentsMap map[int]pathFragment) (string, error) {
 	labels := []string{}
 	currId := id
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index fa8810f..7b40dcd 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -718,6 +718,93 @@
 	assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
 }
 
+func TestMiddlemenAction(t *testing.T) {
+	const inputString = `
+{
+  "artifacts": [{
+    "id": 1,
+    "pathFragmentId": 1
+  }, {
+    "id": 2,
+    "pathFragmentId": 2
+  }, {
+    "id": 3,
+    "pathFragmentId": 3
+  }, {
+    "id": 4,
+    "pathFragmentId": 4
+  }, {
+    "id": 5,
+    "pathFragmentId": 5
+  }, {
+    "id": 6,
+    "pathFragmentId": 6
+  }],
+  "pathFragments": [{
+    "id": 1,
+    "label": "middleinput_one"
+  }, {
+    "id": 2,
+    "label": "middleinput_two"
+  }, {
+    "id": 3,
+    "label": "middleman_artifact"
+  }, {
+    "id": 4,
+    "label": "maininput_one"
+  }, {
+    "id": 5,
+    "label": "maininput_two"
+  }, {
+    "id": 6,
+    "label": "output"
+  }],
+  "depSetOfFiles": [{
+    "id": 1,
+    "directArtifactIds": [1, 2]
+  }, {
+    "id": 2,
+    "directArtifactIds": [3, 4, 5]
+  }],
+  "actions": [{
+    "targetId": 1,
+    "actionKey": "x",
+    "mnemonic": "Middleman",
+    "arguments": ["touch", "foo"],
+    "inputDepSetIds": [1],
+    "outputIds": [3],
+    "primaryOutputId": 3
+  }, {
+    "targetId": 2,
+    "actionKey": "y",
+    "mnemonic": "Main action",
+    "arguments": ["touch", "foo"],
+    "inputDepSetIds": [2],
+    "outputIds": [6],
+    "primaryOutputId": 6
+  }]
+}`
+
+	actual, err := AqueryBuildStatements([]byte(inputString))
+	if err != nil {
+		t.Errorf("Unexpected error %q", err)
+	}
+	if expected := 1; len(actual) != expected {
+		t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
+	}
+
+	bs := actual[0]
+	expectedInputs := []string{"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"}
+	if !reflect.DeepEqual(bs.InputPaths, expectedInputs) {
+		t.Errorf("Expected main action inputs %q, but got %q", expectedInputs, bs.InputPaths)
+	}
+
+	expectedOutputs := []string{"output"}
+	if !reflect.DeepEqual(bs.OutputPaths, expectedOutputs) {
+		t.Errorf("Expected main action outputs %q, but got %q", expectedOutputs, bs.OutputPaths)
+	}
+}
+
 func assertError(t *testing.T, err error, expected string) {
 	if err == nil {
 		t.Errorf("expected error '%s', but got no error", expected)
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 63a6c2e..71660a8 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -324,11 +324,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
-		if Errored(t, "", errs) {
+		if errored(t, "", errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, "", errs) {
+		if errored(t, "", errs) {
 			continue
 		}
 
@@ -925,11 +925,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
@@ -957,17 +957,6 @@
 	}
 }
 
-func Errored(t *testing.T, desc string, errs []error) bool {
-	t.Helper()
-	if len(errs) > 0 {
-		for _, err := range errs {
-			t.Errorf("%s: %s", desc, err)
-		}
-		return true
-	}
-	return false
-}
-
 type bp2buildMutator = func(android.TopDownMutatorContext)
 
 func TestBp2BuildInlinesDefaults(t *testing.T) {
@@ -1483,11 +1472,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
@@ -1606,11 +1595,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 32b12e4..204c519 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -22,8 +22,6 @@
 	"testing"
 )
 
-var buildDir string
-
 func setUp() {
 	var err error
 	buildDir, err = ioutil.TempDir("", "bazel_queryview_test")
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index da5444c..a1ffabc 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -617,11 +617,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 1202da6..a3965ed 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -385,11 +385,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index bb12462..4fcf5e4 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1132,11 +1132,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index ea8b9f1..ebc9c94 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -228,11 +228,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
@@ -411,11 +411,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/constants.go b/bp2build/constants.go
index 70f320e..4870dff 100644
--- a/bp2build/constants.go
+++ b/bp2build/constants.go
@@ -19,7 +19,10 @@
 	// be preferred for use within a Bazel build.
 
 	// The file name used for automatically generated files.
-	GeneratedBuildFileName = "BUILD"
+	GeneratedBuildFileName = "BUILD.bazel"
+
 	// The file name used for hand-crafted build targets.
+	// NOTE: It is okay that this matches GeneratedBuildFileName, since we generate BUILD files in a different directory to source files
+	// FIXME: Because there are hundreds of existing BUILD.bazel files in the AOSP tree, we should pick another name here, like BUILD.android
 	HandcraftedBuildFileName = "BUILD.bazel"
 )
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index a08c03d..0931ff7 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -29,7 +29,7 @@
 	expectedFilePaths := []bazelFilepath{
 		{
 			dir:      "",
-			basename: "BUILD",
+			basename: "BUILD.bazel",
 		},
 		{
 			dir:      "",
@@ -37,7 +37,7 @@
 		},
 		{
 			dir:      bazelRulesSubDir,
-			basename: "BUILD",
+			basename: "BUILD.bazel",
 		},
 		{
 			dir:      bazelRulesSubDir,
@@ -69,7 +69,7 @@
 
 		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" {
+		} else if actualFile.Basename == "BUILD.bazel" || actualFile.Basename == "WORKSPACE" {
 			if actualFile.Contents != "" {
 				t.Errorf("Expected %s to have no content.", actualFile)
 			}
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 2054e06..ed509bf 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -128,11 +128,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index 37f542e..575bf58 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -101,11 +101,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/testing.go b/bp2build/testing.go
index b925682..e575bc6 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -1,6 +1,8 @@
 package bp2build
 
 import (
+	"testing"
+
 	"android/soong/android"
 	"android/soong/bazel"
 )
@@ -10,6 +12,8 @@
 	bp2buildConfig = android.Bp2BuildConfig{
 		android.BP2BUILD_TOPLEVEL: android.Bp2BuildDefaultTrueRecursively,
 	}
+
+	buildDir string
 )
 
 type nestedProps struct {
@@ -39,6 +43,17 @@
 	props customProps
 }
 
+func errored(t *testing.T, desc string, errs []error) bool {
+	t.Helper()
+	if len(errs) > 0 {
+		for _, err := range errs {
+			t.Errorf("%s: %s", desc, err)
+		}
+		return true
+	}
+	return false
+}
+
 // OutputFiles is needed because some instances of this module use dist with a
 // tag property which requires the module implements OutputFileProducer.
 func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
diff --git a/cc/Android.bp b/cc/Android.bp
index c32cca8..1fc8d9f 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -92,6 +92,7 @@
         "object_test.go",
         "prebuilt_test.go",
         "proto_test.go",
+        "sanitize_test.go",
         "test_data_test.go",
         "vendor_public_library_test.go",
         "vendor_snapshot_test.go",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 02d6428..75543ac 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -91,12 +91,15 @@
 		allDeps = append(allDeps, lib.SharedProperties.Shared.Static_libs...)
 		allDeps = append(allDeps, lib.SharedProperties.Shared.Whole_static_libs...)
 		allDeps = append(allDeps, lib.SharedProperties.Shared.Shared_libs...)
-		allDeps = append(allDeps, lib.SharedProperties.Shared.System_shared_libs...)
 
 		allDeps = append(allDeps, lib.StaticProperties.Static.Static_libs...)
 		allDeps = append(allDeps, lib.StaticProperties.Static.Whole_static_libs...)
 		allDeps = append(allDeps, lib.StaticProperties.Static.Shared_libs...)
-		allDeps = append(allDeps, lib.StaticProperties.Static.System_shared_libs...)
+
+		// TODO(b/186024507, b/186489250): Temporarily exclude adding
+		// system_shared_libs deps until libc and libm builds.
+		// allDeps = append(allDeps, lib.SharedProperties.Shared.System_shared_libs...)
+		// allDeps = append(allDeps, lib.StaticProperties.Static.System_shared_libs...)
 	}
 
 	ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...)
diff --git a/cc/config/global.go b/cc/config/global.go
index 59fe8e1..d6eba0f 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -225,18 +225,19 @@
 
 	// Everything in these lists is a crime against abstraction and dependency tracking.
 	// Do not add anything to this list.
-	pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I",
-		[]string{
-			"system/core/include",
-			"system/logging/liblog/include",
-			"system/media/audio/include",
-			"hardware/libhardware/include",
-			"hardware/libhardware_legacy/include",
-			"hardware/ril/include",
-			"frameworks/native/include",
-			"frameworks/native/opengl/include",
-			"frameworks/av/include",
-		})
+	commonGlobalIncludes := []string{
+		"system/core/include",
+		"system/logging/liblog/include",
+		"system/media/audio/include",
+		"hardware/libhardware/include",
+		"hardware/libhardware_legacy/include",
+		"hardware/ril/include",
+		"frameworks/native/include",
+		"frameworks/native/opengl/include",
+		"frameworks/av/include",
+	}
+	exportedVars.Set("CommonGlobalIncludes", commonGlobalIncludes)
+	pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I", commonGlobalIncludes)
 
 	pctx.SourcePathVariable("ClangDefaultBase", ClangDefaultBase)
 	pctx.VariableFunc("ClangBase", func(ctx android.PackageVarContext) string {
diff --git a/cc/linker.go b/cc/linker.go
index 196806d..5bd21ed 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -393,7 +393,7 @@
 	if ctx.minSdkVersion() == "current" {
 		return true
 	}
-	parsedSdkVersion, err := android.ApiLevelFromUser(ctx, ctx.minSdkVersion())
+	parsedSdkVersion, err := nativeApiLevelFromUser(ctx, ctx.minSdkVersion())
 	if err != nil {
 		ctx.PropertyErrorf("min_sdk_version",
 			"Invalid min_sdk_version value (must be int or current): %q",
@@ -424,7 +424,7 @@
 			// ANDROID_RELR relocations were supported at API level >= 28.
 			// Relocation packer was supported at API level >= 23.
 			// Do the best we can...
-			if !ctx.useSdk() || CheckSdkVersionAtLeast(ctx, android.FirstShtRelrVersion) {
+			if (!ctx.useSdk() && ctx.minSdkVersion() == "") || CheckSdkVersionAtLeast(ctx, android.FirstShtRelrVersion) {
 				flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android+relr")
 			} else if CheckSdkVersionAtLeast(ctx, android.FirstAndroidRelrVersion) {
 				flags.Global.LdFlags = append(flags.Global.LdFlags,
diff --git a/cc/makevars.go b/cc/makevars.go
index da5f1fd..2b326ef 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -288,9 +288,7 @@
 		ctx.Strict(makePrefix+"OBJCOPY", "${config.ClangBin}/llvm-objcopy")
 		ctx.Strict(makePrefix+"LD", "${config.ClangBin}/lld")
 		ctx.Strict(makePrefix+"NDK_TRIPLE", config.NDKTriple(toolchain))
-		// TODO: work out whether to make this "${config.ClangBin}/llvm-", which
-		// should mostly work, or remove it.
-		ctx.Strict(makePrefix+"TOOLS_PREFIX", gccCmd(toolchain, ""))
+		ctx.Strict(makePrefix+"TOOLS_PREFIX", "${config.ClangBin}/llvm-")
 		// TODO: GCC version is obsolete now that GCC has been removed.
 		ctx.Strict(makePrefix+"GCC_VERSION", toolchain.GccVersion())
 	}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 605a8d0..f486ee4 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -902,7 +902,7 @@
 					if d, ok := child.(PlatformSanitizeable); ok && d.SanitizePropDefined() &&
 						!d.SanitizeNever() &&
 						!d.IsSanitizerExplicitlyDisabled(t) {
-						if t == cfi || t == Hwasan || t == scs {
+						if t == cfi || t == Hwasan || t == scs || t == Asan {
 							if d.StaticallyLinked() && d.SanitizerSupported(t) {
 								// Rust does not support some of these sanitizers, so we need to check if it's
 								// supported before setting this true.
@@ -1261,7 +1261,7 @@
 				modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
 			} else if c.IsSanitizerEnabled(t) || c.SanitizeDep() {
 				isSanitizerEnabled := c.IsSanitizerEnabled(t)
-				if c.StaticallyLinked() || c.Header() || t == Asan || t == Fuzzer {
+				if c.StaticallyLinked() || c.Header() || t == Fuzzer {
 					// Static and header libs are split into non-sanitized and sanitized variants.
 					// Shared libs are not split. However, for asan and fuzzer, we split even for shared
 					// libs because a library sanitized for asan/fuzzer can't be linked from a library
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
new file mode 100644
index 0000000..f126346
--- /dev/null
+++ b/cc/sanitize_test.go
@@ -0,0 +1,204 @@
+// Copyright 2021 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 cc
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+var prepareForAsanTest = android.FixtureAddFile("asan/Android.bp", []byte(`
+	cc_library_shared {
+		name: "libclang_rt.asan-aarch64-android",
+	}
+
+	cc_library_shared {
+		name: "libclang_rt.asan-arm-android",
+	}
+`))
+
+func TestAsan(t *testing.T) {
+	bp := `
+		cc_binary {
+			name: "bin_with_asan",
+			host_supported: true,
+			shared_libs: [
+				"libshared",
+				"libasan",
+			],
+			static_libs: [
+				"libstatic",
+				"libnoasan",
+			],
+			sanitize: {
+				address: true,
+			}
+		}
+
+		cc_binary {
+			name: "bin_no_asan",
+			host_supported: true,
+			shared_libs: [
+				"libshared",
+				"libasan",
+			],
+			static_libs: [
+				"libstatic",
+				"libnoasan",
+			],
+		}
+
+		cc_library_shared {
+			name: "libshared",
+			host_supported: true,
+			shared_libs: ["libtransitive"],
+		}
+
+		cc_library_shared {
+			name: "libasan",
+			host_supported: true,
+			shared_libs: ["libtransitive"],
+			sanitize: {
+				address: true,
+			}
+		}
+
+		cc_library_shared {
+			name: "libtransitive",
+			host_supported: true,
+		}
+
+		cc_library_static {
+			name: "libstatic",
+			host_supported: true,
+		}
+
+		cc_library_static {
+			name: "libnoasan",
+			host_supported: true,
+			sanitize: {
+				address: false,
+			}
+		}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+		prepareForAsanTest,
+	).RunTestWithBp(t, bp)
+
+	check := func(t *testing.T, result *android.TestResult, variant string) {
+		asanVariant := variant + "_asan"
+		sharedVariant := variant + "_shared"
+		sharedAsanVariant := sharedVariant + "_asan"
+		staticVariant := variant + "_static"
+		staticAsanVariant := staticVariant + "_asan"
+
+		// The binaries, one with asan and one without
+		binWithAsan := result.ModuleForTests("bin_with_asan", asanVariant)
+		binNoAsan := result.ModuleForTests("bin_no_asan", variant)
+
+		// Shared libraries that don't request asan
+		libShared := result.ModuleForTests("libshared", sharedVariant)
+		libTransitive := result.ModuleForTests("libtransitive", sharedVariant)
+
+		// Shared library that requests asan
+		libAsan := result.ModuleForTests("libasan", sharedAsanVariant)
+
+		// Static library that uses an asan variant for bin_with_asan and a non-asan variant
+		// for bin_no_asan.
+		libStaticAsanVariant := result.ModuleForTests("libstatic", staticAsanVariant)
+		libStaticNoAsanVariant := result.ModuleForTests("libstatic", staticVariant)
+
+		// Static library that never uses asan.
+		libNoAsan := result.ModuleForTests("libnoasan", staticVariant)
+
+		// expectSharedLinkDep verifies that the from module links against the to module as a
+		// shared library.
+		expectSharedLinkDep := func(from, to android.TestingModule) {
+			t.Helper()
+			fromLink := from.Description("link")
+			toLink := to.Description("strip")
+
+			if g, w := fromLink.OrderOnly.Strings(), toLink.Output.String(); !android.InList(w, g) {
+				t.Errorf("%s should link against %s, expected %q, got %q",
+					from.Module(), to.Module(), w, g)
+			}
+		}
+
+		// expectStaticLinkDep verifies that the from module links against the to module as a
+		// static library.
+		expectStaticLinkDep := func(from, to android.TestingModule) {
+			t.Helper()
+			fromLink := from.Description("link")
+			toLink := to.Description("static link")
+
+			if g, w := fromLink.Implicits.Strings(), toLink.Output.String(); !android.InList(w, g) {
+				t.Errorf("%s should link against %s, expected %q, got %q",
+					from.Module(), to.Module(), w, g)
+			}
+
+		}
+
+		// expectInstallDep verifies that the install rule of the from module depends on the
+		// install rule of the to module.
+		expectInstallDep := func(from, to android.TestingModule) {
+			t.Helper()
+			fromInstalled := from.Description("install")
+			toInstalled := to.Description("install")
+
+			// combine implicits and order-only dependencies, host uses implicit but device uses
+			// order-only.
+			got := append(fromInstalled.Implicits.Strings(), fromInstalled.OrderOnly.Strings()...)
+			want := toInstalled.Output.String()
+			if !android.InList(want, got) {
+				t.Errorf("%s installation should depend on %s, expected %q, got %q",
+					from.Module(), to.Module(), want, got)
+			}
+		}
+
+		expectSharedLinkDep(binWithAsan, libShared)
+		expectSharedLinkDep(binWithAsan, libAsan)
+		expectSharedLinkDep(libShared, libTransitive)
+		expectSharedLinkDep(libAsan, libTransitive)
+
+		expectStaticLinkDep(binWithAsan, libStaticAsanVariant)
+		expectStaticLinkDep(binWithAsan, libNoAsan)
+
+		expectInstallDep(binWithAsan, libShared)
+		expectInstallDep(binWithAsan, libAsan)
+		expectInstallDep(binWithAsan, libTransitive)
+		expectInstallDep(libShared, libTransitive)
+		expectInstallDep(libAsan, libTransitive)
+
+		expectSharedLinkDep(binNoAsan, libShared)
+		expectSharedLinkDep(binNoAsan, libAsan)
+		expectSharedLinkDep(libShared, libTransitive)
+		expectSharedLinkDep(libAsan, libTransitive)
+
+		expectStaticLinkDep(binNoAsan, libStaticNoAsanVariant)
+		expectStaticLinkDep(binNoAsan, libNoAsan)
+
+		expectInstallDep(binNoAsan, libShared)
+		expectInstallDep(binNoAsan, libAsan)
+		expectInstallDep(binNoAsan, libTransitive)
+		expectInstallDep(libShared, libTransitive)
+		expectInstallDep(libAsan, libTransitive)
+	}
+
+	t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) })
+	t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
+}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 7e73bf7..0bcec17 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -372,6 +372,15 @@
 func (d dex2oatDependencyTag) ExcludeFromApexContents() {
 }
 
+func (d dex2oatDependencyTag) AllowDisabledModuleDependency(target android.Module) bool {
+	// RegisterToolDeps may run after the prebuilt mutators and hence register a
+	// dependency on the source module even when the prebuilt is to be used.
+	// dex2oatPathFromDep takes that into account when it retrieves the path to
+	// the binary, but we also need to disable the check for dependencies on
+	// disabled modules.
+	return target.IsReplacedByPrebuilt()
+}
+
 // Dex2oatDepTag represents the dependency onto the dex2oatd module. It is added to any module that
 // needs dexpreopting and so it makes no sense for it to be checked for visibility or included in
 // the apex.
@@ -379,6 +388,7 @@
 
 var _ android.ExcludeFromVisibilityEnforcementTag = Dex2oatDepTag
 var _ android.ExcludeFromApexContentsTag = Dex2oatDepTag
+var _ android.AllowDisabledModuleDependency = Dex2oatDepTag
 
 // RegisterToolDeps adds the necessary dependencies to binary modules for tools
 // that are required later when Get(Cached)GlobalSoongConfig is called. It
diff --git a/java/base.go b/java/base.go
index c828503..0d2f1ac 100644
--- a/java/base.go
+++ b/java/base.go
@@ -889,8 +889,8 @@
 		kotlincFlags := j.properties.Kotlincflags
 		CheckKotlincFlags(ctx, kotlincFlags)
 
-		// Dogfood the JVM_IR backend.
-		kotlincFlags = append(kotlincFlags, "-Xuse-ir")
+		// Workaround for KT-46512
+		kotlincFlags = append(kotlincFlags, "-Xsam-conversions=class")
 
 		// If there are kotlin files, compile them first but pass all the kotlin and java files
 		// kotlinc will use the java files to resolve types referenced by the kotlin files, but
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index 02833ab..634959a 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -29,7 +29,7 @@
 
 func registerBootclasspathBuildComponents(ctx android.RegistrationContext) {
 	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator)
+		ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator).Parallel()
 	})
 }
 
@@ -95,6 +95,15 @@
 	if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
 		ctx.AddVariationDependencies(variations, tag, prebuiltName)
 		addedDep = true
+	} else if ctx.Config().AlwaysUsePrebuiltSdks() && len(variations) > 0 {
+		// TODO(b/179354495): Remove this code path once the Android build has been fully migrated to
+		//  use bootclasspath_fragment properly.
+		// Some prebuilt java_sdk_library modules do not yet have an APEX variations so try and add a
+		// dependency on the non-APEX variant.
+		if ctx.OtherModuleDependencyVariantExists(nil, prebuiltName) {
+			ctx.AddVariationDependencies(nil, tag, prebuiltName)
+			addedDep = true
+		}
 	}
 
 	// If no appropriate variant existing for this, so no dependency could be added, then it is an
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 7408090..bc0416a 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -136,7 +136,7 @@
 	for idx, jar := range jars {
 		fmt.Fprintf(&content, "{\n")
 
-		fmt.Fprintf(&content, "\"relativePath\": \"%s\",\n", jar.path)
+		fmt.Fprintf(&content, "\"path\": \"%s\",\n", jar.path)
 		fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath)
 
 		if idx < len(jars)-1 {
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index be202c0..e1a3650 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -766,7 +766,7 @@
 			if len(pp) > 0 {
 				updatablePackages = append(updatablePackages, pp...)
 			} else {
-				ctx.ModuleErrorf("Missing permitted_packages")
+				ctx.OtherModuleErrorf(module, "Missing permitted_packages")
 			}
 		}
 	}
@@ -803,8 +803,7 @@
 		rule := android.NewRuleBuilder(pctx, ctx)
 		imageLocationsOnHost, _ := image.imageLocations()
 		rule.Command().
-			// TODO: for now, use the debug version for better error reporting
-			BuiltTool("oatdumpd").
+			BuiltTool("oatdump").
 			FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
 			FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
 			FlagWithArg("--image=", strings.Join(imageLocationsOnHost, ":")).Implicits(image.imagesDeps.Paths()).
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index a9e0773..f065534 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -15,7 +15,12 @@
 package java
 
 import (
+	"fmt"
 	"testing"
+
+	"android/soong/android"
+	"android/soong/cc"
+	"android/soong/dexpreopt"
 )
 
 func TestDexpreoptEnabled(t *testing.T) {
@@ -166,3 +171,46 @@
 		return "disabled"
 	}
 }
+
+func TestDex2oatToolDeps(t *testing.T) {
+	preparers := android.GroupFixturePreparers(
+		cc.PrepareForTestWithCcDefaultModules,
+		PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd,
+		dexpreopt.PrepareForTestByEnablingDexpreopt)
+
+	testDex2oatToolDep := func(sourceEnabled, prebuiltEnabled, prebuiltPreferred bool,
+		expectedDex2oatPath string) {
+		name := fmt.Sprintf("sourceEnabled:%t,prebuiltEnabled:%t,prebuiltPreferred:%t",
+			sourceEnabled, prebuiltEnabled, prebuiltPreferred)
+		t.Run(name, func(t *testing.T) {
+			result := preparers.RunTestWithBp(t, fmt.Sprintf(`
+					cc_binary {
+						name: "dex2oatd",
+						enabled: %t,
+						host_supported: true,
+					}
+					cc_prebuilt_binary {
+						name: "dex2oatd",
+						enabled: %t,
+						prefer: %t,
+						host_supported: true,
+						srcs: ["x86_64/bin/dex2oatd"],
+					}
+					java_library {
+						name: "myjavalib",
+					}
+				`, sourceEnabled, prebuiltEnabled, prebuiltPreferred))
+			pathContext := android.PathContextForTesting(result.Config)
+			dex2oatPath := dexpreopt.GetCachedGlobalSoongConfig(pathContext).Dex2oat
+			android.AssertStringEquals(t, "Testing "+name, expectedDex2oatPath, android.NormalizePathForTesting(dex2oatPath))
+		})
+	}
+
+	sourceDex2oatPath := "host/linux-x86/bin/dex2oatd"
+	prebuiltDex2oatPath := ".intermediates/prebuilt_dex2oatd/linux_glibc_x86_64/dex2oatd"
+
+	testDex2oatToolDep(true, false, false, sourceDex2oatPath)
+	testDex2oatToolDep(true, true, false, sourceDex2oatPath)
+	testDex2oatToolDep(true, true, true, prebuiltDex2oatPath)
+	testDex2oatToolDep(false, true, false, prebuiltDex2oatPath)
+}
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 2dceb65..f5afe5d 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"fmt"
 	"strings"
 
 	"android/soong/android"
@@ -560,7 +561,25 @@
 	for _, module := range contents {
 		bootDexJar := module.bootDexJar()
 		if bootDexJar == nil {
-			ctx.ModuleErrorf("module %s does not provide a dex jar", module)
+			if ctx.Config().AlwaysUsePrebuiltSdks() {
+				// TODO(b/179354495): Remove this work around when it is unnecessary.
+				// Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
+				// create a fake one that will cause a build error only if it is used.
+				fake := android.PathForModuleOut(ctx, "fake/boot-dex/%s.jar", module.Name())
+
+				// Create an error rule that pretends to create the output file but will actually fail if it
+				// is run.
+				ctx.Build(pctx, android.BuildParams{
+					Rule:   android.ErrorRule,
+					Output: fake,
+					Args: map[string]string{
+						"error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
+					},
+				})
+				bootDexJars = append(bootDexJars, fake)
+			} else {
+				ctx.ModuleErrorf("module %s does not provide a dex jar", module)
+			}
 		} else {
 			bootDexJars = append(bootDexJars, bootDexJar)
 		}
diff --git a/java/java.go b/java/java.go
index 45eb693..2bbb5b1 100644
--- a/java/java.go
+++ b/java/java.go
@@ -57,6 +57,10 @@
 	ctx.RegisterModuleType("java_host_for_device", HostForDeviceFactory)
 	ctx.RegisterModuleType("dex_import", DexImportFactory)
 
+	// This mutator registers dependencies on dex2oat for modules that should be
+	// dexpreopted. This is done late when the final variants have been
+	// established, to not get the dependencies split into the wrong variants and
+	// to support the checks in dexpreoptDisabled().
 	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel()
 	})
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 3a8d6e3..10bf179 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -242,8 +242,15 @@
 		} else {
 			name := ctx.OtherModuleName(m)
 			if apexInfo.IsForPlatform() {
-				// error: this jar is part of the platform
-				ctx.ModuleErrorf("module %q from platform is not allowed in the updatable boot jars list", name)
+				// If AlwaysUsePrebuiltSdks() returns true then it is possible that the updatable list will
+				// include platform variants of a prebuilt module due to workarounds elsewhere. In that case
+				// do not treat this as an error.
+				// TODO(b/179354495): Always treat this as an error when migration to bootclasspath_fragment
+				//  modules is complete.
+				if !ctx.Config().AlwaysUsePrebuiltSdks() {
+					// error: this jar is part of the platform
+					ctx.ModuleErrorf("module %q from platform is not allowed in the updatable boot jars list", name)
+				}
 			} else {
 				// TODO(b/177892522): Treat this as an error.
 				// Cannot do that at the moment because framework-wifi and framework-tethering are in the
diff --git a/java/testing.go b/java/testing.go
index cc0feea..1fef337 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -56,8 +56,9 @@
 	}.AddToFixture(),
 )
 
-// Test fixture preparer that will define default java modules, e.g. standard prebuilt modules.
-var PrepareForTestWithJavaDefaultModules = android.GroupFixturePreparers(
+// Test fixture preparer that will define all default java modules except the
+// fake_tool_binary for dex2oatd.
+var PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd = android.GroupFixturePreparers(
 	// Make sure that all the module types used in the defaults are registered.
 	PrepareForTestWithJavaBuildComponents,
 	// Additional files needed when test disallows non-existent source.
@@ -73,6 +74,11 @@
 	android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", gatherRequiredDepsForTest()),
 	// Add dexpreopt compat libs (android.test.base, etc.) and a fake dex2oatd module.
 	dexpreopt.PrepareForTestWithDexpreoptCompatLibs,
+)
+
+// Test fixture preparer that will define default java modules, e.g. standard prebuilt modules.
+var PrepareForTestWithJavaDefaultModules = android.GroupFixturePreparers(
+	PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd,
 	dexpreopt.PrepareForTestWithFakeDex2oatd,
 )
 
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 3f51114..42363e9 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -7,6 +7,8 @@
 
 source "$(dirname "$0")/lib.sh"
 
+readonly GENERATED_BUILD_FILE_NAME="BUILD.bazel"
+
 function test_smoke {
   setup
   run_soong
@@ -505,8 +507,8 @@
 EOF
 
   GENERATE_BAZEL_FILES=1 run_soong
-  [[ -e out/soong/bp2build/a/BUILD ]] || fail "a/BUILD not created"
-  [[ -L out/soong/workspace/a/BUILD ]] || fail "a/BUILD not symlinked"
+  [[ -e out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not created"
+  [[ -L out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not symlinked"
 
   mkdir -p b
   touch b/b.txt
@@ -519,8 +521,8 @@
 EOF
 
   GENERATE_BAZEL_FILES=1 run_soong
-  [[ -e out/soong/bp2build/b/BUILD ]] || fail "a/BUILD not created"
-  [[ -L out/soong/workspace/b/BUILD ]] || fail "a/BUILD not symlinked"
+  [[ -e out/soong/bp2build/b/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not created"
+  [[ -L out/soong/workspace/b/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not symlinked"
 }
 
 function test_bp2build_null_build {
@@ -551,11 +553,11 @@
 EOF
 
   GENERATE_BAZEL_FILES=1 run_soong
-  grep -q a1.txt out/soong/bp2build/a/BUILD || fail "a1.txt not in BUILD file"
+  grep -q a1.txt "out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME}" || fail "a1.txt not in ${GENERATED_BUILD_FILE_NAME} file"
 
   touch a/a2.txt
   GENERATE_BAZEL_FILES=1 run_soong
-  grep -q a2.txt out/soong/bp2build/a/BUILD || fail "a2.txt not in BUILD file"
+  grep -q a2.txt "out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME}" || fail "a2.txt not in ${GENERATED_BUILD_FILE_NAME} file"
 }
 
 function test_dump_json_module_graph() {
@@ -583,8 +585,8 @@
   GENERATE_BAZEL_FILES=1 run_soong
   [[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
   [[ -d out/soong/workspace/a/b ]] || fail "module directory not a directory"
-  [[ -L out/soong/workspace/a/b/BUILD ]] || fail "BUILD file not symlinked"
-  [[ "$(readlink -f out/soong/workspace/a/b/BUILD)" =~ bp2build/a/b/BUILD$ ]] \
+  [[ -L "out/soong/workspace/a/b/${GENERATED_BUILD_FILE_NAME}" ]] || fail "${GENERATED_BUILD_FILE_NAME} file not symlinked"
+  [[ "$(readlink -f out/soong/workspace/a/b/${GENERATED_BUILD_FILE_NAME})" =~ "bp2build/a/b/${GENERATED_BUILD_FILE_NAME}"$ ]] \
     || fail "BUILD files symlinked at the wrong place"
   [[ -L out/soong/workspace/a/b/b.txt ]] || fail "a/b/b.txt not symlinked"
   [[ -L out/soong/workspace/a/a.txt ]] || fail "a/b/a.txt not symlinked"
@@ -616,7 +618,7 @@
 
   mkdir -p a
   touch a/a.txt
-  touch a/BUILD
+  touch a/${GENERATED_BUILD_FILE_NAME}
   cat > a/Android.bp <<EOF
 filegroup {
   name: "a",
@@ -626,15 +628,15 @@
 EOF
 
   GENERATE_BAZEL_FILES=1 run_soong
-  [[ -L out/soong/workspace/a/BUILD ]] || fail "BUILD file not symlinked"
-  [[ "$(readlink -f out/soong/workspace/a/BUILD)" =~ bp2build/a/BUILD$ ]] \
-    || fail "BUILD files symlinked to the wrong place"
+  [[ -L "out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME}" ]] || fail "${GENERATED_BUILD_FILE_NAME} file not symlinked"
+  [[ "$(readlink -f out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME})" =~ "bp2build/a/${GENERATED_BUILD_FILE_NAME}"$ ]] \
+    || fail "${GENERATED_BUILD_FILE_NAME} files symlinked to the wrong place"
 }
 
 function test_bp2build_reports_multiple_errors {
   setup
 
-  mkdir -p a/BUILD
+  mkdir -p "a/${GENERATED_BUILD_FILE_NAME}"
   touch a/a.txt
   cat > a/Android.bp <<EOF
 filegroup {
@@ -644,7 +646,7 @@
 }
 EOF
 
-  mkdir -p b/BUILD
+  mkdir -p "b/${GENERATED_BUILD_FILE_NAME}"
   touch b/b.txt
   cat > b/Android.bp <<EOF
 filegroup {
@@ -658,8 +660,8 @@
     fail "Build should have failed"
   fi
 
-  grep -q "a/BUILD' exist" "$MOCK_TOP/errors" || fail "Error for a/BUILD not found"
-  grep -q "b/BUILD' exist" "$MOCK_TOP/errors" || fail "Error for b/BUILD not found"
+  grep -q "a/${GENERATED_BUILD_FILE_NAME}' exist" "$MOCK_TOP/errors" || fail "Error for a/${GENERATED_BUILD_FILE_NAME} not found"
+  grep -q "b/${GENERATED_BUILD_FILE_NAME}' exist" "$MOCK_TOP/errors" || fail "Error for b/${GENERATED_BUILD_FILE_NAME} not found"
 }
 
 test_smoke
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 082cd06..e357710 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -6,6 +6,8 @@
 
 source "$(dirname "$0")/lib.sh"
 
+readonly GENERATED_BUILD_FILE_NAME="BUILD.bazel"
+
 function test_bp2build_generates_all_buildfiles {
   setup
   create_mock_bazel
@@ -40,24 +42,24 @@
 
   run_bp2build
 
-  if [[ ! -f "./out/soong/workspace/foo/convertible_soong_module/BUILD" ]]; then
-    fail "./out/soong/workspace/foo/convertible_soong_module/BUILD was not generated"
+  if [[ ! -f "./out/soong/workspace/foo/convertible_soong_module/${GENERATED_BUILD_FILE_NAME}" ]]; then
+    fail "./out/soong/workspace/foo/convertible_soong_module/${GENERATED_BUILD_FILE_NAME} was not generated"
   fi
 
-  if [[ ! -f "./out/soong/workspace/foo/unconvertible_soong_module/BUILD" ]]; then
-    fail "./out/soong/workspace/foo/unconvertible_soong_module/BUILD was not generated"
+  if [[ ! -f "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}" ]]; then
+    fail "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME} was not generated"
   fi
 
-  if ! grep "the_answer" "./out/soong/workspace/foo/convertible_soong_module/BUILD"; then
-    fail "missing BUILD target the_answer in convertible_soong_module/BUILD"
+  if ! grep "the_answer" "./out/soong/workspace/foo/convertible_soong_module/${GENERATED_BUILD_FILE_NAME}"; then
+    fail "missing BUILD target the_answer in convertible_soong_module/${GENERATED_BUILD_FILE_NAME}"
   fi
 
-  if grep "not_the_answer" "./out/soong/workspace/foo/unconvertible_soong_module/BUILD"; then
-    fail "found unexpected BUILD target not_the_answer in unconvertible_soong_module/BUILD"
+  if grep "not_the_answer" "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"; then
+    fail "found unexpected BUILD target not_the_answer in unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"
   fi
 
-  if ! grep "filegroup" "./out/soong/workspace/foo/unconvertible_soong_module/BUILD"; then
-    fail "missing filegroup in unconvertible_soong_module/BUILD"
+  if ! grep "filegroup" "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"; then
+    fail "missing filegroup in unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"
   fi
 
   # NOTE: We don't actually use the extra BUILD file for anything here
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 2eb84ca..09d53cc 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -76,6 +76,8 @@
 			"Blueprints",
 			// Bazel build definitions.
 			"BUILD.bazel",
+			// Bazel build definitions.
+			"BUILD",
 			// Kati clean definitions.
 			"CleanSpec.mk",
 			// Ownership definition.
@@ -102,7 +104,7 @@
 func findBazelFiles(entries finder.DirEntries) (dirNames []string, fileNames []string) {
 	matches := []string{}
 	for _, foundName := range entries.FileNames {
-		if foundName == "BUILD.bazel" || foundName == "WORKSPACE" || strings.HasSuffix(foundName, ".bzl") {
+		if foundName == "BUILD.bazel" || foundName == "BUILD" || foundName == "WORKSPACE" || strings.HasSuffix(foundName, ".bzl") {
 			matches = append(matches, foundName)
 		}
 	}