Merge "Remove obsolete llndk_library"
diff --git a/android/apex.go b/android/apex.go
index 25a07b8..60da45b 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -847,7 +847,6 @@
 	"libprocpartition":                                         30,
 	"libprotobuf-java-lite":                                    30,
 	"libprotoutil":                                             30,
-	"libqemu_pipe":                                             30,
 	"libsync":                                                  30,
 	"libtextclassifier_hash_headers":                           30,
 	"libtextclassifier_hash_static":                            30,
diff --git a/android/bazel.go b/android/bazel.go
index ba5ae31..f50b31d 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -167,61 +167,69 @@
 		"bionic":                Bp2BuildDefaultTrueRecursively,
 		"external/gwp_asan":     Bp2BuildDefaultTrueRecursively,
 		"system/core/libcutils": Bp2BuildDefaultTrueRecursively,
+		"system/core/property_service/libpropertyinfoparser": Bp2BuildDefaultTrueRecursively,
+		"system/libbase":        Bp2BuildDefaultTrueRecursively,
 		"system/logging/liblog": Bp2BuildDefaultTrueRecursively,
 	}
 
 	// Per-module denylist to always opt modules out of both bp2build and mixed builds.
 	bp2buildModuleDoNotConvertList = []string{
-		"libBionicBenchmarksUtils",      // ruperts@, cc_library_static, 'map' file not found
-		"libbionic_spawn_benchmark",     // ruperts@, cc_library_static, depends on //system/libbase
-		"libc_jemalloc_wrapper",         // ruperts@, cc_library_static, depends on //external/jemalloc_new
-		"libc_bootstrap",                // ruperts@, cc_library_static, 'private/bionic_auxv.h' file not found
-		"libc_init_static",              // ruperts@, cc_library_static, 'private/bionic_elf_tls.h' file not found
-		"libc_init_dynamic",             // ruperts@, cc_library_static, 'private/bionic_defs.h' file not found
-		"libc_tzcode",                   // ruperts@, cc_library_static, error: expected expression
-		"libc_netbsd",                   // ruperts@, cc_library_static, 'engine.c' file not found
-		"libc_fortify",                  // ruperts@, cc_library_static, 'private/bionic_fortify.h' file not found
-		"libc_bionic",                   // ruperts@, cc_library_static, 'private/bionic_asm.h' file not found
-		"libc_bionic_ndk",               // ruperts@, cc_library_static, depends on //bionic/libc/system_properties
-		"libc_bionic_systrace",          // ruperts@, cc_library_static, 'private/bionic_systrace.h' file not found
-		"libc_pthread",                  // ruperts@, cc_library_static, 'private/bionic_defs.h' file not found
-		"libc_syscalls",                 // eakammer@, cc_library_static,  'private/bionic_asm.h' file not found
-		"libc_ndk",                      // ruperts@, cc_library_static, depends on //bionic/libm:libm
-		"libc_nopthread",                // ruperts@, cc_library_static, depends on //external/arm-optimized-routines
-		"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_unwind_static",            // ruperts@, cc_library_static, 'private/bionic_elf_tls.h' file not found
-		"libc_nomalloc",                 // ruperts@, cc_library_static, depends on //bionic/libc:libc_common
-		"libasync_safe",                 // ruperts@, cc_library_static, 'private/CachedProperty.h' file not found
-		"libc_malloc_debug_backtrace",   // ruperts@, cc_library_static, depends on //system/libbase
-		"libsystemproperties",           // ruperts@, cc_library_static, depends on //system/core/property_service/libpropertyinfoparser
-		"libdl_static",                  // ruperts@, cc_library_static, 'private/CFIShadow.h' file not found
-		"liblinker_main",                // ruperts@, cc_library_static, depends on //system/libbase
-		"liblinker_malloc",              // ruperts@, cc_library_static, depends on //system/logging/liblog:liblog
-		"liblinker_debuggerd_stub",      // ruperts@, cc_library_static, depends on //system/libbase
-		"libbionic_tests_headers_posix", // ruperts@, cc_library_static, 'complex.h' file not found
-		"libc_dns",                      // ruperts@, cc_library_static, 'private/android_filesystem_config.h' file not found
-		"libc_static_dispatch",          // eakammer@, cc_library_static, 'private/bionic_asm.h' file not found
-		"libc_dynamic_dispatch",         // eakammer@, cc_library_static, 'private/bionic_ifuncs.h' file not found
-		"note_memtag_heap_async",        // jingwen@, cc_library_static, 'private/bionic_asm.h' file not found (arm64)
-		"note_memtag_heap_sync",         // jingwen@, cc_library_static, 'private/bionic_asm.h' file not found (arm64)
+		// Things that transitively depend on //external/arm-optimized-routines. That one fails
+		// with a linker error: "ld.lld: no input files"
+		"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
 
-		// List of all full_cc_libraries in //bionic, with their immediate failures
-		"libc",              // jingwen@, cc_library, depends on //external/gwp_asan
-		"libc_malloc_debug", // jingwen@, cc_library, fatal error: 'assert.h' file not found
-		"libc_malloc_hooks", // jingwen@, cc_library, fatal error: 'errno.h' file not found
-		"libdl",             // jingwen@, cc_library, ld.lld: error: no input files
-		"libm",              // lberki@, cc_library, compiler error: "Unexpected token in argument list"
-		"libseccomp_policy", // lberki@, cc_library, 'linux/filter.h' not found, caused by missing -isystem bionic/libc/kernel/uapi, dunno where it comes from in Soong
-		"libstdc++",         // jingwen@, cc_library, depends on //external/gwp_asan
+		// Things that transitively depend on //system/libbase. libbase doesn't work because:
+		// fmtlib: fatal error: 'cassert' file not found
+		"libbase",                     // eakammer@, cc_library, no such target '//build/bazel/platforms/os:darwin': target 'darwin' not declared
+		"libbase_ndk",                 // eakammer@, cc_library, no such target '//build/bazel/platforms/os:darwin': target 'darwin' not declared
+		"libbionic_spawn_benchmark",   // ruperts@, cc_library_static, depends on libbase, libgoogle-benchmark
+		"libc_malloc_debug",           // ruperts@, cc_library_static, depends on libbase
+		"libc_malloc_debug_backtrace", // ruperts@, cc_library_static, depends on libbase
+		"libcutils",                   // eakammer@, cc_library, depends on libbase, liblog
+		"libcutils_sockets",           // eakammer@, cc_library, depends on libbase, liblog
+		"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
+		"libc_jemalloc_wrapper", // ruperts@, cc_library_static, depends on //external/jemalloc_new
+
+		// Compilation error, seems to be fixable by changing the toolchain definition
+		"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
+		"libc_malloc_hooks", // jingwen@, cc_library, undefined symbol: __malloc_hook, etc.
+		"libdl",             // jingwen@, cc_library, clang failed
+		"libstdc++",         // jingwen@, cc_library, undefined symbol: free
+
+		// Includes not found
+		"libbionic_tests_headers_posix", // ruperts@, cc_library_static, 'dirent.h' not found
+		"liblog",                        // eakammer@, cc_library, 'sys/cdefs.h' file not found, missing -isystem bionic/libc/include through the libc/libm/libdl default dependencies if system_shared_libs unset
+		"libseccomp_policy",             // jingwen@, cc_library, 'linux/filter.h' not found, missing -isystem bionic/libc/kernel/uapi/asm-arm, probably due to us not handling arch { ... { export_system_include_dirs } } correctly
+		"note_memtag_heap_async",        // lberki@, cc_library_static, error: feature.h not found, missing -isystem bionic/libc/include through the libc/libm/libdl default dependencies if system_shared_libs unset
+		"note_memtag_heap_sync",         // lberki@, cc_library_static, error: feature.h not found, missing -isystem bionic/libc/include through the libc/libm/libdl default dependencies if system_shared_libs unset
+
+		// Other
+		"libBionicBenchmarksUtils", // ruperts@, cc_library_static, 'map' file not found
+		"libc_ndk",                 // ruperts@, cc_library_static, depends on libc_bionic_ndk, libc_jemalloc_wrapper, libc_tzcode, libstdc++
+
+		"libc", // jingwen@, cc_library, depends on //external/gwp_asan
 	}
 
 	// 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_openbsd", // ruperts@, cc_library_static, OK for bp2build but error: duplicate symbol: strcpy for mixed builds
+		"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
+		"libsystemproperties",   // cparsons@, cc_library_static, wrong include paths
+		"libpropertyinfoparser", // cparsons@, cc_library_static, wrong include paths
 	}
 
 	// 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/module.go b/android/module.go
index 9f923e2..fdb5290 100644
--- a/android/module.go
+++ b/android/module.go
@@ -213,7 +213,7 @@
 
 	// GetDirectDep returns the Module and DependencyTag for the  direct dependency with the specified
 	// name, or nil if none exists.  If there are multiple dependencies on the same module it returns
-	// the first DependencyTag.  It skips any dependencies that are not an android.Module.
+	// the first DependencyTag.
 	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
 
 	// VisitDirectDepsBlueprint calls visit for each direct dependency.  If there are multiple
@@ -2244,11 +2244,12 @@
 	return aModule
 }
 
-func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) {
-	type dep struct {
-		mod blueprint.Module
-		tag blueprint.DependencyTag
-	}
+type dep struct {
+	mod blueprint.Module
+	tag blueprint.DependencyTag
+}
+
+func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []dep {
 	var deps []dep
 	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
 		if aModule, _ := module.(Module); aModule != nil {
@@ -2265,6 +2266,11 @@
 			}
 		}
 	})
+	return deps
+}
+
+func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) {
+	deps := b.getDirectDepsInternal(name, tag)
 	if len(deps) == 1 {
 		return deps[0].mod, deps[0].tag
 	} else if len(deps) >= 2 {
@@ -2275,6 +2281,25 @@
 	}
 }
 
+func (b *baseModuleContext) getDirectDepFirstTag(name string) (blueprint.Module, blueprint.DependencyTag) {
+	foundDeps := b.getDirectDepsInternal(name, nil)
+	deps := map[blueprint.Module]bool{}
+	for _, dep := range foundDeps {
+		deps[dep.mod] = true
+	}
+	if len(deps) == 1 {
+		return foundDeps[0].mod, foundDeps[0].tag
+	} else if len(deps) >= 2 {
+		// this could happen if two dependencies have the same name in different namespaces
+		// TODO(b/186554727): this should not occur if namespaces are handled within
+		// getDirectDepsInternal.
+		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
+			name, b.ModuleName()))
+	} else {
+		return nil, nil
+	}
+}
+
 func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
 	var deps []Module
 	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
@@ -2292,8 +2317,11 @@
 	return module
 }
 
+// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified
+// name, or nil if none exists. If there are multiple dependencies on the same module it returns the
+// first DependencyTag.
 func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) {
-	return b.getDirectDepInternal(name, nil)
+	return b.getDirectDepFirstTag(name)
 }
 
 func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) {
diff --git a/android/neverallow.go b/android/neverallow.go
index a385bbc..41b399a 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,22 @@
 		"external/vixl",
 		"external/wycheproof",
 	}
+	noUseIncludeDir := []string{
+		"frameworks/av/apex",
+		"frameworks/av/tools",
+		"frameworks/native/cmds",
+		"system/apex",
+		"system/bpf",
+		"system/gatekeeper",
+		"system/hwservicemanager",
+		"system/libbase",
+		"system/libfmq",
+		"system/libvintf",
+	}
 
-	// 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 +104,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/android/override_module.go b/android/override_module.go
index 97acc5c..0a7e294 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -244,11 +244,11 @@
 		// See if there's a prebuilt module that overrides this override module with prefer flag,
 		// in which case we call HideFromMake on the corresponding variant later.
 		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(dep Module) {
-			prebuilt, ok := dep.(PrebuiltInterface)
-			if !ok {
+			prebuilt := GetEmbeddedPrebuilt(dep)
+			if prebuilt == nil {
 				panic("PrebuiltDepTag leads to a non-prebuilt module " + dep.Name())
 			}
-			if prebuilt.Prebuilt().UsePrebuilt() {
+			if prebuilt.UsePrebuilt() {
 				module.setOverriddenByPrebuilt(true)
 				return
 			}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 40bcdfd..43b7cbe 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -242,14 +242,30 @@
 		// A source module that has been replaced by a prebuilt counterpart.
 		return false
 	}
-	if prebuilt, ok := module.(PrebuiltInterface); ok {
-		if p := prebuilt.Prebuilt(); p != nil {
-			return p.UsePrebuilt()
-		}
+	if p := GetEmbeddedPrebuilt(module); p != nil {
+		return p.UsePrebuilt()
 	}
 	return true
 }
 
+// IsModulePrebuilt returns true if the module implements PrebuiltInterface and
+// has been initialized as a prebuilt and so returns a non-nil value from the
+// PrebuiltInterface.Prebuilt() method.
+func IsModulePrebuilt(module Module) bool {
+	return GetEmbeddedPrebuilt(module) != nil
+}
+
+// GetEmbeddedPrebuilt returns a pointer to the embedded Prebuilt structure or
+// nil if the module does not implement PrebuiltInterface or has not been
+// initialized as a prebuilt module.
+func GetEmbeddedPrebuilt(module Module) *Prebuilt {
+	if p, ok := module.(PrebuiltInterface); ok {
+		return p.Prebuilt()
+	}
+
+	return nil
+}
+
 func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
 	ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).Parallel()
 }
@@ -263,11 +279,12 @@
 // PrebuiltRenameMutator ensures that there always is a module with an
 // undecorated name.
 func PrebuiltRenameMutator(ctx BottomUpMutatorContext) {
-	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
+	m := ctx.Module()
+	if p := GetEmbeddedPrebuilt(m); p != nil {
 		name := m.base().BaseModuleName()
 		if !ctx.OtherModuleExists(name) {
 			ctx.Rename(name)
-			m.Prebuilt().properties.PrebuiltRenamedToSource = true
+			p.properties.PrebuiltRenamedToSource = true
 		}
 	}
 }
@@ -275,14 +292,14 @@
 // PrebuiltSourceDepsMutator adds dependencies to the prebuilt module from the
 // corresponding source module, if one exists for the same variant.
 func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) {
-	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Enabled() && m.Prebuilt() != nil {
-		p := m.Prebuilt()
-		if !p.properties.PrebuiltRenamedToSource {
-			name := m.base().BaseModuleName()
-			if ctx.OtherModuleReverseDependencyVariantExists(name) {
-				ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
-				p.properties.SourceExists = true
-			}
+	m := ctx.Module()
+	// If this module is a prebuilt, is enabled and has not been renamed to source then add a
+	// dependency onto the source if it is present.
+	if p := GetEmbeddedPrebuilt(m); p != nil && m.Enabled() && !p.properties.PrebuiltRenamedToSource {
+		name := m.base().BaseModuleName()
+		if ctx.OtherModuleReverseDependencyVariantExists(name) {
+			ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
+			p.properties.SourceExists = true
 		}
 	}
 }
@@ -290,8 +307,8 @@
 // PrebuiltSelectModuleMutator marks prebuilts that are used, either overriding source modules or
 // because the source module doesn't exist.  It also disables installing overridden source modules.
 func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
-	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
-		p := m.Prebuilt()
+	m := ctx.Module()
+	if p := GetEmbeddedPrebuilt(m); p != nil {
 		if p.srcsSupplier == nil {
 			panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
 		}
@@ -299,9 +316,9 @@
 			p.properties.UsePrebuilt = p.usePrebuilt(ctx, nil, m)
 		}
 	} else if s, ok := ctx.Module().(Module); ok {
-		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(m Module) {
-			p := m.(PrebuiltInterface).Prebuilt()
-			if p.usePrebuilt(ctx, s, m) {
+		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(prebuiltModule Module) {
+			p := GetEmbeddedPrebuilt(prebuiltModule)
+			if p.usePrebuilt(ctx, s, prebuiltModule) {
 				p.properties.UsePrebuilt = true
 				s.ReplacedByPrebuilt()
 			}
@@ -313,8 +330,8 @@
 // prebuilt when both modules exist and the prebuilt should be used.  When the prebuilt should not
 // be used, disable installing it.
 func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) {
-	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
-		p := m.Prebuilt()
+	m := ctx.Module()
+	if p := GetEmbeddedPrebuilt(m); p != nil {
 		name := m.base().BaseModuleName()
 		if p.properties.UsePrebuilt {
 			if p.properties.SourceExists {
diff --git a/android/sdk.go b/android/sdk.go
index b4ef8aa..6fc1910 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -171,6 +171,16 @@
 	m.AddProperties(&base.properties)
 }
 
+// IsModuleInVersionedSdk returns true if the module is an versioned sdk.
+func IsModuleInVersionedSdk(module Module) bool {
+	if s, ok := module.(SdkAware); ok {
+		if !s.ContainingSdk().Unversioned() {
+			return true
+		}
+	}
+	return false
+}
+
 // Provide support for generating the build rules which will build the snapshot.
 type SnapshotBuilder interface {
 	// Copy src to the dest (which is a snapshot relative path) and add the dest
@@ -290,7 +300,7 @@
 
 	// SdkMemberType returns the SdkMemberType that will be used to automatically add the child module
 	// to the sdk.
-	SdkMemberType() SdkMemberType
+	SdkMemberType(child Module) SdkMemberType
 
 	// ExportMember determines whether a module added to the sdk through this tag will be exported
 	// from the sdk or not.
@@ -317,7 +327,7 @@
 	export     bool
 }
 
-func (t *sdkMemberDependencyTag) SdkMemberType() SdkMemberType {
+func (t *sdkMemberDependencyTag) SdkMemberType(_ Module) SdkMemberType {
 	return t.memberType
 }
 
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..e8235d5 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,226 @@
     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",
+        ],
+    }),
+)`},
+		},
+		{
+			description:                        "cc_library_static multiple dep same name panic",
+			moduleTypeUnderTest:                "cc_library_static",
+			moduleTypeUnderTestFactory:         cc.LibraryStaticFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+			filesystem:                         map[string]string{},
+			bp: soongCcLibraryStaticPreamble + `
+cc_library_static { name: "static_dep" }
+cc_library_static {
+    name: "foo_static",
+    static_libs: ["static_dep"],
+    whole_static_libs: ["static_dep"],
+}`,
+			expectedBazelTargets: []string{`cc_library_static(
+    name = "foo_static",
+    copts = ["-I."],
+    deps = [":static_dep"],
+    linkstatic = True,
+)`, `cc_library_static(
+    name = "static_dep",
+    copts = ["-I."],
+    linkstatic = True,
+)`},
+		},
 	}
 
 	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/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/fuzz.go b/cc/fuzz.go
index 5219ebc..c780b6f 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -221,8 +221,7 @@
 	// If the same library is present both as source and a prebuilt we must pick
 	// only one to avoid a conflict. Always prefer the source since the prebuilt
 	// probably won't be built with sanitizers enabled.
-	if prebuilt, ok := dependency.(android.PrebuiltInterface); ok &&
-		prebuilt.Prebuilt() != nil && prebuilt.Prebuilt().SourceExists() {
+	if prebuilt := android.GetEmbeddedPrebuilt(dependency); prebuilt != nil && prebuilt.SourceExists() {
 		return false
 	}
 
diff --git a/cc/library.go b/cc/library.go
index b2f33a0..3a70765 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -256,11 +256,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,
@@ -400,11 +399,18 @@
 
 func (f *flagExporter) setProvider(ctx android.ModuleContext) {
 	ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{
-		IncludeDirs:       android.FirstUniquePaths(f.dirs),
+		// Comes from Export_include_dirs property, and those of exported transitive deps
+		IncludeDirs: android.FirstUniquePaths(f.dirs),
+		// Comes from Export_system_include_dirs property, and those of exported transitive deps
 		SystemIncludeDirs: android.FirstUniquePaths(f.systemDirs),
-		Flags:             f.flags,
-		Deps:              f.deps,
-		GeneratedHeaders:  f.headers,
+		// Used in very few places as a one-off way of adding extra defines.
+		Flags: f.flags,
+		// Used sparingly, for extra files that need to be explicitly exported to dependers,
+		// or for phony files to minimize ninja.
+		Deps: f.deps,
+		// For exported generated headers, such as exported aidl headers, proto headers, or
+		// sysprop headers.
+		GeneratedHeaders: f.headers,
 	})
 }
 
@@ -522,6 +528,8 @@
 			Direct(outputFilePath).
 			Build(),
 	})
+
+	ctx.SetProvider(FlagExporterInfoProvider, flagExporterInfoFromCcInfo(ctx, ccInfo))
 	if i, ok := handler.module.linker.(snapshotLibraryInterface); ok {
 		// Dependencies on this library will expect collectedSnapshotHeaders to
 		// be set, otherwise validation will fail. For now, set this to an empty
@@ -2170,7 +2178,7 @@
 
 	compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
 	linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
-	exportedIncludes, exportedIncludesHeaders := bp2BuildParseExportedIncludes(ctx, module)
+	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
 
 	attrs := &bazelCcLibraryStaticAttributes{
 		Copts:      compilerAttrs.copts,
@@ -2178,7 +2186,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 6f6410a..17526b4 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -277,7 +277,7 @@
 	systemIncludes := android.PathsForBazelOut(ctx, ccInfo.SystemIncludes)
 
 	return FlagExporterInfo{
-		IncludeDirs:       includes,
-		SystemIncludeDirs: systemIncludes,
+		IncludeDirs:       android.FirstUniquePaths(includes),
+		SystemIncludeDirs: android.FirstUniquePaths(systemIncludes),
 	}
 }
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index a94e7af..7397919 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,
@@ -408,14 +404,14 @@
 		if parent == ctx.Module() && ctx.OtherModuleDependencyTag(child) == Dex2oatDepTag {
 			// Found the source module, or prebuilt module that has replaced the source.
 			dex2oatModule = child
-			if p, ok := child.(android.PrebuiltInterface); ok && p.Prebuilt() != nil {
+			if android.IsModulePrebuilt(child) {
 				return false // If it's the prebuilt we're done.
 			} else {
 				return true // Recurse to check if the source has a prebuilt dependency.
 			}
 		}
 		if parent == dex2oatModule && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag {
-			if p, ok := child.(android.PrebuiltInterface); ok && p.Prebuilt() != nil && p.Prebuilt().UsePrebuilt() {
+			if p := android.GetEmbeddedPrebuilt(child); p != nil && p.UsePrebuilt() {
 				dex2oatModule = child // Found a prebuilt that should be used.
 			}
 		}
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 2e33c06..5c1c5f0 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -63,7 +63,7 @@
 
 // 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 {
+func (b bootclasspathFragmentContentDependencyTag) SdkMemberType(_ android.Module) android.SdkMemberType {
 	return javaBootLibsSdkMemberType
 }
 
@@ -150,7 +150,7 @@
 	imageName := proptools.String(m.properties.Image_name)
 	if imageName == "art" {
 		// TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property.
-		if m.MemberName() != "" {
+		if android.IsModuleInVersionedSdk(m) {
 			// 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
@@ -205,7 +205,7 @@
 	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() != "" {
+		if android.IsModuleInVersionedSdk(b) {
 			// 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
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..8a6f3d1 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -423,27 +423,40 @@
 	writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
 
 	global := dexpreopt.GetGlobalConfig(ctx)
-
-	// Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
-	// and invalidate first-stage artifacts which are crucial to SANITIZE_LITE builds.
-	// Note: this is technically incorrect. Compiled code contains stack checks which may depend
-	//       on ASAN settings.
-	if len(ctx.Config().SanitizeDevice()) == 1 &&
-		ctx.Config().SanitizeDevice()[0] == "address" &&
-		global.SanitizeLite {
+	if !shouldBuildBootImages(ctx.Config(), global) {
 		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 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)
 
 	dumpOatRules(ctx, d.defaultBootImage)
 }
 
+// shouldBuildBootImages determines whether boot images should be built.
+func shouldBuildBootImages(config android.Config, global *dexpreopt.GlobalConfig) bool {
+	// Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
+	// and invalidate first-stage artifacts which are crucial to SANITIZE_LITE builds.
+	// Note: this is technically incorrect. Compiled code contains stack checks which may depend
+	//       on ASAN settings.
+	if len(config.SanitizeDevice()) == 1 && config.SanitizeDevice()[0] == "address" && global.SanitizeLite {
+		return false
+	}
+	return true
+}
+
 // Inspect this module to see if it contains a bootclasspath dex jar.
 // Note that the same jar may occur in multiple modules.
 // This logic is tested in the apex package to avoid import cycle apex <-> java.
@@ -549,7 +562,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 +581,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 +653,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 +672,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,158 +807,142 @@
 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 {
-	globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
+// bootFrameworkProfileRule generates the rule to create the boot framework profile and
+// returns a path to the generated file.
+func bootFrameworkProfileRule(ctx android.ModuleContext, image *bootImageConfig) android.WritablePath {
+	globalSoong := dexpreopt.GetGlobalSoongConfig(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)
-		}
+	defaultProfile := "frameworks/base/config/boot-profile.txt"
+	bootFrameworkProfile := android.PathForSource(ctx, 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.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)
+	var modules []android.Module
+	updatableModules := global.UpdatableBootJars.CopyOfJars()
+	ctx.VisitAllModules(func(module android.Module) {
+		if !isActiveModule(module) {
+			return
+		}
+		name := ctx.ModuleName(module)
+		if i := android.IndexList(name, updatableModules); i != -1 {
+			modules = append(modules, module)
+			// 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)
-
-		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"))
-
-		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()...)
-
-		return updatableBcpPackages
-	}).(android.WritablePath)
+	return generateUpdatableBcpPackagesRule(ctx, image, modules)
 }
 
-var updatableBcpPackagesRuleKey = android.NewOnceKey("updatableBcpPackagesRule")
+// generateUpdatableBcpPackagesRule generates the rule to create the updatable-bcp-packages.txt file
+// and returns a path to the generated file.
+func generateUpdatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig, updatableModules []android.Module) android.WritablePath {
+	// Collect `permitted_packages` for updatable boot jars.
+	var updatablePackages []string
+	for _, module := range updatableModules {
+		if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok {
+			pp := j.PermittedPackagesForUpdatableBootJars()
+			if len(pp) > 0 {
+				updatablePackages = append(updatablePackages, pp...)
+			} else {
+				ctx.Errorf("Missing permitted_packages for %s", ctx.ModuleName(module))
+			}
+		}
+	}
+
+	// Sort updatable packages to ensure deterministic ordering.
+	sort.Strings(updatablePackages)
+
+	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"))
+
+	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
+}
 
 func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) {
 	var allPhonies android.Paths
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 8cc6f8f..793d63a 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -33,6 +33,21 @@
 	return false
 }
 
+func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType {
+	// If the module is a java_sdk_library then treat it as if it was specific in the java_sdk_libs
+	// property, otherwise treat if it was specified in the java_header_libs property.
+	if javaSdkLibrarySdkMemberType.IsInstance(child) {
+		return javaSdkLibrarySdkMemberType
+	}
+
+	return javaHeaderLibsSdkMemberType
+}
+
+func (b hiddenAPIStubsDependencyTag) ExportMember() bool {
+	// Export the module added via this dependency tag from the sdk.
+	return true
+}
+
 // Avoid having to make stubs content explicitly visible to dependent modules.
 //
 // This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules
@@ -44,6 +59,7 @@
 var _ android.ExcludeFromVisibilityEnforcementTag = hiddenAPIStubsDependencyTag{}
 var _ android.ReplaceSourceWithPrebuilt = hiddenAPIStubsDependencyTag{}
 var _ android.ExcludeFromApexContentsTag = hiddenAPIStubsDependencyTag{}
+var _ android.SdkMemberTypeDependencyTag = hiddenAPIStubsDependencyTag{}
 
 // hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden
 // API processing.
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 05b8e2f..6503eca 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -168,9 +168,7 @@
 		return
 	}
 
-	// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
-	// GenerateSingletonBuildActions method as it cannot create it for itself.
-	dexpreopt.GetGlobalSoongConfig(ctx)
+	b.generateBootImageBuildActions(ctx)
 }
 
 func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
@@ -297,3 +295,23 @@
 
 	rule.Build("platform-bootclasspath-monolithic-hiddenapi-metadata", "monolithic hidden API metadata")
 }
+
+// generateBootImageBuildActions generates ninja rules related to the boot image creation.
+func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext) {
+	// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
+	// GenerateSingletonBuildActions method as it cannot create it for itself.
+	dexpreopt.GetGlobalSoongConfig(ctx)
+
+	imageConfig := b.getImageConfig(ctx)
+	if imageConfig == nil {
+		return
+	}
+
+	global := dexpreopt.GetGlobalConfig(ctx)
+	if !shouldBuildBootImages(ctx.Config(), global) {
+		return
+	}
+
+	// Generate the framework profile rule
+	bootFrameworkProfileRule(ctx, imageConfig)
+}
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index edfa146..712c2a2 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -226,10 +226,8 @@
 func isModulePreferredByCompatConfig(module android.Module) bool {
 	// A versioned prebuilt_platform_compat_config, i.e. foo-platform-compat-config@current should be
 	// ignored.
-	if s, ok := module.(android.SdkAware); ok {
-		if !s.ContainingSdk().Unversioned() {
-			return false
-		}
+	if android.IsModuleInVersionedSdk(module) {
+		return false
 	}
 
 	return android.IsModulePreferred(module)
diff --git a/java/sdk.go b/java/sdk.go
index 1c097d5..cbd873d 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -356,6 +356,7 @@
 			"frameworks-base-api-current.txt",
 			"frameworks-base-api-system-current.txt",
 			"frameworks-base-api-module-lib-current.txt",
+			"services-system-server-current.txt",
 		}
 		count := 0
 		ctx.VisitAllModules(func(module android.Module) {
@@ -369,8 +370,7 @@
 			ctx.Errorf("Could not find all the expected API modules %v, found %d\n", apiTxtFileModules, count)
 			return
 		}
-		cmd.Input(android.PathForSource(ctx, "frameworks/base/services/api/current.txt")).
-			Text("| md5sum | cut -d' ' -f1 >").
+		cmd.Text("| md5sum | cut -d' ' -f1 >").
 			Output(out)
 	} else {
 		// Unbundled build
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 05ce97a..fcc105d 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -339,12 +339,7 @@
 	})
 
 	// Register sdk member types.
-	android.RegisterSdkMemberType(&sdkLibrarySdkMemberType{
-		android.SdkMemberTypeBase{
-			PropertyName: "java_sdk_libs",
-			SupportsSdk:  true,
-		},
-	})
+	android.RegisterSdkMemberType(javaSdkLibrarySdkMemberType)
 }
 
 func RegisterSdkLibraryBuildComponents(ctx android.RegistrationContext) {
@@ -2377,6 +2372,13 @@
 	return &sdkLibrarySdkMemberProperties{}
 }
 
+var javaSdkLibrarySdkMemberType = &sdkLibrarySdkMemberType{
+	android.SdkMemberTypeBase{
+		PropertyName: "java_sdk_libs",
+		SupportsSdk:  true,
+	},
+}
+
 type sdkLibrarySdkMemberProperties struct {
 	android.SdkMemberPropertiesBase
 
diff --git a/rust/builder.go b/rust/builder.go
index 1fcce38..6db508d 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -47,8 +47,7 @@
 	_       = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc")
 	rustdoc = pctx.AndroidStaticRule("rustdoc",
 		blueprint.RuleParams{
-			Command: "rm -rf $outDir && " +
-				"$envVars $rustdocCmd $rustdocFlags $in -o $outDir && " +
+			Command: "$envVars $rustdocCmd $rustdocFlags $in -o $outDir && " +
 				"touch $out",
 			CommandDeps: []string{"$rustdocCmd"},
 		},
@@ -307,6 +306,10 @@
 	rustdocFlags := append([]string{}, flags.RustdocFlags...)
 	rustdocFlags = append(rustdocFlags, "--sysroot=/dev/null")
 
+	// Build an index for all our crates. -Z unstable options is required to use
+	// this flag.
+	rustdocFlags = append(rustdocFlags, "-Z", "unstable-options", "--enable-index-page")
+
 	targetTriple := ctx.toolchain().RustTriple()
 
 	// Collect rustc flags
@@ -315,13 +318,17 @@
 	}
 
 	crateName := ctx.RustModule().CrateName()
-	if crateName != "" {
-		rustdocFlags = append(rustdocFlags, "--crate-name "+crateName)
-	}
+	rustdocFlags = append(rustdocFlags, "--crate-name "+crateName)
 
 	rustdocFlags = append(rustdocFlags, makeLibFlags(deps)...)
 	docTimestampFile := android.PathForModuleOut(ctx, "rustdoc.timestamp")
-	docDir := android.PathForOutput(ctx, "rustdoc", ctx.ModuleName())
+
+	// Yes, the same out directory is used simultaneously by all rustdoc builds.
+	// This is what cargo does. The docs for individual crates get generated to
+	// a subdirectory named for the crate, and rustdoc synchronizes writes to
+	// shared pieces like the index and search data itself.
+	// https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/render/write_shared.rs#L144-L146
+	docDir := android.PathForOutput(ctx, "rustdoc")
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rustdoc,
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index dcdf852..5658f16 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -46,6 +46,8 @@
 				],
 			}
 		`),
+		// Needed for platform_bootclasspath
+		android.FixtureAddFile("frameworks/base/config/boot-profile.txt", nil),
 
 		java.FixtureConfigureBootJars("com.android.art:mybootlib"),
 		android.FixtureWithRootAndroidBp(`
diff --git a/sdk/update.go b/sdk/update.go
index 3668b46..72b02e8 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -120,7 +120,7 @@
 	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
 		tag := ctx.OtherModuleDependencyTag(child)
 		if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
-			memberType := memberTag.SdkMemberType()
+			memberType := memberTag.SdkMemberType(child)
 
 			// Make sure that the resolved module is allowed in the member list property.
 			if !memberType.IsInstance(child) {