Merge "Remove libqemu_pipe from minSdkVersionAllowlist"
diff --git a/android/bazel.go b/android/bazel.go
index 52c59aa..49fc0ad 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -171,23 +171,22 @@
 	}
 
 	// Per-module denylist to always opt modules out of both bp2build and mixed builds.
-	// Please keep sorted.
 	bp2buildModuleDoNotConvertList = []string{
 		// Things that transitively depend on //external/arm-optimized-routines. That one fails
 		// with a linker error: "ld.lld: no input files"
-		"libc_nopthread",     // ruperts@, cc_library_static, depends on //external/arm-optimized-routine
 		"libc_common",        // ruperts@, cc_library_static, depends on //bionic/libc:libc_nopthread
 		"libc_common_static", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
 		"libc_common_shared", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
 		"libc_nomalloc",      // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
+		"libc_nopthread",     // ruperts@, cc_library_static, depends on //external/arm-optimized-routine
 
 		// Things that transitively depend on //system/libbase. libbase doesn't work because:
 		// "Multiple dependencies having same BaseModuleName() "fmtlib" found from "libbase""
 		"libbionic_spawn_benchmark",   // ruperts@, cc_library_static, depends on libbase, libgoogle-benchmark
-		"libc_malloc_debug_backtrace", // ruperts@, cc_library_static, depends on libbase
-		"liblinker_main",              // ruperts@, cc_library_static, depends on libbase, libz, libziparchive
-		"liblinker_debuggerd_stub",    // ruperts@, cc_library_static, depends on libbase, libz, libziparchive
 		"libc_malloc_debug",           // ruperts@, cc_library_static, depends on libbase
+		"libc_malloc_debug_backtrace", // ruperts@, cc_library_static, depends on libbase
+		"liblinker_debuggerd_stub",    // ruperts@, cc_library_static, depends on libbase, libz, libziparchive
+		"liblinker_main",              // ruperts@, cc_library_static, depends on libbase, libz, libziparchive
 		"liblinker_malloc",            // ruperts@, cc_library_static, depends on libziparchive, libz, libbase
 
 		// Requires non-libc targets, but otherwise works
@@ -195,8 +194,8 @@
 		"libsystemproperties",   // ruperts@, cc_library_static, depends on //system/core/property_service/libpropertyinfoparser
 
 		// Compilation error, seems to be fixable by changing the toolchain definition
-		"libc_tzcode",     // ruperts@, cc_library_static, error: expected expression
 		"libc_bionic_ndk", // ruperts@, cc_library_static, error: ISO C++ requires field designators...
+		"libc_tzcode",     // ruperts@, cc_library_static, error: expected expression
 		"libm",            // jingwen@, cc_library, error: "expected register here" (and many others)
 
 		// Linker error
@@ -222,9 +221,10 @@
 	// Per-module denylist to opt modules out of mixed builds. Such modules will
 	// still be generated via bp2build.
 	mixedBuildsDisabledList = []string{
-		"libc_gdtoa",   // ruperts@, cc_library_static, OK for bp2build but undefined symbol: __strtorQ for mixed builds
-		"libc_netbsd",  // lberki@, cc_library_static, version script assignment of 'LIBC_PRIVATE' to symbol 'SHA1Final' failed: symbol not defined
-		"libc_openbsd", // ruperts@, cc_library_static, OK for bp2build but error: duplicate symbol: strcpy for mixed builds
+		"libasync_safe", // lberki@, cc_library_static, 'async_safe/log.h not found' for out/combined-aosp_arm64.ninja out/soong/.intermediates/system/unwinding/libbacktrace/libbacktrace/android_arm64_armv8-a_shared/obj/system/unwinding/libbacktrace/ThreadEntry.o
+		"libc_gdtoa",    // ruperts@, cc_library_static, OK for bp2build but undefined symbol: __strtorQ for mixed builds
+		"libc_netbsd",   // lberki@, cc_library_static, version script assignment of 'LIBC_PRIVATE' to symbol 'SHA1Final' failed: symbol not defined
+		"libc_openbsd",  // ruperts@, cc_library_static, OK for bp2build but error: duplicate symbol: strcpy for mixed builds
 	}
 
 	// Used for quicker lookups
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 63e2c50..4280bc3 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -243,6 +243,14 @@
 	labels := bazel.LabelList{
 		Includes: []bazel.Label{},
 	}
+
+	// expandedExcludes contain module-dir relative paths, but root-relative paths
+	// are needed for GlobFiles later.
+	var rootRelativeExpandedExcludes []string
+	for _, e := range expandedExcludes {
+		rootRelativeExpandedExcludes = append(rootRelativeExpandedExcludes, filepath.Join(ctx.ModuleDir(), e))
+	}
+
 	for _, p := range paths {
 		if m, tag := SrcIsModuleWithTag(p); m != "" {
 			l := getOtherModuleLabel(ctx, m, tag)
@@ -253,7 +261,10 @@
 		} else {
 			var expandedPaths []bazel.Label
 			if pathtools.IsGlob(p) {
-				globbedPaths := GlobFiles(ctx, pathForModuleSrc(ctx, p).String(), expandedExcludes)
+				// e.g. turn "math/*.c" in
+				// external/arm-optimized-routines to external/arm-optimized-routines/math/*.c
+				rootRelativeGlobPath := pathForModuleSrc(ctx, p).String()
+				globbedPaths := GlobFiles(ctx, rootRelativeGlobPath, rootRelativeExpandedExcludes)
 				globbedPaths = PathsWithModuleSrcSubDir(ctx, globbedPaths, "")
 				for _, path := range globbedPaths {
 					s := path.Rel()
diff --git a/android/neverallow.go b/android/neverallow.go
index a385bbc..d4a1ff1 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -63,8 +63,7 @@
 }
 
 func createIncludeDirsRules() []Rule {
-	// The list of paths that cannot be referenced using include_dirs
-	paths := []string{
+	notInIncludeDir := []string{
 		"art",
 		"art/libnativebridge",
 		"art/libnativeloader",
@@ -80,12 +79,13 @@
 		"external/vixl",
 		"external/wycheproof",
 	}
+	noUseIncludeDir := []string{
+		"system/libfmq",
+	}
 
-	// Create a composite matcher that will match if the value starts with any of the restricted
-	// paths. A / is appended to the prefix to ensure that restricting path X does not affect paths
-	// XY.
-	rules := make([]Rule, 0, len(paths))
-	for _, path := range paths {
+	rules := make([]Rule, 0, len(notInIncludeDir)+len(noUseIncludeDir))
+
+	for _, path := range notInIncludeDir {
 		rule :=
 			NeverAllow().
 				WithMatcher("include_dirs", StartsWith(path+"/")).
@@ -95,6 +95,13 @@
 		rules = append(rules, rule)
 	}
 
+	for _, path := range noUseIncludeDir {
+		rule := NeverAllow().In(path+"/").WithMatcher("include_dirs", isSetMatcherInstance).
+			Because("include_dirs is deprecated, all usages of them in '" + path + "' have been migrated" +
+				" to use alternate mechanisms and so can no longer be used.")
+		rules = append(rules, rule)
+	}
+
 	return rules
 }
 
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 268346a..35aadd8 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -76,7 +76,20 @@
 		},
 	},
 	{
-		name: "include_dir can reference another location",
+		name: "include_dir not allowed to reference art",
+		fs: map[string][]byte{
+			"system/libfmq/Android.bp": []byte(`
+				cc_library {
+					name: "libother",
+					include_dirs: ["any/random/file"],
+				}`),
+		},
+		expectedErrors: []string{
+			"all usages of them in 'system/libfmq' have been migrated",
+		},
+	},
+	{
+		name: "include_dir can work",
 		fs: map[string][]byte{
 			"other/Android.bp": []byte(`
 				cc_library {
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index feda482..3d39d34 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -15,6 +15,7 @@
 package apex
 
 import (
+	"fmt"
 	"strings"
 	"testing"
 
@@ -162,13 +163,11 @@
 }
 
 func TestBootclasspathFragmentInArtApex(t *testing.T) {
-	result := android.GroupFixturePreparers(
+	commonPreparer := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
 		prepareForTestWithArtApex,
 
-		// Configure some libraries in the art bootclasspath_fragment.
-		java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
-	).RunTestWithBp(t, `
+		android.FixtureWithRootAndroidBp(`
 		apex {
 			name: "com.android.art",
 			key: "com.android.art.key",
@@ -208,14 +207,6 @@
 			],
 		}
 
-		bootclasspath_fragment {
-			name: "mybootclasspathfragment",
-			image_name: "art",
-			apex_available: [
-				"com.android.art",
-			],
-		}
-
 		java_import {
 			name: "foo",
 			jars: ["foo.jar"],
@@ -231,39 +222,141 @@
 				"com.android.art",
 			],
 		}
+	`),
+	)
 
-		// Make sure that a preferred prebuilt doesn't affect the apex.
-		prebuilt_bootclasspath_fragment {
-			name: "mybootclasspathfragment",
-			image_name: "art",
-			prefer: true,
-			apex_available: [
-				"com.android.art",
-			],
+	contentsInsert := func(contents []string) string {
+		insert := ""
+		if contents != nil {
+			insert = fmt.Sprintf(`contents: ["%s"],`, strings.Join(contents, `", "`))
 		}
-	`)
+		return insert
+	}
 
-	ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
-		"javalib/arm/boot.art",
-		"javalib/arm/boot.oat",
-		"javalib/arm/boot.vdex",
-		"javalib/arm/boot-bar.art",
-		"javalib/arm/boot-bar.oat",
-		"javalib/arm/boot-bar.vdex",
-		"javalib/arm64/boot.art",
-		"javalib/arm64/boot.oat",
-		"javalib/arm64/boot.vdex",
-		"javalib/arm64/boot-bar.art",
-		"javalib/arm64/boot-bar.oat",
-		"javalib/arm64/boot-bar.vdex",
-		"javalib/bar.jar",
-		"javalib/foo.jar",
+	addSource := func(contents ...string) android.FixturePreparer {
+		text := fmt.Sprintf(`
+			bootclasspath_fragment {
+				name: "mybootclasspathfragment",
+				image_name: "art",
+				%s
+				apex_available: [
+					"com.android.art",
+				],
+			}
+		`, contentsInsert(contents))
+
+		return android.FixtureAddTextFile("art/build/boot/Android.bp", text)
+	}
+
+	addPrebuilt := func(prefer bool, contents ...string) android.FixturePreparer {
+		text := fmt.Sprintf(`
+			prebuilt_bootclasspath_fragment {
+				name: "mybootclasspathfragment",
+				image_name: "art",
+				%s
+				prefer: %t,
+				apex_available: [
+					"com.android.art",
+				],
+			}
+		`, contentsInsert(contents), prefer)
+		return android.FixtureAddTextFile("prebuilts/module_sdk/art/Android.bp", text)
+	}
+
+	t.Run("boot image files", func(t *testing.T) {
+		result := android.GroupFixturePreparers(
+			commonPreparer,
+
+			// Configure some libraries in the art bootclasspath_fragment that match the source
+			// bootclasspath_fragment's contents property.
+			java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
+			addSource("foo", "bar"),
+
+			// Make sure that a preferred prebuilt with consistent contents doesn't affect the apex.
+			addPrebuilt(true, "foo", "bar"),
+		).RunTest(t)
+
+		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+			"javalib/arm/boot.art",
+			"javalib/arm/boot.oat",
+			"javalib/arm/boot.vdex",
+			"javalib/arm/boot-bar.art",
+			"javalib/arm/boot-bar.oat",
+			"javalib/arm/boot-bar.vdex",
+			"javalib/arm64/boot.art",
+			"javalib/arm64/boot.oat",
+			"javalib/arm64/boot.vdex",
+			"javalib/arm64/boot-bar.art",
+			"javalib/arm64/boot-bar.oat",
+			"javalib/arm64/boot-bar.vdex",
+			"javalib/bar.jar",
+			"javalib/foo.jar",
+		})
+
+		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+			`bar`,
+			`com.android.art.key`,
+			`mybootclasspathfragment`,
+		})
 	})
 
-	java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
-		`bar`,
-		`com.android.art.key`,
-		`mybootclasspathfragment`,
+	t.Run("source with inconsistency between config and contents", func(t *testing.T) {
+		android.GroupFixturePreparers(
+			commonPreparer,
+
+			// Create an inconsistency between the ArtApexJars configuration and the art source
+			// bootclasspath_fragment module's contents property.
+			java.FixtureConfigureBootJars("com.android.art:foo"),
+			addSource("foo", "bar"),
+		).
+			ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`\QArtApexJars configuration specifies []string{"foo"}, contents property specifies []string{"foo", "bar"}\E`)).
+			RunTest(t)
+	})
+
+	t.Run("prebuilt with inconsistency between config and contents", func(t *testing.T) {
+		android.GroupFixturePreparers(
+			commonPreparer,
+
+			// Create an inconsistency between the ArtApexJars configuration and the art
+			// prebuilt_bootclasspath_fragment module's contents property.
+			java.FixtureConfigureBootJars("com.android.art:foo"),
+			addPrebuilt(false, "foo", "bar"),
+		).
+			ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`\QArtApexJars configuration specifies []string{"foo"}, contents property specifies []string{"foo", "bar"}\E`)).
+			RunTest(t)
+	})
+
+	t.Run("preferred prebuilt with inconsistency between config and contents", func(t *testing.T) {
+		android.GroupFixturePreparers(
+			commonPreparer,
+
+			// Create an inconsistency between the ArtApexJars configuration and the art
+			// prebuilt_bootclasspath_fragment module's contents property.
+			java.FixtureConfigureBootJars("com.android.art:foo"),
+			addPrebuilt(true, "foo", "bar"),
+
+			// Source contents property is consistent with the config.
+			addSource("foo"),
+		).
+			ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`\QArtApexJars configuration specifies []string{"foo"}, contents property specifies []string{"foo", "bar"}\E`)).
+			RunTest(t)
+	})
+
+	t.Run("source preferred and prebuilt with inconsistency between config and contents", func(t *testing.T) {
+		android.GroupFixturePreparers(
+			commonPreparer,
+
+			// Create an inconsistency between the ArtApexJars configuration and the art
+			// prebuilt_bootclasspath_fragment module's contents property.
+			java.FixtureConfigureBootJars("com.android.art:foo"),
+			addPrebuilt(false, "foo", "bar"),
+
+			// Source contents property is consistent with the config.
+			addSource("foo"),
+
+			// This should pass because while the prebuilt is inconsistent with the configuration it is
+			// not actually used.
+		).RunTest(t)
 	})
 }
 
diff --git a/bazel/properties.go b/bazel/properties.go
index 48d9589..037150d 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -64,43 +64,6 @@
 	Excludes []Label
 }
 
-// GlobsInDir returns a list of glob expressions for a list of extensions
-// (optionally recursive) within a directory.
-func GlobsInDir(dir string, recursive bool, extensions []string) []string {
-	globs := []string{}
-
-	globInfix := ""
-	if dir == "." {
-		if recursive {
-			// e.g "**/*.h"
-			globInfix = "**/"
-		} // else e.g. "*.h"
-		for _, ext := range extensions {
-			globs = append(globs, globInfix+"*"+ext)
-		}
-	} else {
-		if recursive {
-			// e.g. "foo/bar/**/*.h"
-			dir += "/**"
-		} // else e.g. "foo/bar/*.h"
-		for _, ext := range extensions {
-			globs = append(globs, dir+"/*"+ext)
-		}
-	}
-	return globs
-}
-
-// LooseHdrsGlobs returns the list of non-recursive header globs for each parent directory of
-// each source file in this LabelList's Includes.
-func (ll *LabelList) LooseHdrsGlobs(exts []string) []string {
-	var globs []string
-	for _, parentDir := range ll.uniqueParentDirectories() {
-		globs = append(globs,
-			GlobsInDir(parentDir, false, exts)...)
-	}
-	return globs
-}
-
 // uniqueParentDirectories returns a list of the unique parent directories for
 // all files in ll.Includes.
 func (ll *LabelList) uniqueParentDirectories() []string {
@@ -220,6 +183,15 @@
 	OS_LINUX        = "linux_glibc"
 	OS_LINUX_BIONIC = "linux_bionic"
 	OS_WINDOWS      = "windows"
+
+	// This is the string representation of the default condition wherever a
+	// configurable attribute is used in a select statement, i.e.
+	// //conditions:default for Bazel.
+	//
+	// This is consistently named "conditions_default" to mirror the Soong
+	// config variable default key in an Android.bp file, although there's no
+	// integration with Soong config variables (yet).
+	CONDITIONS_DEFAULT = "conditions_default"
 )
 
 var (
@@ -231,21 +203,23 @@
 	// A map of architectures to the Bazel label of the constraint_value
 	// for the @platforms//cpu:cpu constraint_setting
 	PlatformArchMap = map[string]string{
-		ARCH_ARM:    "//build/bazel/platforms/arch:arm",
-		ARCH_ARM64:  "//build/bazel/platforms/arch:arm64",
-		ARCH_X86:    "//build/bazel/platforms/arch:x86",
-		ARCH_X86_64: "//build/bazel/platforms/arch:x86_64",
+		ARCH_ARM:           "//build/bazel/platforms/arch:arm",
+		ARCH_ARM64:         "//build/bazel/platforms/arch:arm64",
+		ARCH_X86:           "//build/bazel/platforms/arch:x86",
+		ARCH_X86_64:        "//build/bazel/platforms/arch:x86_64",
+		CONDITIONS_DEFAULT: "//conditions:default", // The default condition of as arch select map.
 	}
 
 	// A map of target operating systems to the Bazel label of the
 	// constraint_value for the @platforms//os:os constraint_setting
 	PlatformOsMap = map[string]string{
-		OS_ANDROID:      "//build/bazel/platforms/os:android",
-		OS_DARWIN:       "//build/bazel/platforms/os:darwin",
-		OS_FUCHSIA:      "//build/bazel/platforms/os:fuchsia",
-		OS_LINUX:        "//build/bazel/platforms/os:linux",
-		OS_LINUX_BIONIC: "//build/bazel/platforms/os:linux_bionic",
-		OS_WINDOWS:      "//build/bazel/platforms/os:windows",
+		OS_ANDROID:         "//build/bazel/platforms/os:android",
+		OS_DARWIN:          "//build/bazel/platforms/os:darwin",
+		OS_FUCHSIA:         "//build/bazel/platforms/os:fuchsia",
+		OS_LINUX:           "//build/bazel/platforms/os:linux",
+		OS_LINUX_BIONIC:    "//build/bazel/platforms/os:linux_bionic",
+		OS_WINDOWS:         "//build/bazel/platforms/os:windows",
+		CONDITIONS_DEFAULT: "//conditions:default", // The default condition of an os select map.
 	}
 )
 
@@ -261,6 +235,8 @@
 	Arm    LabelList
 	Arm64  LabelList
 	Common LabelList
+
+	ConditionsDefault LabelList
 }
 
 type labelListOsValues struct {
@@ -270,6 +246,8 @@
 	Linux       LabelList
 	LinuxBionic LabelList
 	Windows     LabelList
+
+	ConditionsDefault LabelList
 }
 
 // LabelListAttribute is used to represent a list of Bazel labels as an
@@ -333,10 +311,11 @@
 
 func (attrs *LabelListAttribute) archValuePtrs() map[string]*LabelList {
 	return map[string]*LabelList{
-		ARCH_X86:    &attrs.ArchValues.X86,
-		ARCH_X86_64: &attrs.ArchValues.X86_64,
-		ARCH_ARM:    &attrs.ArchValues.Arm,
-		ARCH_ARM64:  &attrs.ArchValues.Arm64,
+		ARCH_X86:           &attrs.ArchValues.X86,
+		ARCH_X86_64:        &attrs.ArchValues.X86_64,
+		ARCH_ARM:           &attrs.ArchValues.Arm,
+		ARCH_ARM64:         &attrs.ArchValues.Arm64,
+		CONDITIONS_DEFAULT: &attrs.ArchValues.ConditionsDefault,
 	}
 }
 
@@ -360,12 +339,13 @@
 
 func (attrs *LabelListAttribute) osValuePtrs() map[string]*LabelList {
 	return map[string]*LabelList{
-		OS_ANDROID:      &attrs.OsValues.Android,
-		OS_DARWIN:       &attrs.OsValues.Darwin,
-		OS_FUCHSIA:      &attrs.OsValues.Fuchsia,
-		OS_LINUX:        &attrs.OsValues.Linux,
-		OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic,
-		OS_WINDOWS:      &attrs.OsValues.Windows,
+		OS_ANDROID:         &attrs.OsValues.Android,
+		OS_DARWIN:          &attrs.OsValues.Darwin,
+		OS_FUCHSIA:         &attrs.OsValues.Fuchsia,
+		OS_LINUX:           &attrs.OsValues.Linux,
+		OS_LINUX_BIONIC:    &attrs.OsValues.LinuxBionic,
+		OS_WINDOWS:         &attrs.OsValues.Windows,
+		CONDITIONS_DEFAULT: &attrs.OsValues.ConditionsDefault,
 	}
 }
 
@@ -418,6 +398,8 @@
 	Arm    []string
 	Arm64  []string
 	Common []string
+
+	ConditionsDefault []string
 }
 
 type stringListOsValues struct {
@@ -427,6 +409,8 @@
 	Linux       []string
 	LinuxBionic []string
 	Windows     []string
+
+	ConditionsDefault []string
 }
 
 // HasConfigurableValues returns true if the attribute contains
@@ -448,10 +432,11 @@
 
 func (attrs *StringListAttribute) archValuePtrs() map[string]*[]string {
 	return map[string]*[]string{
-		ARCH_X86:    &attrs.ArchValues.X86,
-		ARCH_X86_64: &attrs.ArchValues.X86_64,
-		ARCH_ARM:    &attrs.ArchValues.Arm,
-		ARCH_ARM64:  &attrs.ArchValues.Arm64,
+		ARCH_X86:           &attrs.ArchValues.X86,
+		ARCH_X86_64:        &attrs.ArchValues.X86_64,
+		ARCH_ARM:           &attrs.ArchValues.Arm,
+		ARCH_ARM64:         &attrs.ArchValues.Arm64,
+		CONDITIONS_DEFAULT: &attrs.ArchValues.ConditionsDefault,
 	}
 }
 
@@ -475,12 +460,13 @@
 
 func (attrs *StringListAttribute) osValuePtrs() map[string]*[]string {
 	return map[string]*[]string{
-		OS_ANDROID:      &attrs.OsValues.Android,
-		OS_DARWIN:       &attrs.OsValues.Darwin,
-		OS_FUCHSIA:      &attrs.OsValues.Fuchsia,
-		OS_LINUX:        &attrs.OsValues.Linux,
-		OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic,
-		OS_WINDOWS:      &attrs.OsValues.Windows,
+		OS_ANDROID:         &attrs.OsValues.Android,
+		OS_DARWIN:          &attrs.OsValues.Darwin,
+		OS_FUCHSIA:         &attrs.OsValues.Fuchsia,
+		OS_LINUX:           &attrs.OsValues.Linux,
+		OS_LINUX_BIONIC:    &attrs.OsValues.LinuxBionic,
+		OS_WINDOWS:         &attrs.OsValues.Windows,
+		CONDITIONS_DEFAULT: &attrs.OsValues.ConditionsDefault,
 	}
 }
 
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 21d7062..63a6c2e 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -1512,3 +1512,126 @@
 		}
 	}
 }
+
+func TestGlobExcludeSrcs(t *testing.T) {
+	testCases := []struct {
+		description                        string
+		moduleTypeUnderTest                string
+		moduleTypeUnderTestFactory         android.ModuleFactory
+		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+		bp                                 string
+		expectedBazelTargets               []string
+		fs                                 map[string]string
+		dir                                string
+	}{
+		{
+			description:                        "filegroup top level exclude_srcs",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+			bp: `filegroup {
+    name: "fg_foo",
+    srcs: ["**/*.txt"],
+    exclude_srcs: ["c.txt"],
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`filegroup(
+    name = "fg_foo",
+    srcs = [
+        "//dir:e.txt",
+        "//dir:f.txt",
+        "a.txt",
+        "b.txt",
+    ],
+)`,
+			},
+			fs: map[string]string{
+				"a.txt":          "",
+				"b.txt":          "",
+				"c.txt":          "",
+				"dir/Android.bp": "",
+				"dir/e.txt":      "",
+				"dir/f.txt":      "",
+			},
+		},
+		{
+			description:                        "filegroup in subdir exclude_srcs",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+			bp:                                 "",
+			dir:                                "dir",
+			fs: map[string]string{
+				"dir/Android.bp": `filegroup {
+    name: "fg_foo",
+    srcs: ["**/*.txt"],
+    exclude_srcs: ["b.txt"],
+    bazel_module: { bp2build_available: true },
+}
+`,
+				"dir/a.txt":             "",
+				"dir/b.txt":             "",
+				"dir/subdir/Android.bp": "",
+				"dir/subdir/e.txt":      "",
+				"dir/subdir/f.txt":      "",
+			},
+			expectedBazelTargets: []string{`filegroup(
+    name = "fg_foo",
+    srcs = [
+        "//dir/subdir:e.txt",
+        "//dir/subdir:f.txt",
+        "a.txt",
+    ],
+)`,
+			},
+		},
+	}
+
+	dir := "."
+	for _, testCase := range testCases {
+		fs := make(map[string][]byte)
+		toParse := []string{
+			"Android.bp",
+		}
+		for f, content := range testCase.fs {
+			if strings.HasSuffix(f, "Android.bp") {
+				toParse = append(toParse, f)
+			}
+			fs[f] = []byte(content)
+		}
+		config := android.TestConfig(buildDir, nil, testCase.bp, fs)
+		ctx := android.NewTestContext(config)
+		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+		ctx.RegisterForBazelConversion()
+
+		_, errs := ctx.ParseFileList(dir, toParse)
+		if Errored(t, testCase.description, errs) {
+			continue
+		}
+		_, errs = ctx.ResolveDependencies(config)
+		if Errored(t, testCase.description, errs) {
+			continue
+		}
+
+		checkDir := dir
+		if testCase.dir != "" {
+			checkDir = testCase.dir
+		}
+		bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir)
+		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
+			t.Errorf("%s: Expected %d bazel target, got %d\n%s", testCase.description, expectedCount, actualCount, bazelTargets)
+		} else {
+			for i, target := range bazelTargets {
+				if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
+					t.Errorf(
+						"%s: Expected generated Bazel target to be '%s', got '%s'",
+						testCase.description,
+						w,
+						g,
+					)
+				}
+			}
+		}
+	}
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 4b6e888..d9cd22d 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -114,26 +114,13 @@
         "-I.",
     ],
     deps = [":some-headers"],
-    hdrs = ["foo-dir/a.h"],
     includes = ["foo-dir"],
     linkopts = ["-Wl,--exclude-libs=bar.a"] + select({
         "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"],
         "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=qux.a"],
         "//conditions:default": [],
     }),
-    srcs = [
-        "impl.cpp",
-        "header.h",
-        "foo-dir/a.h",
-        "header.hh",
-        "header.hpp",
-        "header.hxx",
-        "header.h++",
-        "header.inl",
-        "header.inc",
-        "header.ipp",
-        "header.h.generic",
-    ] + select({
+    srcs = ["impl.cpp"] + select({
         "//build/bazel/platforms/arch:x86": ["x86.cpp"],
         "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
         "//conditions:default": [],
@@ -209,13 +196,56 @@
         "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=libgcc_eh.a"],
         "//conditions:default": [],
     }),
-    srcs = [
-        "ld_android.cpp",
-        "linked_list.h",
-        "linker.h",
-        "linker_block_allocator.h",
-        "linker_cfi.h",
+    srcs = ["ld_android.cpp"],
+)`},
+		},
+		{
+			description:                        "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math",
+			moduleTypeUnderTest:                "cc_library",
+			moduleTypeUnderTestFactory:         cc.LibraryFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+			dir:                                "external",
+			filesystem: map[string]string{
+				"external/math/cosf.c":      "",
+				"external/math/erf.c":       "",
+				"external/math/erf_data.c":  "",
+				"external/math/erff.c":      "",
+				"external/math/erff_data.c": "",
+				"external/Android.bp": `
+cc_library {
+    name: "fake-libarm-optimized-routines-math",
+    exclude_srcs: [
+        // Provided by:
+        // bionic/libm/upstream-freebsd/lib/msun/src/s_erf.c
+        // bionic/libm/upstream-freebsd/lib/msun/src/s_erff.c
+        "math/erf.c",
+        "math/erf_data.c",
+        "math/erff.c",
+        "math/erff_data.c",
     ],
+    srcs: [
+        "math/*.c",
+    ],
+    // arch-specific settings
+    arch: {
+        arm64: {
+            cflags: [
+                "-DHAVE_FAST_FMA=1",
+            ],
+        },
+    },
+    bazel_module: { bp2build_available: true },
+}
+`,
+			},
+			bp: soongCcLibraryPreamble,
+			expectedBazelTargets: []string{`cc_library(
+    name = "fake-libarm-optimized-routines-math",
+    copts = ["-Iexternal"] + select({
+        "//build/bazel/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"],
+        "//conditions:default": [],
+    }),
+    srcs = ["math/cosf.c"],
 )`},
 		},
 	}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 00042ab..0905aba 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -136,17 +136,6 @@
         ":lib-1",
         ":lib-2",
     ],
-    hdrs = [
-        "dir-1/dir1a.h",
-        "dir-1/dir1b.h",
-        "dir-2/dir2a.h",
-        "dir-2/dir2b.h",
-    ] + select({
-        "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir/a.h"],
-        "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir/b.h"],
-        "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir/c.h"],
-        "//conditions:default": [],
-    }),
     includes = [
         "dir-1",
         "dir-2",
@@ -159,18 +148,10 @@
 )`, `cc_library_headers(
     name = "lib-1",
     copts = ["-I."],
-    hdrs = [
-        "lib-1/lib1a.h",
-        "lib-1/lib1b.h",
-    ],
     includes = ["lib-1"],
 )`, `cc_library_headers(
     name = "lib-2",
     copts = ["-I."],
-    hdrs = [
-        "lib-2/lib2a.h",
-        "lib-2/lib2b.h",
-    ],
     includes = ["lib-2"],
 )`},
 		},
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 00325fb..9d23cc5 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -192,12 +192,6 @@
         ":whole_static_lib_1",
         ":whole_static_lib_2",
     ],
-    hdrs = [
-        "export_include_dir_1/export_include_dir_1_a.h",
-        "export_include_dir_1/export_include_dir_1_b.h",
-        "export_include_dir_2/export_include_dir_2_a.h",
-        "export_include_dir_2/export_include_dir_2_b.h",
-    ],
     includes = [
         "export_include_dir_1",
         "export_include_dir_2",
@@ -206,105 +200,27 @@
     srcs = [
         "foo_static1.cc",
         "foo_static2.cc",
-        "implicit_include_1.h",
-        "implicit_include_2.h",
-        "export_include_dir_1/export_include_dir_1_a.h",
-        "export_include_dir_1/export_include_dir_1_b.h",
-        "export_include_dir_2/export_include_dir_2_a.h",
-        "export_include_dir_2/export_include_dir_2_b.h",
-        "include_dir_1/include_dir_1_a.h",
-        "include_dir_1/include_dir_1_b.h",
-        "include_dir_2/include_dir_2_a.h",
-        "include_dir_2/include_dir_2_b.h",
-        "local_include_dir_1/local_include_dir_1_a.h",
-        "local_include_dir_1/local_include_dir_1_b.h",
-        "local_include_dir_2/local_include_dir_2_a.h",
-        "local_include_dir_2/local_include_dir_2_b.h",
     ],
 )`, `cc_library_static(
     name = "static_lib_1",
     copts = ["-I."],
     linkstatic = True,
-    srcs = [
-        "static_lib_1.cc",
-        "implicit_include_1.h",
-        "implicit_include_2.h",
-        "export_include_dir_1/export_include_dir_1_a.h",
-        "export_include_dir_1/export_include_dir_1_b.h",
-        "export_include_dir_2/export_include_dir_2_a.h",
-        "export_include_dir_2/export_include_dir_2_b.h",
-        "include_dir_1/include_dir_1_a.h",
-        "include_dir_1/include_dir_1_b.h",
-        "include_dir_2/include_dir_2_a.h",
-        "include_dir_2/include_dir_2_b.h",
-        "local_include_dir_1/local_include_dir_1_a.h",
-        "local_include_dir_1/local_include_dir_1_b.h",
-        "local_include_dir_2/local_include_dir_2_a.h",
-        "local_include_dir_2/local_include_dir_2_b.h",
-    ],
+    srcs = ["static_lib_1.cc"],
 )`, `cc_library_static(
     name = "static_lib_2",
     copts = ["-I."],
     linkstatic = True,
-    srcs = [
-        "static_lib_2.cc",
-        "implicit_include_1.h",
-        "implicit_include_2.h",
-        "export_include_dir_1/export_include_dir_1_a.h",
-        "export_include_dir_1/export_include_dir_1_b.h",
-        "export_include_dir_2/export_include_dir_2_a.h",
-        "export_include_dir_2/export_include_dir_2_b.h",
-        "include_dir_1/include_dir_1_a.h",
-        "include_dir_1/include_dir_1_b.h",
-        "include_dir_2/include_dir_2_a.h",
-        "include_dir_2/include_dir_2_b.h",
-        "local_include_dir_1/local_include_dir_1_a.h",
-        "local_include_dir_1/local_include_dir_1_b.h",
-        "local_include_dir_2/local_include_dir_2_a.h",
-        "local_include_dir_2/local_include_dir_2_b.h",
-    ],
+    srcs = ["static_lib_2.cc"],
 )`, `cc_library_static(
     name = "whole_static_lib_1",
     copts = ["-I."],
     linkstatic = True,
-    srcs = [
-        "whole_static_lib_1.cc",
-        "implicit_include_1.h",
-        "implicit_include_2.h",
-        "export_include_dir_1/export_include_dir_1_a.h",
-        "export_include_dir_1/export_include_dir_1_b.h",
-        "export_include_dir_2/export_include_dir_2_a.h",
-        "export_include_dir_2/export_include_dir_2_b.h",
-        "include_dir_1/include_dir_1_a.h",
-        "include_dir_1/include_dir_1_b.h",
-        "include_dir_2/include_dir_2_a.h",
-        "include_dir_2/include_dir_2_b.h",
-        "local_include_dir_1/local_include_dir_1_a.h",
-        "local_include_dir_1/local_include_dir_1_b.h",
-        "local_include_dir_2/local_include_dir_2_a.h",
-        "local_include_dir_2/local_include_dir_2_b.h",
-    ],
+    srcs = ["whole_static_lib_1.cc"],
 )`, `cc_library_static(
     name = "whole_static_lib_2",
     copts = ["-I."],
     linkstatic = True,
-    srcs = [
-        "whole_static_lib_2.cc",
-        "implicit_include_1.h",
-        "implicit_include_2.h",
-        "export_include_dir_1/export_include_dir_1_a.h",
-        "export_include_dir_1/export_include_dir_1_b.h",
-        "export_include_dir_2/export_include_dir_2_a.h",
-        "export_include_dir_2/export_include_dir_2_b.h",
-        "include_dir_1/include_dir_1_a.h",
-        "include_dir_1/include_dir_1_b.h",
-        "include_dir_2/include_dir_2_a.h",
-        "include_dir_2/include_dir_2_b.h",
-        "local_include_dir_1/local_include_dir_1_a.h",
-        "local_include_dir_1/local_include_dir_1_b.h",
-        "local_include_dir_2/local_include_dir_2_a.h",
-        "local_include_dir_2/local_include_dir_2_b.h",
-    ],
+    srcs = ["whole_static_lib_2.cc"],
 )`},
 		},
 		{
@@ -342,14 +258,6 @@
         "-I.",
     ],
     linkstatic = True,
-    srcs = [
-        "//subpackage:subpackage_header.h",
-        "//subpackage:subdirectory/subdirectory_header.h",
-        "//subpackage/subsubpackage:subsubpackage_header.h",
-        "//subpackage/subsubpackage:subdirectory/subdirectory_header.h",
-        "//subpackage/subsubpackage/subsubsubpackage:subsubsubpackage_header.h",
-        "//subpackage/subsubpackage/subsubsubpackage:subdirectory/subdirectory_header.h",
-    ],
 )`},
 		},
 		{
@@ -371,16 +279,8 @@
 			expectedBazelTargets: []string{`cc_library_static(
     name = "foo_static",
     copts = ["-I."],
-    hdrs = [
-        "//subpackage:subdirectory/subdirectory_header.h",
-        "//subpackage:subpackage_header.h",
-    ],
     includes = ["subpackage"],
     linkstatic = True,
-    srcs = [
-        "//subpackage:subpackage_header.h",
-        "//subpackage:subdirectory/subdirectory_header.h",
-    ],
 )`},
 		},
 		{
@@ -402,16 +302,8 @@
 			expectedBazelTargets: []string{`cc_library_static(
     name = "foo_static",
     copts = ["-I."],
-    hdrs = [
-        "//subpackage:subdirectory/subdirectory_header.h",
-        "//subpackage:subpackage_header.h",
-    ],
     includes = ["subpackage"],
     linkstatic = True,
-    srcs = [
-        "//subpackage:subpackage_header.h",
-        "//subpackage:subdirectory/subdirectory_header.h",
-    ],
 )`},
 		},
 		{
@@ -452,14 +344,8 @@
         "-Isubpackage/subsubpackage2",
         "-Isubpackage",
     ],
-    hdrs = ["exported_subsubpackage/header.h"],
     includes = ["./exported_subsubpackage"],
     linkstatic = True,
-    srcs = [
-        "exported_subsubpackage/header.h",
-        "subsubpackage/header.h",
-        "subsubpackage2/header.h",
-    ],
 )`},
 		},
 		{
@@ -517,11 +403,6 @@
         "-I.",
     ],
     linkstatic = True,
-    srcs = [
-        "//subpackage:subpackage_header.h",
-        "//subpackage:subdirectory/subdirectory_header.h",
-        "//subpackage2:subpackage2_header.h",
-    ],
 )`},
 		},
 		{
@@ -645,6 +526,201 @@
     linkstatic = True,
 )`},
 		},
+		{
+			description:                        "cc_library_static simple exclude_srcs",
+			moduleTypeUnderTest:                "cc_library_static",
+			moduleTypeUnderTestFactory:         cc.LibraryStaticFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+			filesystem: map[string]string{
+				"common.c":       "",
+				"foo-a.c":        "",
+				"foo-excluded.c": "",
+			},
+			bp: soongCcLibraryStaticPreamble + `
+cc_library_static {
+    name: "foo_static",
+    srcs: ["common.c", "foo-*.c"],
+    exclude_srcs: ["foo-excluded.c"],
+}`,
+			expectedBazelTargets: []string{`cc_library_static(
+    name = "foo_static",
+    copts = ["-I."],
+    linkstatic = True,
+    srcs = [
+        "common.c",
+        "foo-a.c",
+    ],
+)`},
+		},
+		{
+			description:                        "cc_library_static one arch specific srcs",
+			moduleTypeUnderTest:                "cc_library_static",
+			moduleTypeUnderTestFactory:         cc.LibraryStaticFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+			filesystem: map[string]string{
+				"common.c":  "",
+				"foo-arm.c": "",
+			},
+			bp: soongCcLibraryStaticPreamble + `
+cc_library_static {
+    name: "foo_static",
+    srcs: ["common.c"],
+    arch: { arm: { srcs: ["foo-arm.c"] } }
+}`,
+			expectedBazelTargets: []string{`cc_library_static(
+    name = "foo_static",
+    copts = ["-I."],
+    linkstatic = True,
+    srcs = ["common.c"] + select({
+        "//build/bazel/platforms/arch:arm": ["foo-arm.c"],
+        "//conditions:default": [],
+    }),
+)`},
+		},
+		{
+			description:                        "cc_library_static one arch specific srcs and exclude_srcs",
+			moduleTypeUnderTest:                "cc_library_static",
+			moduleTypeUnderTestFactory:         cc.LibraryStaticFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+			filesystem: map[string]string{
+				"common.c":           "",
+				"for-arm.c":          "",
+				"not-for-arm.c":      "",
+				"not-for-anything.c": "",
+			},
+			bp: soongCcLibraryStaticPreamble + `
+cc_library_static {
+    name: "foo_static",
+    srcs: ["common.c", "not-for-*.c"],
+    exclude_srcs: ["not-for-anything.c"],
+    arch: {
+        arm: { srcs: ["for-arm.c"], exclude_srcs: ["not-for-arm.c"] },
+    },
+}`,
+			expectedBazelTargets: []string{`cc_library_static(
+    name = "foo_static",
+    copts = ["-I."],
+    linkstatic = True,
+    srcs = ["common.c"] + select({
+        "//build/bazel/platforms/arch:arm": ["for-arm.c"],
+        "//conditions:default": ["not-for-arm.c"],
+    }),
+)`},
+		},
+		{
+			description:                        "cc_library_static arch specific exclude_srcs for 2 architectures",
+			moduleTypeUnderTest:                "cc_library_static",
+			moduleTypeUnderTestFactory:         cc.LibraryStaticFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+			filesystem: map[string]string{
+				"common.c":      "",
+				"for-arm.c":     "",
+				"for-x86.c":     "",
+				"not-for-arm.c": "",
+				"not-for-x86.c": "",
+			},
+			bp: soongCcLibraryStaticPreamble + `
+cc_library_static {
+    name: "foo_static",
+    srcs: ["common.c", "not-for-*.c"],
+    exclude_srcs: ["not-for-everything.c"],
+    arch: {
+        arm: { srcs: ["for-arm.c"], exclude_srcs: ["not-for-arm.c"] },
+        x86: { srcs: ["for-x86.c"], exclude_srcs: ["not-for-x86.c"] },
+    },
+} `,
+			expectedBazelTargets: []string{`cc_library_static(
+    name = "foo_static",
+    copts = ["-I."],
+    linkstatic = True,
+    srcs = ["common.c"] + select({
+        "//build/bazel/platforms/arch:arm": [
+            "for-arm.c",
+            "not-for-x86.c",
+        ],
+        "//build/bazel/platforms/arch:x86": [
+            "for-x86.c",
+            "not-for-arm.c",
+        ],
+        "//conditions:default": [
+            "not-for-arm.c",
+            "not-for-x86.c",
+        ],
+    }),
+)`},
+		},
+		{
+			description:                        "cc_library_static arch specific exclude_srcs for 4 architectures",
+			moduleTypeUnderTest:                "cc_library_static",
+			moduleTypeUnderTestFactory:         cc.LibraryStaticFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+			filesystem: map[string]string{
+				"common.c":             "",
+				"for-arm.c":            "",
+				"for-arm64.c":          "",
+				"for-x86.c":            "",
+				"for-x86_64.c":         "",
+				"not-for-arm.c":        "",
+				"not-for-arm64.c":      "",
+				"not-for-x86.c":        "",
+				"not-for-x86_64.c":     "",
+				"not-for-everything.c": "",
+			},
+			bp: soongCcLibraryStaticPreamble + `
+cc_library_static {
+    name: "foo_static",
+    srcs: ["common.c", "not-for-*.c"],
+    exclude_srcs: ["not-for-everything.c"],
+    arch: {
+        arm: { srcs: ["for-arm.c"], exclude_srcs: ["not-for-arm.c"] },
+        arm64: { srcs: ["for-arm64.c"], exclude_srcs: ["not-for-arm64.c"] },
+        x86: { srcs: ["for-x86.c"], exclude_srcs: ["not-for-x86.c"] },
+        x86_64: { srcs: ["for-x86_64.c"], exclude_srcs: ["not-for-x86_64.c"] },
+	},
+} `,
+			expectedBazelTargets: []string{`cc_library_static(
+    name = "foo_static",
+    copts = ["-I."],
+    linkstatic = True,
+    srcs = ["common.c"] + select({
+        "//build/bazel/platforms/arch:arm": [
+            "for-arm.c",
+            "not-for-arm64.c",
+            "not-for-x86.c",
+            "not-for-x86_64.c",
+        ],
+        "//build/bazel/platforms/arch:arm64": [
+            "for-arm64.c",
+            "not-for-arm.c",
+            "not-for-x86.c",
+            "not-for-x86_64.c",
+        ],
+        "//build/bazel/platforms/arch:x86": [
+            "for-x86.c",
+            "not-for-arm.c",
+            "not-for-arm64.c",
+            "not-for-x86_64.c",
+        ],
+        "//build/bazel/platforms/arch:x86_64": [
+            "for-x86_64.c",
+            "not-for-arm.c",
+            "not-for-arm64.c",
+            "not-for-x86.c",
+        ],
+        "//conditions:default": [
+            "not-for-arm.c",
+            "not-for-arm64.c",
+            "not-for-x86.c",
+            "not-for-x86_64.c",
+        ],
+    }),
+)`},
+		},
 	}
 
 	dir := "."
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index d00a1cb..9efdb53 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -67,11 +67,7 @@
         "-Iinclude",
         "-I.",
     ],
-    srcs = [
-        "a/b/c.c",
-        "a/b/bar.h",
-        "a/b/foo.h",
-    ],
+    srcs = ["a/b/c.c"],
 )`,
 			},
 		},
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index b9ffc04..52afb55 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -99,8 +99,15 @@
 		return "", nil
 	}
 
+	// addConditionsDefault := false
+	conditionsDefaultKey := bazel.PlatformArchMap[bazel.CONDITIONS_DEFAULT]
+
 	var selects string
 	for _, selectKey := range android.SortedStringKeys(selectMap) {
+		if selectKey == conditionsDefaultKey {
+			// Handle default condition later.
+			continue
+		}
 		value := selectMap[selectKey]
 		if isZero(value) {
 			// Ignore zero values to not generate empty lists.
@@ -125,8 +132,22 @@
 	// Create the map.
 	ret := "select({\n"
 	ret += selects
-	// default condition comes last.
-	ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue)
+
+	// Handle the default condition
+	s, err := prettyPrintSelectEntry(selectMap[conditionsDefaultKey], conditionsDefaultKey, indent)
+	if err != nil {
+		return "", err
+	}
+	if s == "" {
+		// Print an explicit empty list (the default value) even if the value is
+		// empty, to avoid errors about not finding a configuration that matches.
+		ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue)
+	} else {
+		// Print the custom default value.
+		ret += s
+		ret += ",\n"
+	}
+
 	ret += makeIndent(indent)
 	ret += "})"
 
diff --git a/cc/Android.bp b/cc/Android.bp
index cc4d9bc..c32cca8 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -93,6 +93,7 @@
         "prebuilt_test.go",
         "proto_test.go",
         "test_data_test.go",
+        "vendor_public_library_test.go",
         "vendor_snapshot_test.go",
     ],
     pluginFor: ["soong_build"],
diff --git a/cc/bp2build.go b/cc/bp2build.go
index efa2752..9c4bf6e5 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -80,7 +80,7 @@
 
 // bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes.
 func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Module) compilerAttributes {
-	var localHdrs, srcs bazel.LabelListAttribute
+	var srcs bazel.LabelListAttribute
 	var copts bazel.StringListAttribute
 
 	// Creates the -I flag for a directory, while making the directory relative
@@ -90,11 +90,6 @@
 		return "-I" + filepath.Join(ctx.ModuleDir(), dir)
 	}
 
-	// Parse the list of srcs, excluding files from exclude_srcs.
-	parseSrcs := func(baseCompilerProps *BaseCompilerProperties) bazel.LabelList {
-		return android.BazelLabelForModuleSrcExcludes(ctx, baseCompilerProps.Srcs, baseCompilerProps.Exclude_srcs)
-	}
-
 	// Parse the list of module-relative include directories (-I).
 	parseLocalIncludeDirs := func(baseCompilerProps *BaseCompilerProperties) []string {
 		// include_dirs are root-relative, not module-relative.
@@ -111,40 +106,85 @@
 		return copts
 	}
 
+	// baseSrcs contain the list of src files that are used for every configuration.
+	var baseSrcs []string
+	// baseExcludeSrcs contain the list of src files that are excluded for every configuration.
+	var baseExcludeSrcs []string
+	// baseSrcsLabelList is a clone of the base srcs LabelList, used for computing the
+	// arch or os specific srcs later.
+	var baseSrcsLabelList bazel.LabelList
+
+	// Parse srcs from an arch or OS's props value, taking the base srcs and
+	// exclude srcs into account.
+	parseSrcs := func(baseCompilerProps *BaseCompilerProperties) bazel.LabelList {
+		// Combine the base srcs and arch-specific srcs
+		allSrcs := append(baseSrcs, baseCompilerProps.Srcs...)
+		// Combine the base exclude_srcs and configuration-specific exclude_srcs
+		allExcludeSrcs := append(baseExcludeSrcs, baseCompilerProps.Exclude_srcs...)
+		return android.BazelLabelForModuleSrcExcludes(ctx, allSrcs, allExcludeSrcs)
+	}
+
 	for _, props := range module.compiler.compilerProps() {
 		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
 			srcs.Value = parseSrcs(baseCompilerProps)
 			copts.Value = parseCopts(baseCompilerProps)
+
+			// Used for arch-specific srcs later.
+			baseSrcs = baseCompilerProps.Srcs
+			baseExcludeSrcs = baseCompilerProps.Exclude_srcs
+			baseSrcsLabelList = parseSrcs(baseCompilerProps)
 			break
 		}
 	}
 
+	// Handle include_build_directory prop. If the property is true, then the
+	// target has access to all headers recursively in the package, and has
+	// "-I<module-dir>" in its copts.
 	if c, ok := module.compiler.(*baseCompiler); ok && c.includeBuildDirectory() {
 		copts.Value = append(copts.Value, includeFlag("."))
-		localHdrs.Value = bp2BuildListHeadersInDir(ctx, ".")
 	} else if c, ok := module.compiler.(*libraryDecorator); ok && c.includeBuildDirectory() {
 		copts.Value = append(copts.Value, includeFlag("."))
-		localHdrs.Value = bp2BuildListHeadersInDir(ctx, ".")
 	}
 
 	for arch, props := range module.GetArchProperties(&BaseCompilerProperties{}) {
 		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
-			srcsList := parseSrcs(baseCompilerProps)
-			srcs.SetValueForArch(arch.Name, bazel.SubtractBazelLabelList(srcsList, srcs.Value))
+			// If there's arch specific srcs or exclude_srcs, generate a select entry for it.
+			// TODO(b/186153868): do this for OS specific srcs and exclude_srcs too.
+			if len(baseCompilerProps.Srcs) > 0 || len(baseCompilerProps.Exclude_srcs) > 0 {
+				srcsList := parseSrcs(baseCompilerProps)
+				srcs.SetValueForArch(arch.Name, srcsList)
+				// The base srcs value should not contain any arch-specific excludes.
+				srcs.Value = bazel.SubtractBazelLabelList(srcs.Value, bazel.LabelList{Includes: srcsList.Excludes})
+			}
+
 			copts.SetValueForArch(arch.Name, parseCopts(baseCompilerProps))
 		}
 	}
 
-	for os, props := range module.GetTargetProperties(&BaseCompilerProperties{}) {
-		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
-			srcsList := parseSrcs(baseCompilerProps)
-			srcs.SetValueForOS(os.Name, bazel.SubtractBazelLabelList(srcsList, srcs.Value))
-			copts.SetValueForOS(os.Name, parseCopts(baseCompilerProps))
+	// After going through all archs, delete the duplicate files in the arch
+	// values that are already in the base srcs.Value.
+	for arch, props := range module.GetArchProperties(&BaseCompilerProperties{}) {
+		if _, ok := props.(*BaseCompilerProperties); ok {
+			srcs.SetValueForArch(arch.Name, bazel.SubtractBazelLabelList(srcs.GetValueForArch(arch.Name), srcs.Value))
 		}
 	}
 
-	// Combine local, non-exported hdrs into srcs
-	srcs.Append(localHdrs)
+	// Now that the srcs.Value list is finalized, compare it with the original
+	// list, and put the difference into the default condition for the arch
+	// select.
+	defaultsSrcs := bazel.SubtractBazelLabelList(baseSrcsLabelList, srcs.Value)
+	// TODO(b/186153868): handle the case with multiple variant types, e.g. when arch and os are both used.
+	srcs.SetValueForArch(bazel.CONDITIONS_DEFAULT, defaultsSrcs)
+
+	// Handle OS specific props.
+	for os, props := range module.GetTargetProperties(&BaseCompilerProperties{}) {
+		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+			srcsList := parseSrcs(baseCompilerProps)
+			// TODO(b/186153868): add support for os-specific srcs and exclude_srcs
+			srcs.SetValueForOS(os.Name, bazel.SubtractBazelLabelList(srcsList, baseSrcsLabelList))
+			copts.SetValueForOS(os.Name, parseCopts(baseCompilerProps))
+		}
+	}
 
 	return compilerAttributes{
 		srcs:  srcs,
@@ -207,11 +247,6 @@
 	}
 }
 
-func bp2BuildListHeadersInDir(ctx android.TopDownMutatorContext, includeDir string) bazel.LabelList {
-	globs := bazel.GlobsInDir(includeDir, true, headerExts)
-	return android.BazelLabelForModuleSrc(ctx, globs)
-}
-
 // Relativize a list of root-relative paths with respect to the module's
 // directory.
 //
@@ -236,9 +271,8 @@
 }
 
 // bp2BuildParseExportedIncludes creates a string list attribute contains the
-// exported included directories of a module, and a label list attribute
-// containing the exported headers of a module.
-func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) (bazel.StringListAttribute, bazel.LabelListAttribute) {
+// exported included directories of a module.
+func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) bazel.StringListAttribute {
 	libraryDecorator := module.linker.(*libraryDecorator)
 
 	// Export_system_include_dirs and export_include_dirs are already module dir
@@ -248,14 +282,6 @@
 	includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...)
 	includeDirsAttribute := bazel.MakeStringListAttribute(includeDirs)
 
-	var headersAttribute bazel.LabelListAttribute
-	var headers bazel.LabelList
-	for _, includeDir := range includeDirs {
-		headers.Append(bp2BuildListHeadersInDir(ctx, includeDir))
-	}
-	headers = bazel.UniqueBazelLabelList(headers)
-	headersAttribute.Value = headers
-
 	for arch, props := range module.GetArchProperties(&FlagExporterProperties{}) {
 		if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
 			archIncludeDirs := flagExporterProperties.Export_system_include_dirs
@@ -268,20 +294,6 @@
 			if len(archIncludeDirs) > 0 {
 				includeDirsAttribute.SetValueForArch(arch.Name, archIncludeDirs)
 			}
-
-			var archHeaders bazel.LabelList
-			for _, archIncludeDir := range archIncludeDirs {
-				archHeaders.Append(bp2BuildListHeadersInDir(ctx, archIncludeDir))
-			}
-			archHeaders = bazel.UniqueBazelLabelList(archHeaders)
-
-			// To avoid duplicate headers when base headers + arch headers are combined
-			// FIXME: This doesn't take conflicts between arch and os includes into account
-			archHeaders = bazel.SubtractBazelLabelList(archHeaders, headers)
-
-			if len(archHeaders.Includes) > 0 || len(archHeaders.Excludes) > 0 {
-				headersAttribute.SetValueForArch(arch.Name, archHeaders)
-			}
 		}
 	}
 
@@ -297,22 +309,8 @@
 			if len(osIncludeDirs) > 0 {
 				includeDirsAttribute.SetValueForOS(os.Name, osIncludeDirs)
 			}
-
-			var osHeaders bazel.LabelList
-			for _, osIncludeDir := range osIncludeDirs {
-				osHeaders.Append(bp2BuildListHeadersInDir(ctx, osIncludeDir))
-			}
-			osHeaders = bazel.UniqueBazelLabelList(osHeaders)
-
-			// To avoid duplicate headers when base headers + os headers are combined
-			// FIXME: This doesn't take conflicts between arch and os includes into account
-			osHeaders = bazel.SubtractBazelLabelList(osHeaders, headers)
-
-			if len(osHeaders.Includes) > 0 || len(osHeaders.Excludes) > 0 {
-				headersAttribute.SetValueForOS(os.Name, osHeaders)
-			}
 		}
 	}
 
-	return includeDirsAttribute, headersAttribute
+	return includeDirsAttribute
 }
diff --git a/cc/cc.go b/cc/cc.go
index 98df545..4d8f4e1 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1135,9 +1135,9 @@
 	return false
 }
 
-func (m *Module) HasLlndkStubs() bool {
+func (m *Module) NeedsLlndkVariants() bool {
 	lib := moduleLibraryInterface(m)
-	return lib != nil && lib.hasLLNDKStubs()
+	return lib != nil && (lib.hasLLNDKStubs() || lib.hasLLNDKHeaders())
 }
 
 // isImplementationForLLNDKPublic returns true for any variant of a cc_library that has LLNDK stubs
@@ -2070,8 +2070,6 @@
 					nonvariantLibs = append(nonvariantLibs, rewriteSnapshotLib(entry, getSnapshot().SharedLibs))
 				} else if ctx.useSdk() && inList(name, *getNDKKnownLibs(ctx.Config())) {
 					variantLibs = append(variantLibs, name+ndkLibrarySuffix)
-				} else if ctx.useVndk() {
-					nonvariantLibs = append(nonvariantLibs, rewriteSnapshotLib(entry, getSnapshot().SharedLibs))
 				} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, *vendorPublicLibraries) {
 					vendorPublicLib := name + vendorPublicLibrarySuffix
 					if actx.OtherModuleExists(vendorPublicLib) {
@@ -2082,6 +2080,8 @@
 						// link to the original library.
 						nonvariantLibs = append(nonvariantLibs, name)
 					}
+				} else if ctx.useVndk() {
+					nonvariantLibs = append(nonvariantLibs, rewriteSnapshotLib(entry, getSnapshot().SharedLibs))
 				} else {
 					// put name#version back
 					nonvariantLibs = append(nonvariantLibs, entry)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index c56643b..3d2160f 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -3236,72 +3236,6 @@
 	}
 }
 
-func TestVendorPublicLibraries(t *testing.T) {
-	ctx := testCc(t, `
-	cc_library_headers {
-		name: "libvendorpublic_headers",
-		export_include_dirs: ["my_include"],
-	}
-	vendor_public_library {
-		name: "libvendorpublic",
-		symbol_file: "",
-		export_public_headers: ["libvendorpublic_headers"],
-	}
-	cc_library {
-		name: "libvendorpublic",
-		srcs: ["foo.c"],
-		vendor: true,
-		no_libcrt: true,
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "libsystem",
-		shared_libs: ["libvendorpublic"],
-		vendor: false,
-		srcs: ["foo.c"],
-		no_libcrt: true,
-		nocrt: true,
-	}
-	cc_library {
-		name: "libvendor",
-		shared_libs: ["libvendorpublic"],
-		vendor: true,
-		srcs: ["foo.c"],
-		no_libcrt: true,
-		nocrt: true,
-	}
-	`)
-
-	coreVariant := "android_arm64_armv8-a_shared"
-	vendorVariant := "android_vendor.29_arm64_armv8-a_shared"
-
-	// test if header search paths are correctly added
-	// _static variant is used since _shared reuses *.o from the static variant
-	cc := ctx.ModuleForTests("libsystem", strings.Replace(coreVariant, "_shared", "_static", 1)).Rule("cc")
-	cflags := cc.Args["cFlags"]
-	if !strings.Contains(cflags, "-Imy_include") {
-		t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
-	}
-
-	// test if libsystem is linked to the stub
-	ld := ctx.ModuleForTests("libsystem", coreVariant).Rule("ld")
-	libflags := ld.Args["libFlags"]
-	stubPaths := getOutputPaths(ctx, coreVariant, []string{"libvendorpublic" + vendorPublicLibrarySuffix})
-	if !strings.Contains(libflags, stubPaths[0].String()) {
-		t.Errorf("libflags for libsystem must contain %#v, but was %#v", stubPaths[0], libflags)
-	}
-
-	// test if libvendor is linked to the real shared lib
-	ld = ctx.ModuleForTests("libvendor", vendorVariant).Rule("ld")
-	libflags = ld.Args["libFlags"]
-	stubPaths = getOutputPaths(ctx, vendorVariant, []string{"libvendorpublic"})
-	if !strings.Contains(libflags, stubPaths[0].String()) {
-		t.Errorf("libflags for libvendor must contain %#v, but was %#v", stubPaths[0], libflags)
-	}
-
-}
-
 func TestRecovery(t *testing.T) {
 	ctx := testCc(t, `
 		cc_library_shared {
diff --git a/cc/image.go b/cc/image.go
index c1e5dfe..6265b13 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -437,13 +437,13 @@
 		productVndkVersion = platformVndkVersion
 	}
 
-	if m.IsLlndkLibrary() || m.IsLlndkHeaders() || m.HasLlndkStubs() {
+	if m.IsLlndkLibrary() || m.IsLlndkHeaders() || m.NeedsLlndkVariants() {
 		// This is an LLNDK library.  The implementation of the library will be on /system,
 		// and vendor and product variants will be created with LLNDK stubs.
 		// The LLNDK libraries need vendor variants even if there is no VNDK.
 		// The obsolete llndk_library and llndk_headers modules also need the vendor variants
 		// so the cc_library LLNDK stubs can depend on them.
-		if m.HasLlndkStubs() {
+		if m.NeedsLlndkVariants() {
 			coreVariantNeeded = true
 		}
 		if platformVndkVersion != "" {
diff --git a/cc/library.go b/cc/library.go
index af92b24..3ac7e11 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -259,11 +259,10 @@
 
 	compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
 	linkerAttrs := bp2BuildParseLinkerProps(ctx, m)
-	exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, m)
+	exportedIncludes := bp2BuildParseExportedIncludes(ctx, m)
 
 	attrs := &bazelCcLibraryAttributes{
 		Srcs:     compilerAttrs.srcs,
-		Hdrs:     exportedIncludesHeaders,
 		Copts:    compilerAttrs.copts,
 		Linkopts: linkerAttrs.linkopts,
 		Deps:     linkerAttrs.deps,
@@ -869,6 +868,7 @@
 
 	implementationModuleName(name string) string
 	hasLLNDKStubs() bool
+	hasLLNDKHeaders() bool
 }
 
 var _ libraryInterface = (*libraryDecorator)(nil)
@@ -1683,6 +1683,12 @@
 	return String(library.Properties.Llndk_stubs) != ""
 }
 
+// hasLLNDKHeaders returns true if this cc_library module has a variant that provides headers
+// to a module that sets llndk.symbol_file.
+func (library *libraryDecorator) hasLLNDKHeaders() bool {
+	return Bool(library.Properties.Llndk.Llndk_headers)
+}
+
 func (library *libraryDecorator) implementationModuleName(name string) string {
 	return name
 }
@@ -2176,7 +2182,7 @@
 
 	compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
 	linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
-	exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, module)
+	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
 
 	attrs := &bazelCcLibraryStaticAttributes{
 		Copts:      compilerAttrs.copts,
@@ -2184,7 +2190,6 @@
 		Deps:       linkerAttrs.deps,
 		Linkstatic: true,
 		Includes:   exportedIncludes,
-		Hdrs:       exportedIncludesHeaders,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
diff --git a/cc/library_headers.go b/cc/library_headers.go
index f2cb52b..0aba8de 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -142,14 +142,13 @@
 		return
 	}
 
-	exportedIncludes, exportedHdrs := bp2BuildParseExportedIncludes(ctx, module)
+	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
 	compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
 	linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
 
 	attrs := &bazelCcLibraryHeadersAttributes{
 		Copts:    compilerAttrs.copts,
 		Includes: exportedIncludes,
-		Hdrs:     exportedHdrs,
 		Deps:     linkerAttrs.deps,
 	}
 
diff --git a/cc/linkable.go b/cc/linkable.go
index 2fa12f6..8fe0b4a 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -112,8 +112,8 @@
 	// IsLlndkLibrary returns true if this module is an LLNDK library module.
 	IsLlndkLibrary() bool
 
-	// HasLlndkStubs returns true if this module has LLNDK stubs.
-	HasLlndkStubs() bool
+	// NeedsLlndkVariants returns true if this module has LLNDK stubs or provides LLNDK headers.
+	NeedsLlndkVariants() bool
 
 	UseVndk() bool
 	MustUseVendorVariant() bool
diff --git a/cc/linker.go b/cc/linker.go
index ae33356..73fc4f0 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -322,7 +322,7 @@
 
 	if ctx.toolchain().Bionic() {
 		// libclang_rt.builtins has to be last on the command line
-		if !Bool(linker.Properties.No_libcrt) {
+		if !Bool(linker.Properties.No_libcrt) && !ctx.header() {
 			deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
 		}
 
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index d05dbce..ad19e47 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -69,6 +69,10 @@
 	// vendor nor product libraries. This effectively hides this module from
 	// non-system modules. Default value is false.
 	Private *bool
+
+	// if true, make this module available to provide headers to other modules that set
+	// llndk.symbol_file.
+	Llndk_headers *bool
 }
 
 type llndkStubDecorator struct {
diff --git a/cc/stl.go b/cc/stl.go
index 4f8865f..75921c6 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -62,6 +62,8 @@
 		s := ""
 		if stl.Properties.Stl != nil {
 			s = *stl.Properties.Stl
+		} else if ctx.header() {
+			s = "none"
 		}
 		if ctx.useSdk() && ctx.Device() {
 			switch s {
diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go
index 85f514c..394e322 100644
--- a/cc/vendor_public_library.go
+++ b/cc/vendor_public_library.go
@@ -155,6 +155,7 @@
 
 	module.AddProperties(
 		&stub.Properties,
+		&module.VendorProperties,
 		&library.MutatedProperties,
 		&library.flagExporter.Properties)
 
diff --git a/cc/vendor_public_library_test.go b/cc/vendor_public_library_test.go
new file mode 100644
index 0000000..9f2accf
--- /dev/null
+++ b/cc/vendor_public_library_test.go
@@ -0,0 +1,104 @@
+// 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 (
+	"strings"
+	"testing"
+)
+
+func TestVendorPublicLibraries(t *testing.T) {
+	ctx := testCc(t, `
+	cc_library_headers {
+		name: "libvendorpublic_headers",
+		product_available: true,
+		export_include_dirs: ["my_include"],
+	}
+	vendor_public_library {
+		name: "libvendorpublic",
+		product_available: true,
+		symbol_file: "",
+		export_public_headers: ["libvendorpublic_headers"],
+	}
+	cc_library {
+		name: "libvendorpublic",
+		srcs: ["foo.c"],
+		vendor: true,
+		no_libcrt: true,
+		nocrt: true,
+	}
+
+	cc_library {
+		name: "libsystem",
+		shared_libs: ["libvendorpublic"],
+		vendor: false,
+		srcs: ["foo.c"],
+		no_libcrt: true,
+		nocrt: true,
+	}
+	cc_library {
+		name: "libproduct",
+		shared_libs: ["libvendorpublic"],
+		product_specific: true,
+		srcs: ["foo.c"],
+		no_libcrt: true,
+		nocrt: true,
+	}
+	cc_library {
+		name: "libvendor",
+		shared_libs: ["libvendorpublic"],
+		vendor: true,
+		srcs: ["foo.c"],
+		no_libcrt: true,
+		nocrt: true,
+	}
+	`)
+
+	coreVariant := "android_arm64_armv8-a_shared"
+	vendorVariant := "android_vendor.29_arm64_armv8-a_shared"
+	productVariant := "android_product.29_arm64_armv8-a_shared"
+
+	// test if header search paths are correctly added
+	// _static variant is used since _shared reuses *.o from the static variant
+	cc := ctx.ModuleForTests("libsystem", strings.Replace(coreVariant, "_shared", "_static", 1)).Rule("cc")
+	cflags := cc.Args["cFlags"]
+	if !strings.Contains(cflags, "-Imy_include") {
+		t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
+	}
+
+	// test if libsystem is linked to the stub
+	ld := ctx.ModuleForTests("libsystem", coreVariant).Rule("ld")
+	libflags := ld.Args["libFlags"]
+	stubPaths := getOutputPaths(ctx, coreVariant, []string{"libvendorpublic" + vendorPublicLibrarySuffix})
+	if !strings.Contains(libflags, stubPaths[0].String()) {
+		t.Errorf("libflags for libsystem must contain %#v, but was %#v", stubPaths[0], libflags)
+	}
+
+	// test if libsystem is linked to the stub
+	ld = ctx.ModuleForTests("libproduct", productVariant).Rule("ld")
+	libflags = ld.Args["libFlags"]
+	stubPaths = getOutputPaths(ctx, productVariant, []string{"libvendorpublic" + vendorPublicLibrarySuffix})
+	if !strings.Contains(libflags, stubPaths[0].String()) {
+		t.Errorf("libflags for libproduct must contain %#v, but was %#v", stubPaths[0], libflags)
+	}
+
+	// test if libvendor is linked to the real shared lib
+	ld = ctx.ModuleForTests("libvendor", vendorVariant).Rule("ld")
+	libflags = ld.Args["libFlags"]
+	stubPaths = getOutputPaths(ctx, vendorVariant, []string{"libvendorpublic"})
+	if !strings.Contains(libflags, stubPaths[0].String()) {
+		t.Errorf("libflags for libvendor must contain %#v, but was %#v", stubPaths[0], libflags)
+	}
+}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index a94e7af..8a656ed 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -131,7 +131,6 @@
 	ClassLoaderContexts            ClassLoaderContextMap
 
 	Archs                   []android.ArchType
-	DexPreoptImages         android.Paths
 	DexPreoptImagesDeps     []android.OutputPaths
 	DexPreoptImageLocations []string
 
@@ -276,7 +275,6 @@
 	EnforceUsesLibrariesStatusFile string
 	ClassLoaderContexts            jsonClassLoaderContextMap
 
-	DexPreoptImages     []string
 	DexPreoptImagesDeps [][]string
 
 	PreoptBootClassPathDexFiles []string
@@ -302,11 +300,10 @@
 	config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing))
 	config.ModuleConfig.EnforceUsesLibrariesStatusFile = constructPath(ctx, config.EnforceUsesLibrariesStatusFile)
 	config.ModuleConfig.ClassLoaderContexts = fromJsonClassLoaderContext(ctx, config.ClassLoaderContexts)
-	config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages)
 	config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles)
 
 	// This needs to exist, but dependencies are already handled in Make, so we don't need to pass them through JSON.
-	config.ModuleConfig.DexPreoptImagesDeps = make([]android.OutputPaths, len(config.ModuleConfig.DexPreoptImages))
+	config.ModuleConfig.DexPreoptImagesDeps = make([]android.OutputPaths, len(config.ModuleConfig.Archs))
 
 	return config.ModuleConfig, nil
 }
@@ -328,7 +325,6 @@
 		ProfileBootListing:             config.ProfileBootListing.String(),
 		EnforceUsesLibrariesStatusFile: config.EnforceUsesLibrariesStatusFile.String(),
 		ClassLoaderContexts:            toJsonClassLoaderContext(config.ClassLoaderContexts),
-		DexPreoptImages:                config.DexPreoptImages.Strings(),
 		DexPreoptImagesDeps:            pathsListToStringLists(config.DexPreoptImagesDeps),
 		PreoptBootClassPathDexFiles:    config.PreoptBootClassPathDexFiles.Strings(),
 		ModuleConfig:                   config,
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index cd7551c..bb4e80e 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -47,7 +47,6 @@
 		EnforceUsesLibraries:            false,
 		ClassLoaderContexts:             nil,
 		Archs:                           []android.ArchType{android.Arm},
-		DexPreoptImages:                 android.Paths{android.PathForTesting("system/framework/arm/boot.art")},
 		DexPreoptImagesDeps:             []android.OutputPaths{android.OutputPaths{}},
 		DexPreoptImageLocations:         []string{},
 		PreoptBootClassPathDexFiles:     nil,
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index 6ca0f75..c16193d 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -15,9 +15,8 @@
 package java
 
 import (
-	"fmt"
-
 	"android/soong/android"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -116,15 +115,7 @@
 // reportMissingVariationDependency intentionally adds a dependency on a missing variation in order
 // to generate an appropriate error message with information about the available variations.
 func reportMissingVariationDependency(ctx android.BottomUpMutatorContext, variations []blueprint.Variation, name string) {
-	modules := ctx.AddFarVariationDependencies(variations, nil, name)
-	if len(modules) != 1 {
-		panic(fmt.Errorf("Internal Error: expected one module, found %d", len(modules)))
-		return
-	}
-	if modules[0] != nil {
-		panic(fmt.Errorf("Internal Error: expected module to be missing but was found: %q", modules[0]))
-		return
-	}
+	ctx.AddFarVariationDependencies(variations, nil, name)
 }
 
 // ApexVariantReference specifies a particular apex variant of a module.
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 8bb5cb1..2e33c06 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"path/filepath"
+	"reflect"
 	"strings"
 
 	"android/soong/android"
@@ -31,8 +32,9 @@
 
 	android.RegisterSdkMemberType(&bootclasspathFragmentMemberType{
 		SdkMemberTypeBase: android.SdkMemberTypeBase{
-			PropertyName: "bootclasspath_fragments",
-			SupportsSdk:  true,
+			PropertyName:         "bootclasspath_fragments",
+			SupportsSdk:          true,
+			TransitiveSdkMembers: true,
 		},
 	})
 }
@@ -59,11 +61,22 @@
 	return false
 }
 
+// SdkMemberType causes dependencies added with this tag to be automatically added to the sdk as if
+// they were specified using java_boot_libs.
+func (b bootclasspathFragmentContentDependencyTag) SdkMemberType() android.SdkMemberType {
+	return javaBootLibsSdkMemberType
+}
+
+func (b bootclasspathFragmentContentDependencyTag) ExportMember() bool {
+	return true
+}
+
 // The tag used for the dependency between the bootclasspath_fragment module and its contents.
 var bootclasspathFragmentContentDepTag = bootclasspathFragmentContentDependencyTag{}
 
 var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathFragmentContentDepTag
 var _ android.ReplaceSourceWithPrebuilt = bootclasspathFragmentContentDepTag
+var _ android.SdkMemberTypeDependencyTag = bootclasspathFragmentContentDepTag
 
 func IsBootclasspathFragmentContentDepTag(tag blueprint.DependencyTag) bool {
 	return tag == bootclasspathFragmentContentDepTag
@@ -128,8 +141,10 @@
 	if m.properties.Image_name == nil && len(contents) == 0 {
 		ctx.ModuleErrorf(`neither of the "image_name" and "contents" properties have been supplied, please supply exactly one`)
 	}
-	if m.properties.Image_name != nil && len(contents) != 0 {
-		ctx.ModuleErrorf(`both of the "image_name" and "contents" properties have been supplied, please supply exactly one`)
+
+	if len(contents) != 0 {
+		// Nothing to do.
+		return
 	}
 
 	imageName := proptools.String(m.properties.Image_name)
@@ -154,7 +169,6 @@
 
 		// Make sure that the apex specified in the configuration is consistent and is one for which
 		// this boot image is available.
-		jars := []string{}
 		commonApex := ""
 		for i := 0; i < modules.Len(); i++ {
 			apex := modules.Apex(i)
@@ -174,11 +188,50 @@
 				ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q",
 					commonApex, apex)
 			}
-			jars = append(jars, jar)
 		}
 
 		// Store the jars in the Contents property so that they can be used to add dependencies.
-		m.properties.Contents = jars
+		m.properties.Contents = modules.CopyOfJars()
+	}
+}
+
+// bootclasspathImageNameContentsConsistencyCheck checks that the configuration that applies to this
+// module (if any) matches the contents.
+//
+// This should be a noop as if image_name="art" then the contents will be set from the ArtApexJars
+// config by bootclasspathFragmentInitContentsFromImage so it will be guaranteed to match. However,
+// in future this will not be the case.
+func (b *BootclasspathFragmentModule) bootclasspathImageNameContentsConsistencyCheck(ctx android.BaseModuleContext) {
+	imageName := proptools.String(b.properties.Image_name)
+	if imageName == "art" {
+		// TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property.
+		if b.MemberName() != "" {
+			// The module is a versioned prebuilt so ignore it. This is done for a couple of reasons:
+			// 1. There is no way to use this at the moment so ignoring it is safe.
+			// 2. Attempting to initialize the contents property from the configuration will end up having
+			//    the versioned prebuilt depending on the unversioned prebuilt. That will cause problems
+			//    as the unversioned prebuilt could end up with an APEX variant created for the source
+			//    APEX which will prevent it from having an APEX variant for the prebuilt APEX which in
+			//    turn will prevent it from accessing the dex implementation jar from that which will
+			//    break hidden API processing, amongst others.
+			return
+		}
+
+		// Get the configuration for the art apex jars.
+		modules := b.getImageConfig(ctx).modules
+		configuredJars := modules.CopyOfJars()
+
+		// Skip the check if the configured jars list is empty as that is a common configuration when
+		// building targets that do not result in a system image.
+		if len(configuredJars) == 0 {
+			return
+		}
+
+		contents := b.properties.Contents
+		if !reflect.DeepEqual(configuredJars, contents) {
+			ctx.ModuleErrorf("inconsistency in specification of contents. ArtApexJars configuration specifies %#v, contents property specifies %#v",
+				configuredJars, contents)
+		}
 	}
 }
 
@@ -274,6 +327,13 @@
 }
 
 func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Only perform a consistency check if this module is the active module. That will prevent an
+	// unused prebuilt that was created without instrumentation from breaking an instrumentation
+	// build.
+	if isActiveModule(ctx.Module()) {
+		b.bootclasspathImageNameContentsConsistencyCheck(ctx)
+	}
+
 	// Perform hidden API processing.
 	b.generateHiddenAPIBuildActions(ctx)
 
@@ -368,12 +428,7 @@
 	module := variant.(*BootclasspathFragmentModule)
 
 	b.Image_name = module.properties.Image_name
-	if b.Image_name == nil {
-		// Only one of image_name or contents can be specified. However, if image_name is set then the
-		// contents property is updated to match the configuration used to create the corresponding
-		// boot image. Therefore, contents property is only copied if the image name is not specified.
-		b.Contents = module.properties.Contents
-	}
+	b.Contents = module.properties.Contents
 
 	// Get the flag file information from the module.
 	mctx := ctx.SdkModuleContext()
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 0db9361..0419a46 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -113,19 +113,6 @@
 		`)
 }
 
-func TestBootclasspathFragmentWithImageNameAndContents(t *testing.T) {
-	prepareForTestWithBootclasspathFragment.
-		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
-			`\Qboth of the "image_name" and "contents" properties\E`)).
-		RunTestWithBp(t, `
-			bootclasspath_fragment {
-				name: "bootclasspath-fragment",
-				image_name: "boot",
-				contents: ["other"],
-			}
-		`)
-}
-
 func TestBootclasspathFragment_Coverage(t *testing.T) {
 	prepareForTestWithFrameworkCoverage := android.FixtureMergeEnv(map[string]string{
 		"EMMA_INSTRUMENT":           "true",
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index d00d74b..0020a2d 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -225,7 +225,6 @@
 		ClassLoaderContexts:            d.classLoaderContexts,
 
 		Archs:                   archs,
-		DexPreoptImages:         images,
 		DexPreoptImagesDeps:     imagesDeps,
 		DexPreoptImageLocations: imageLocations,
 
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index f85e1c9..e3b5487 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -434,10 +434,21 @@
 		return
 	}
 
-	// Always create the default boot image first, to get a unique profile rule for all images.
-	d.defaultBootImage = buildBootImage(ctx, defaultBootImageConfig(ctx))
+	// Generate the profile rule from the default boot image.
+	defaultImageConfig := defaultBootImageConfig(ctx)
+	profile := bootImageProfileRule(ctx, defaultImageConfig)
+
+	// Generate the framework profile rule
+	bootFrameworkProfileRule(ctx, defaultImageConfig)
+
+	// Generate the updatable bootclasspath packages rule.
+	updatableBcpPackagesRule(ctx, defaultImageConfig)
+
+	// Create the default boot image.
+	d.defaultBootImage = buildBootImage(ctx, defaultImageConfig, profile)
+
 	// Create boot image for the ART apex (build artifacts are accessed via the global boot image config).
-	d.otherImages = append(d.otherImages, buildBootImage(ctx, artBootImageConfig(ctx)))
+	d.otherImages = append(d.otherImages, buildBootImage(ctx, artBootImageConfig(ctx), profile))
 
 	copyUpdatableBootJars(ctx)
 
@@ -549,7 +560,7 @@
 // Generate commands that will copy boot jars to predefined paths in the global config.
 func findAndCopyBootJars(ctx android.SingletonContext, bootjars android.ConfiguredJarList,
 	jarPathsPredefined android.WritablePaths,
-	getBootJar func(module android.Module) (int, android.Path)) []string {
+	getBootJar func(module android.Module) (int, android.Path)) {
 
 	// This logic is tested in the apex package to avoid import cycle apex <-> java.
 	jarPaths := make(android.Paths, bootjars.Len())
@@ -568,51 +579,52 @@
 		}
 	})
 
-	var missingDeps []string
-	// Ensure all modules were converted to paths
-	for i := range jarPaths {
-		if jarPaths[i] == nil {
-			m := bootjars.Jar(i)
-			if ctx.Config().AllowMissingDependencies() {
-				missingDeps = append(missingDeps, m)
-				jarPaths[i] = android.PathForOutput(ctx, "missing/module", m, "from/apex",
-					bootjars.Apex(i))
-			} else {
-				ctx.Errorf("failed to find a dex jar path for module '%s'"+
-					", note that some jars may be filtered out by module constraints", m)
-			}
-		}
-	}
-
 	// The paths to bootclasspath DEX files need to be known at module GenerateAndroidBuildAction
 	// time, before the boot images are built (these paths are used in dexpreopt rule generation for
 	// Java libraries and apps). Generate rules that copy bootclasspath DEX jars to the predefined
 	// paths.
 	for i := range jarPaths {
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   android.Cp,
-			Input:  jarPaths[i],
-			Output: jarPathsPredefined[i],
-		})
-	}
+		input := jarPaths[i]
+		output := jarPathsPredefined[i]
+		module := bootjars.Jar(i)
+		if input == nil {
+			if ctx.Config().AllowMissingDependencies() {
+				apex := bootjars.Apex(i)
 
-	return missingDeps
+				// 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: output,
+					Args: map[string]string{
+						"error": fmt.Sprintf("missing dependencies: dex jar for %s:%s", module, apex),
+					},
+				})
+			} else {
+				ctx.Errorf("failed to find a dex jar path for module '%s'"+
+					", note that some jars may be filtered out by module constraints", module)
+			}
+
+		} else {
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   android.Cp,
+				Input:  input,
+				Output: output,
+			})
+		}
+	}
 }
 
 // buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
-func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
+func buildBootImage(ctx android.SingletonContext, image *bootImageConfig, profile android.WritablePath) *bootImageConfig {
 	getBootJarFunc := func(module android.Module) (int, android.Path) {
 		return getBootImageJar(ctx, image, module)
 	}
-	missingDeps := findAndCopyBootJars(ctx, image.modules, image.dexPaths, getBootJarFunc)
-
-	profile := bootImageProfileRule(ctx, image, missingDeps)
-	bootFrameworkProfileRule(ctx, image, missingDeps)
-	updatableBcpPackagesRule(ctx, image, missingDeps)
+	findAndCopyBootJars(ctx, image.modules, image.dexPaths, getBootJarFunc)
 
 	var zipFiles android.Paths
 	for _, variant := range image.variants {
-		files := buildBootImageVariant(ctx, variant, profile, missingDeps)
+		files := buildBootImageVariant(ctx, variant, profile)
 		if variant.target.Os == android.Android {
 			zipFiles = append(zipFiles, files.Paths()...)
 		}
@@ -639,17 +651,11 @@
 		index, jar, _ := getBootJar(ctx, config.modules, module, "configured in updatable boot jars ")
 		return index, jar
 	}
-	missingDeps := findAndCopyBootJars(ctx, config.modules, config.dexPaths, getBootJarFunc)
-	// Ignoring missing dependencies here. Ideally they should be added to the dexpreopt rule, but
-	// that is not possible as this rule is created after dexpreopt rules (it's in a singleton
-	// context, and they are in a module context). The true fix is to add dependencies from the
-	// dexpreopted modules on updatable boot jars and avoid this copying altogether.
-	_ = missingDeps
+	findAndCopyBootJars(ctx, config.modules, config.dexPaths, getBootJarFunc)
 }
 
 // Generate boot image build rules for a specific target.
-func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant,
-	profile android.Path, missingDeps []string) android.WritablePaths {
+func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant, profile android.Path) android.WritablePaths {
 
 	globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
 	global := dexpreopt.GetGlobalConfig(ctx)
@@ -664,7 +670,6 @@
 	imagePath := outputPath.ReplaceExtension(ctx, "art")
 
 	rule := android.NewRuleBuilder(pctx, ctx)
-	rule.MissingDeps(missingDeps)
 
 	rule.Command().Text("mkdir").Flag("-p").Flag(symbolsDir.String())
 	rule.Command().Text("rm").Flag("-f").
@@ -800,159 +805,143 @@
 It is likely that the boot classpath is inconsistent.
 Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.`
 
-func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath {
+func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig) android.WritablePath {
 	globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
 	global := dexpreopt.GetGlobalConfig(ctx)
 
 	if global.DisableGenerateProfile {
 		return nil
 	}
-	profile := ctx.Config().Once(bootImageProfileRuleKey, func() interface{} {
-		defaultProfile := "frameworks/base/config/boot-image-profile.txt"
 
-		rule := android.NewRuleBuilder(pctx, ctx)
-		rule.MissingDeps(missingDeps)
+	defaultProfile := "frameworks/base/config/boot-image-profile.txt"
 
-		var bootImageProfile android.Path
-		if len(global.BootImageProfiles) > 1 {
-			combinedBootImageProfile := image.dir.Join(ctx, "boot-image-profile.txt")
-			rule.Command().Text("cat").Inputs(global.BootImageProfiles).Text(">").Output(combinedBootImageProfile)
-			bootImageProfile = combinedBootImageProfile
-		} else if len(global.BootImageProfiles) == 1 {
-			bootImageProfile = global.BootImageProfiles[0]
-		} else if path := android.ExistentPathForSource(ctx, defaultProfile); path.Valid() {
-			bootImageProfile = path.Path()
-		} else {
-			// No profile (not even a default one, which is the case on some branches
-			// like master-art-host that don't have frameworks/base).
-			// Return nil and continue without profile.
-			return nil
-		}
+	rule := android.NewRuleBuilder(pctx, ctx)
 
-		profile := image.dir.Join(ctx, "boot.prof")
-
-		rule.Command().
-			Text(`ANDROID_LOG_TAGS="*:e"`).
-			Tool(globalSoong.Profman).
-			Flag("--output-profile-type=boot").
-			FlagWithInput("--create-profile-from=", bootImageProfile).
-			FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
-			FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
-			FlagWithOutput("--reference-profile-file=", profile)
-
-		rule.Install(profile, "/system/etc/boot-image.prof")
-
-		rule.Build("bootJarsProfile", "profile boot jars")
-
-		image.profileInstalls = rule.Installs()
-
-		return profile
-	})
-	if profile == nil {
-		return nil // wrap nil into a typed pointer with value nil
+	var bootImageProfile android.Path
+	if len(global.BootImageProfiles) > 1 {
+		combinedBootImageProfile := image.dir.Join(ctx, "boot-image-profile.txt")
+		rule.Command().Text("cat").Inputs(global.BootImageProfiles).Text(">").Output(combinedBootImageProfile)
+		bootImageProfile = combinedBootImageProfile
+	} else if len(global.BootImageProfiles) == 1 {
+		bootImageProfile = global.BootImageProfiles[0]
+	} else if path := android.ExistentPathForSource(ctx, defaultProfile); path.Valid() {
+		bootImageProfile = path.Path()
+	} else {
+		// No profile (not even a default one, which is the case on some branches
+		// like master-art-host that don't have frameworks/base).
+		// Return nil and continue without profile.
+		return nil
 	}
-	return profile.(android.WritablePath)
+
+	profile := image.dir.Join(ctx, "boot.prof")
+
+	rule.Command().
+		Text(`ANDROID_LOG_TAGS="*:e"`).
+		Tool(globalSoong.Profman).
+		Flag("--output-profile-type=boot").
+		FlagWithInput("--create-profile-from=", bootImageProfile).
+		FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
+		FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
+		FlagWithOutput("--reference-profile-file=", profile)
+
+	rule.Install(profile, "/system/etc/boot-image.prof")
+
+	rule.Build("bootJarsProfile", "profile boot jars")
+
+	image.profileInstalls = rule.Installs()
+
+	return profile
 }
 
-var bootImageProfileRuleKey = android.NewOnceKey("bootImageProfileRule")
-
-func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath {
+func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConfig) android.WritablePath {
 	globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
 	global := dexpreopt.GetGlobalConfig(ctx)
 
 	if global.DisableGenerateProfile || ctx.Config().UnbundledBuild() {
 		return nil
 	}
-	return ctx.Config().Once(bootFrameworkProfileRuleKey, func() interface{} {
-		rule := android.NewRuleBuilder(pctx, ctx)
-		rule.MissingDeps(missingDeps)
 
-		// Some branches like master-art-host don't have frameworks/base, so manually
-		// handle the case that the default is missing.  Those branches won't attempt to build the profile rule,
-		// and if they do they'll get a missing deps error.
-		defaultProfile := "frameworks/base/config/boot-profile.txt"
-		path := android.ExistentPathForSource(ctx, defaultProfile)
-		var bootFrameworkProfile android.Path
-		if path.Valid() {
-			bootFrameworkProfile = path.Path()
-		} else {
-			missingDeps = append(missingDeps, defaultProfile)
-			bootFrameworkProfile = android.PathForOutput(ctx, "missing", defaultProfile)
-		}
+	// Some branches like master-art-host don't have frameworks/base, so manually
+	// handle the case that the default is missing.  Those branches won't attempt to build the profile rule,
+	// and if they do they'll get a missing deps error.
+	defaultProfile := "frameworks/base/config/boot-profile.txt"
+	path := android.ExistentPathForSource(ctx, defaultProfile)
+	var bootFrameworkProfile android.Path
+	var missingDeps []string
+	if path.Valid() {
+		bootFrameworkProfile = path.Path()
+	} else {
+		missingDeps = append(missingDeps, defaultProfile)
+		bootFrameworkProfile = android.PathForOutput(ctx, "missing", defaultProfile)
+	}
 
-		profile := image.dir.Join(ctx, "boot.bprof")
+	profile := image.dir.Join(ctx, "boot.bprof")
 
-		rule.Command().
-			Text(`ANDROID_LOG_TAGS="*:e"`).
-			Tool(globalSoong.Profman).
-			Flag("--output-profile-type=bprof").
-			FlagWithInput("--create-profile-from=", bootFrameworkProfile).
-			FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
-			FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
-			FlagWithOutput("--reference-profile-file=", profile)
+	rule := android.NewRuleBuilder(pctx, ctx)
+	rule.MissingDeps(missingDeps)
+	rule.Command().
+		Text(`ANDROID_LOG_TAGS="*:e"`).
+		Tool(globalSoong.Profman).
+		Flag("--output-profile-type=bprof").
+		FlagWithInput("--create-profile-from=", bootFrameworkProfile).
+		FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
+		FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
+		FlagWithOutput("--reference-profile-file=", profile)
 
-		rule.Install(profile, "/system/etc/boot-image.bprof")
-		rule.Build("bootFrameworkProfile", "profile boot framework jars")
-		image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
+	rule.Install(profile, "/system/etc/boot-image.bprof")
+	rule.Build("bootFrameworkProfile", "profile boot framework jars")
+	image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
 
-		return profile
-	}).(android.WritablePath)
+	return profile
 }
 
-var bootFrameworkProfileRuleKey = android.NewOnceKey("bootFrameworkProfileRule")
-
-func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath {
+func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig) android.WritablePath {
 	if ctx.Config().UnbundledBuild() {
 		return nil
 	}
 
-	return ctx.Config().Once(updatableBcpPackagesRuleKey, func() interface{} {
-		global := dexpreopt.GetGlobalConfig(ctx)
-		updatableModules := global.UpdatableBootJars.CopyOfJars()
+	global := dexpreopt.GetGlobalConfig(ctx)
+	updatableModules := global.UpdatableBootJars.CopyOfJars()
 
-		// Collect `permitted_packages` for updatable boot jars.
-		var updatablePackages []string
-		ctx.VisitAllModules(func(module android.Module) {
-			if !isActiveModule(module) {
-				return
-			}
-			if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok {
-				name := ctx.ModuleName(module)
-				if i := android.IndexList(name, updatableModules); i != -1 {
-					pp := j.PermittedPackagesForUpdatableBootJars()
-					if len(pp) > 0 {
-						updatablePackages = append(updatablePackages, pp...)
-					} else {
-						ctx.Errorf("Missing permitted_packages for %s", name)
-					}
-					// Do not match the same library repeatedly.
-					updatableModules = append(updatableModules[:i], updatableModules[i+1:]...)
+	// Collect `permitted_packages` for updatable boot jars.
+	var updatablePackages []string
+	ctx.VisitAllModules(func(module android.Module) {
+		if !isActiveModule(module) {
+			return
+		}
+		if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok {
+			name := ctx.ModuleName(module)
+			if i := android.IndexList(name, updatableModules); i != -1 {
+				pp := j.PermittedPackagesForUpdatableBootJars()
+				if len(pp) > 0 {
+					updatablePackages = append(updatablePackages, pp...)
+				} else {
+					ctx.Errorf("Missing permitted_packages for %s", name)
 				}
+				// Do not match the same library repeatedly.
+				updatableModules = append(updatableModules[:i], updatableModules[i+1:]...)
 			}
-		})
+		}
+	})
 
-		// Sort updatable packages to ensure deterministic ordering.
-		sort.Strings(updatablePackages)
+	// Sort updatable packages to ensure deterministic ordering.
+	sort.Strings(updatablePackages)
 
-		updatableBcpPackagesName := "updatable-bcp-packages.txt"
-		updatableBcpPackages := image.dir.Join(ctx, updatableBcpPackagesName)
+	updatableBcpPackagesName := "updatable-bcp-packages.txt"
+	updatableBcpPackages := image.dir.Join(ctx, updatableBcpPackagesName)
 
-		// WriteFileRule automatically adds the last end-of-line.
-		android.WriteFileRule(ctx, updatableBcpPackages, strings.Join(updatablePackages, "\n"))
+	// WriteFileRule automatically adds the last end-of-line.
+	android.WriteFileRule(ctx, updatableBcpPackages, strings.Join(updatablePackages, "\n"))
 
-		rule := android.NewRuleBuilder(pctx, ctx)
-		rule.MissingDeps(missingDeps)
-		rule.Install(updatableBcpPackages, "/system/etc/"+updatableBcpPackagesName)
-		// TODO: Rename `profileInstalls` to `extraInstalls`?
-		// Maybe even move the field out of the bootImageConfig into some higher level type?
-		image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
+	rule := android.NewRuleBuilder(pctx, ctx)
+	rule.Install(updatableBcpPackages, "/system/etc/"+updatableBcpPackagesName)
+	// TODO: Rename `profileInstalls` to `extraInstalls`?
+	// Maybe even move the field out of the bootImageConfig into some higher level type?
+	image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
 
-		return updatableBcpPackages
-	}).(android.WritablePath)
+	return updatableBcpPackages
 }
 
-var updatableBcpPackagesRuleKey = android.NewOnceKey("updatableBcpPackagesRule")
-
 func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) {
 	var allPhonies android.Paths
 	for _, image := range image.variants {
diff --git a/rust/rust.go b/rust/rust.go
index 78a793d..e1a69c0 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -274,7 +274,7 @@
 	return false
 }
 
-func (m *Module) HasLlndkStubs() bool {
+func (m *Module) NeedsLlndkVariants() bool {
 	return false
 }
 
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index ef4d7cd..dcdf852 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -52,7 +52,6 @@
 			sdk {
 				name: "mysdk",
 				bootclasspath_fragments: ["mybootclasspathfragment"],
-				java_boot_libs: ["mybootlib"],
 			}
 
 			apex {
@@ -114,6 +113,7 @@
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
     image_name: "art",
+    contents: ["mybootlib"],
 }
 
 java_import {
@@ -133,6 +133,7 @@
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
     image_name: "art",
+    contents: ["mysdk_mybootlib@current"],
 }
 
 java_import {
@@ -166,7 +167,6 @@
 			sdk {
 				name: "mysdk",
 				bootclasspath_fragments: ["mybootclasspathfragment"],
-				java_boot_libs: ["mybootlib"],
 			}
 
 			bootclasspath_fragment {
@@ -288,7 +288,6 @@
 			sdk {
 				name: "mysdk",
 				bootclasspath_fragments: ["mybootclasspathfragment"],
-				java_boot_libs: ["mybootlib"],
 			}
 
 			bootclasspath_fragment {